I have the last two CGPoints from a Array which contains points of line drawn by the user . i need to extend the line upto a fixed distance at the same angle. so i first calculate the angle between the last two points with the help of following code
-(CGFloat)angleBetweenFirstPoint:(CGPoint)firstPoint ToSecondPoint:(CGPoint)secondPoint
{
CGPoint diff = ccpSub(secondPoint, firstPoint);
NSLog(#"difference point %f , %f",diff.x,diff.y);
CGFloat res = atan2(diff.y, diff.x);
/*if ( res < 0 )
{
res = (0.5 * M_PI) + res;
}
if ( dx<0 && dy>0 ) { // 2nd quadrant
res += 0.5 * M_PI;
} else if ( dx<0 && dy<0 ) { // 3rd quadrant
res += M_PI;
} else if ( dx>0 && dy<0 ) { // 4th quadrant
res += M_PI + (0.5 * M_PI);
}*/
//res=res*180/M_PI;
res = CC_RADIANS_TO_DEGREES(res);
return res;
}
After calculating the angle i find the extend point with the help of following maths
-(void)extendLine
{
lineAngle = [self angleBetweenFirstPoint:pointD ToSecondPoint:endPt];
extendEndPt.x = endPt.x - cos(lineAngle) * 200;
extendEndPt.y = endPt.y - sin(lineAngle) * 200;
// draw line unto extended point
}
But the point i am getting is not right to draw the extended line at the same angle as the original line.
I think it is because i am not getting the right angle between those last points.. what am i possibly doing wrong?? Do i need to consider the whole quadrant system while considering the angle and how? and m working in landscape mode. does that make any difference??
Ye gods, you are doing this in a way that is WILDLY INCREDIBLY over-complicated.
Skip all of the crapola with angles. You don't need it. Period. Do it all with vectors, and very simple ones. First of all, I'll assume that you are given two points, P1 and P2. You wish to find a new point P3, that is a known distance (d) from P2, along the line that connects the two points.
All you need do is first, compute a vector that points along the line in question.
V = P2 - P1;
I've written it as if I am writing in MATLAB, but all this means is to subtract the x and y coordinates of the two points.
Next, scale the vector V to have unit length.
V = V/sqrt(V(1)^2 + V(2)^2);
Dividing the components of the vector V by the length (or 2-norm if you prefer) of that vector creates a vector with unit norm. That norm is just the square root of the sum of squares of the elements of V, so it is clearly the length of the vector.
Now it is simple to compute P3.
P3 = P2 + d*V;
P3 will lie at a distance of d units from P2, in the direction of the line away from point P1. Nothing sophisticated required. No angles computed. No worry about quadrants.
Learn to use vectors. They are your friends, or at the least, they can be if you let them.
Related
I am doing some computer vision based hand gesture recognising stuff. Here, I want to detect a circle (a circular motion) made by my hand. My initial stages are working fine and I am able to get a blob whose centroid from each frame I am plotting. This is essentially my data set. A collection of 2D co-ordinate points. Now I want to detect a circular type motion and say generate a call to a function which says "Circle Detected". The circle detector will give a YES / NO boolean output.
Here is a sample of the data set I am generating in 40 frames
The x, y values are just plotted to a bitmap image using MATLAB.
My initial hand movement was slow and later I picked up speed to complete the circle within stipulated time (40 frames). There is no hard and fast rule about the number of frames thing but for now I am using a 40 frame sliding window for circle detection (0-39) then (1-40) then (2-41) etc.
I am also calculating the arc-tangent between successive points using:
angle = atan2(prev_y - y, prev_x - x) * 180 / pi;
Now what approach should I take for detecting a circle (This sample image should result in a YES). The angle as I am noticing is not steadily increasing from 0 to 360. It does increase but with jumps here and there.
If you are only interested in full or nearly full circles:
I think that the standard parameter estimation approach: Hough/RANSAC won't work very well in this case.
Since you have frames order and therefore distances between consecutive blob centers, you can create a nearly uniform sub sample of the data (let say, pick 20 points spaced ~evenly), calculate the center and measure the distance of all points from that center.
If it is nearly a circle all points will have similar distance from the center.
If you want to do something slightly more robust, you can:
Compute center (mean) of all points.
Perform gradient descent to update the center: should be fairly easy an you won't have local minima. The error term I would probably use is max(D) - min(D) where D is the vector of distances between the blob centers and estimated circle center (but you can use robust statistics instead of max & min)
Evaluate the circle
I would use a Least Square estimation. Numerically you can use the Nelder-Mead method. You get the circle that best approximate your points and on the basis of the residual error value you decide whether to consider the circle valid or not.
Being points the array of the points, xc, yc the coordinates of the center and r the radius, this could be an example of error to minimize:
class Circle
{
private PointF[] _points;
public Circle(PointF[] points)
{
_points = points;
}
public double MinimizeFunction(double xc, double yc, double r)
{
double d, d2, dx, dy, sum;
sum = 0;
foreach(PointF p in _points)
{
dx = p.X - xc;
dy = p.Y - yc;
d2 = dx * dx + dy * dy;
// sum += d2 - r * r;
d = Math.Sqrt(d2) - r;
sum += d * d;
}
return sum;
}
public double ResidualError(double xc, double yc, double r)
{
return Math.Sqrt(MinimizeFunctional(xc, yc, r)) / (_points.Length - 3);
}
}
There is a slight difference between the commented functional and the uncommented, but for practical reason this difference is meaningless. Instead, from a theoretical point of view the difference is important.
Since you need to supply a initial values set (xc, yc, r), you can calculate the circle given three points, choosing three points far from each other.
If you need more details on "circle given three points" or Nelder-Mead you can google or ask me here.
I'm studied the pARK example project (http://developer.apple.com/library/IOS/#samplecode/pARk/Introduction/Intro.html#//apple_ref/doc/uid/DTS40011083) so I can apply some of its fundamentals in an app i'm working on. I understand nearly everything, except:
The way it has to calculate if a point of interest must appear or not. It gets the attitude, multiply it with the projection matrix (to get the rotation in GL coords?), then multiply that matrix with the coordinates of the point of interest and, at last, look at the last coordinate of that vector to find out if the point of interest must be shown. Which are the mathematic fundamentals of this?
Thanks a lot!!
I assume you are referring to the following method:
- (void)drawRect:(CGRect)rect
{
if (placesOfInterestCoordinates == nil) {
return;
}
mat4f_t projectionCameraTransform;
multiplyMatrixAndMatrix(projectionCameraTransform, projectionTransform, cameraTransform);
int i = 0;
for (PlaceOfInterest *poi in [placesOfInterest objectEnumerator]) {
vec4f_t v;
multiplyMatrixAndVector(v, projectionCameraTransform, placesOfInterestCoordinates[i]);
float x = (v[0] / v[3] + 1.0f) * 0.5f;
float y = (v[1] / v[3] + 1.0f) * 0.5f;
if (v[2] < 0.0f) {
poi.view.center = CGPointMake(x*self.bounds.size.width, self.bounds.size.height-y*self.bounds.size.height);
poi.view.hidden = NO;
} else {
poi.view.hidden = YES;
}
i++;
}
}
This is performing an OpenGL like vertex transformation on the places of interest to check if they are in a viewable frustum. The frustum is created in the following line:
createProjectionMatrix(projectionTransform, 60.0f*DEGREES_TO_RADIANS, self.bounds.size.width*1.0f / self.bounds.size.height, 0.25f, 1000.0f);
This sets up a frustum with a 60 degree field of view, a near clipping plane of 0.25 and a far clipping plane of 1000. Any point of interest that is further away than 1000 units will then not be visible.
So, to step through the code, first the projection matrix that sets up the frustum, and the camera view matrix, which simply rotates the object so it is the right way up relative to the camera, are multiplied together. Then, for each place of interest, its location is multiplied by the viewProjection matrix. This will project the location of the place of interest into the view frustum, applying rotation and perspective.
The next two lines then convert the transformed location of the place into whats known as normalized device coordinates. The 4 component vector needs to be collapsed to 3 dimensional space, this is achieved by projecting it onto the plane w == 1, by dividing the vector by its w component, v[3]. It is then possible to determine if the point lies within the projection frustum by checking if its coordinates lie in the cube with side length 2 with origin [0, 0, 0]. In this case, the x and y coordinates are being biased from the range [-1 1] to [0 1] to match up with the UIKit coordinate system, by adding 1 and dividing by 2.
Next, the v[2] component, z, is checked to see if it is greater than 0. This is actually incorrect as it has not been biased, it should be checked to see if it is greater than -1. This will detect if the place of interest is in the first half of the projection frustum, if it is then the object is deemed visible and displayed.
If you are unfamiliar with vertex projection and coordinate systems, this is a huge topic with a fairly steep learning curve. There is however a lot of material online covering it, here are a couple of links to get you started:
http://www.falloutsoftware.com/tutorials/gl/gl0.htm
http://www.opengl.org/wiki/Vertex_Transformation
Good luck//
I have two items, lets call them Obj1 and Obj2... Both have a current position pos1 and pos2.. Moreover they have current velocity vectors speed1 and speed2 ... How can I make sure that if their distances are getting closer (with checking current and NEXT distance), they will move farther away from eachother ?
I have a signed angle function that gives me the signed angle between 2 vectors.. How can I utilize it to check how much should I rotate the speed1 and speed2 to move those sprites from eachother ?
public float signedAngle(Vector2 v1, Vector2 v2)
{
float perpDot = v1.X * v2.Y - v1.Y * v2.X;
return (float)Math.Atan2(perpDot, Vector2.Dot(v1, v2));
}
I check the NEXT and CURRENT distances like that :
float currentDistance = Vector2.Distance(s1.position, s2.position);
Vector2 obj2_nextpos = s2.position + s2.speed + s2.drag;
Vector2 obj1_nextpos = s1.position + s1.speed + s1.drag;
Vector2 s2us = s2.speed;
s2us.Normalize();
Vector2 s1us = s1.speed;
s1us.Normalize();
float nextDistance = Vector2.Distance(obj1_nextpos , obj2_nextpos );
Then depending whether they are getting bigger or smaller I want to move them away (either by increasing their current speed at the same direction or MAKING THEM FURTHER WHICH I FAIL)...
if (nextDistance < currentDistance )
{
float angle = MathHelper.ToRadians(180)- signedAngle(s1us, s2us);
s1.speed += Vector2.Transform(s1us, Matrix.CreateRotationZ(angle)) * esc;
s2.speed += Vector2.Transform(s2us, Matrix.CreateRotationZ(angle)) * esc;
}
Any ideas ?
if objects A and B are getting closer, one of the object components (X or Y) is opposite.
in this case Bx is opposite to Ax, so only have to add Ax to the velocity vector of object B, and Bx to velocity vector of object A
If I understood correctly, this is the situation and you want to obtain the two green vectors.
The red vector is easy to get: redVect = pos1 - pos2. redVect and greenVect2 will point to the same direction, so the only step you have is to scale it so its length will match speed2's one: finalGreenVect2 = greenvect2.Normalize() * speed2.Length (although I'm not actually sure about this formula). greenVect1 = -redVect so finalGreenVect1 = greenVect1.Normalize() * speed1.Length. Then speed1 = finalGreenVect1 and speed2 = finalGreenVect2. This approach will give you instant turn, if you prefer a smooth turn you want to rotate the speed vector by:
angle = signedAngle(speed) + (signedAngle(greenVect) - signedAngle(speed)) * 0.5f;
The o.5f is the rotation speed, adjust it to any value you need. I'm afraid that you have to create a rotation matrix then Transform() the speed vector with this matrix.
Hope this helps ;)
Given two rectangles with x, y, width, height in pixels and a rotation value in degrees -- how do I calculate the closest distance of their outlines toward each other?
Background: In a game written in Lua I'm randomly generating maps, but want to ensure certain rectangles aren't too close to each other -- this is needed because maps become unsolvable if the rectangles get into certain close-distance position, as a ball needs to pass between them. Speed isn't a huge issue as I don't have many rectangles and the map is just generated once per level. Previous links I found on StackOverflow are this and this
Many thanks in advance!
Not in Lua, a Python code based on M Katz's suggestion:
def rect_distance((x1, y1, x1b, y1b), (x2, y2, x2b, y2b)):
left = x2b < x1
right = x1b < x2
bottom = y2b < y1
top = y1b < y2
if top and left:
return dist((x1, y1b), (x2b, y2))
elif left and bottom:
return dist((x1, y1), (x2b, y2b))
elif bottom and right:
return dist((x1b, y1), (x2, y2b))
elif right and top:
return dist((x1b, y1b), (x2, y2))
elif left:
return x1 - x2b
elif right:
return x2 - x1b
elif bottom:
return y1 - y2b
elif top:
return y2 - y1b
else: # rectangles intersect
return 0.
where
dist is the euclidean distance between points
rect. 1 is formed by points (x1, y1) and (x1b, y1b)
rect. 2 is formed by points (x2, y2) and (x2b, y2b)
Edit: As OK points out, this solution assumes all the rectangles are upright. To make it work for rotated rectangles as the OP asks you'd also have to compute the distance from the corners of each rectangle to the closest side of the other rectangle. But you can avoid doing that computation in most cases if the point is above or below both end points of the line segment, and to the left or right of both line segments (in telephone positions 1, 3, 7, or 9 with respect to the line segment).
Agnius's answer relies on a DistanceBetweenLineSegments() function. Here is a case analysis that does not:
(1) Check if the rects intersect. If so, the distance between them is 0.
(2) If not, think of r2 as the center of a telephone key pad, #5.
(3) r1 may be fully in one of the extreme quadrants (#1, #3, #7, or #9). If so
the distance is the distance from one rect corner to another (e.g., if r1 is
in quadrant #1, the distance is the distance from the lower-right corner of
r1 to the upper-left corner of r2).
(4) Otherwise r1 is to the left, right, above, or below r2 and the distance is
the distance between the relevant sides (e.g., if r1 is above, the distance
is the distance between r1's low y and r2's high y).
Actually there is a fast mathematical solution.
Length(Max((0, 0), Abs(Center - otherCenter) - (Extent + otherExtent)))
Where Center = ((Maximum - Minimum) / 2) + Minimum and Extent = (Maximum - Minimum) / 2.
Basically the code above zero's axis which are overlapping and therefore the distance is always correct.
It's preferable to keep the rectangle in this format as it's preferable in many situations ( a.e. rotations are much easier ).
Pseudo-code:
distance_between_rectangles = some_scary_big_number;
For each edge1 in Rectangle1:
For each edge2 in Rectangle2:
distance = calculate shortest distance between edge1 and edge2
if (distance < distance_between_rectangles)
distance_between_rectangles = distance
There are many algorithms to solve this and Agnius algorithm works fine. However I prefer the below since it seems more intuitive (you can do it on a piece of paper) and they don't rely on finding the smallest distance between lines but rather the distance between a point and a line.
The hard part is implementing the mathematical functions to find the distance between a line and a point, and to find if a point is facing a line. You can solve all this with simple trigonometry though. I have below the methodologies to do this.
For polygons (triangles, rectangles, hexagons, etc.) in arbitrary angles
If polygons overlap, return 0
Draw a line between the centres of the two polygons.
Choose the intersecting edge from each polygon. (Here we reduce the problem)
Find the smallest distance from these two edges. (You could just loop through each 4 points and look for the smallest distance to the edge of the other shape).
These algorithms work as long as any two edges of the shape don't create angles more than 180 degrees. The reason is that if something is above 180 degrees then it means that the some corners are inflated inside, like in a star.
Smallest distance between an edge and a point
If point is not facing the face, then return the smallest of the two distances between the point and the edge cornerns.
Draw a triangle from the three points (edge's points plus the solo point).
We can easily get the distances between the three drawn lines with Pythagorean Theorem.
Get the area of the triangle with Heron's formula.
Calculate the height now with Area = 12⋅base⋅height with base being the edge's length.
Check to see if a point faces an edge
As before you make a triangle from an edge and a point. Now using the Cosine law you can find all the angles with just knowing the edge distances. As long as each angle from the edge to the point is below 90 degrees, the point is facing the edge.
I have an implementation in Python for all this here if you are interested.
This question depends on what kind of distance. Do you want, distance of centers, distance of edges or distance of closest corners?
I assume you mean the last one. If the X and Y values indicate the center of the rectangle then you can find each the corners by applying this trick
//Pseudo code
Vector2 BottomLeftCorner = new Vector2(width / 2, heigth / 2);
BottomLeftCorner = BottomLeftCorner * Matrix.CreateRotation(MathHelper.ToRadians(degrees));
//If LUA has no built in Vector/Matrix calculus search for "rotate Vector" on the web.
//this helps: http://www.kirupa.com/forum/archive/index.php/t-12181.html
BottomLeftCorner += new Vector2(X, Y); //add the origin so that we have to world position.
Do this for all corners of all rectangles, then just loop over all corners and calculate the distance (just abs(v1 - v2)).
I hope this helps you
I just wrote the code for that in n-dimensions. I couldn't find a general solution easily.
// considering a rectangle object that contains two points (min and max)
double distance(const rectangle& a, const rectangle& b) const {
// whatever type you are using for points
point_type closest_point;
for (size_t i = 0; i < b.dimensions(); ++i) {
closest_point[i] = b.min[i] > a.min[i] ? a.max[i] : a.min[i];
}
// use usual euclidian distance here
return distance(a, closest_point);
}
For calculating the distance between a rectangle and a point you can:
double distance(const rectangle& a, const point_type& p) const {
double dist = 0.0;
for (size_t i = 0; i < dimensions(); ++i) {
double di = std::max(std::max(a.min[i] - p[i], p[i] - a.max[i]), 0.0);
dist += di * di;
}
return sqrt(dist);
}
If you want to rotate one of the rectangles, you need to rotate the coordinate system.
If you want to rotate both rectangles, you can rotate the coordinate system for rectangle a. Then we have to change this line:
closest_point[i] = b.min[i] > a.min[i] ? a.max[i] : a.min[i];
because this considers there is only one candidate as the closest vertex in b. You have to change it to check the distance to all vertexes in b. It's always one of the vertexes.
See: https://i.stack.imgur.com/EKJmr.png
My approach to solving the problem:
Combine the two rectangles into one large rectangle
Subtract from the large rectangle the first rectangle and the second
rectangle
What is left after the subtraction is a rectangle between the two
rectangles, the diagonal of this rectangle is the distance between
the two rectangles.
Here is an example in C#
public static double GetRectDistance(this System.Drawing.Rectangle rect1, System.Drawing.Rectangle rect2)
{
if (rect1.IntersectsWith(rect2))
{
return 0;
}
var rectUnion = System.Drawing.Rectangle.Union(rect1, rect2);
rectUnion.Width -= rect1.Width + rect2.Width;
rectUnion.Width = Math.Max(0, rectUnion.Width);
rectUnion.Height -= rect1.Height + rect2.Height;
rectUnion.Height = Math.Max(0, rectUnion.Height);
return rectUnion.Diagonal();
}
public static double Diagonal(this System.Drawing.Rectangle rect)
{
return Math.Sqrt(rect.Height * rect.Height + rect.Width * rect.Width);
}
Please check this for Java, it has the constraint all rectangles are parallel, it returns 0 for all intersecting rectangles:
public static double findClosest(Rectangle rec1, Rectangle rec2) {
double x1, x2, y1, y2;
double w, h;
if (rec1.x > rec2.x) {
x1 = rec2.x; w = rec2.width; x2 = rec1.x;
} else {
x1 = rec1.x; w = rec1.width; x2 = rec2.x;
}
if (rec1.y > rec2.y) {
y1 = rec2.y; h = rec2.height; y2 = rec1.y;
} else {
y1 = rec1.y; h = rec1.height; y2 = rec2.y;
}
double a = Math.max(0, x2 - x1 - w);
double b = Math.max(0, y2 - y1 - h);
return Math.sqrt(a*a+b*b);
}
Another solution, which calculates a number of points on the rectangle and choses the pair with the smallest distance.
Pros: works for all polygons.
Cons: a little bit less accurate and slower.
import numpy as np
import math
POINTS_PER_LINE = 100
# get points on polygon outer lines
# format of polygons: ((x1, y1), (x2, y2), ...)
def get_points_on_polygon(poly, points_per_line=POINTS_PER_LINE):
all_res = []
for i in range(len(poly)):
a = poly[i]
if i == 0:
b = poly[-1]
else:
b = poly[i-1]
res = list(np.linspace(a, b, points_per_line))
all_res += res
return all_res
# compute minimum distance between two polygons
# format of polygons: ((x1, y1), (x2, y2), ...)
def min_poly_distance(poly1, poly2, points_per_line=POINTS_PER_LINE):
poly1_points = get_points_on_polygon(poly1, points_per_line=points_per_line)
poly2_points = get_points_on_polygon(poly2, points_per_line=points_per_line)
distance = min([math.sqrt((a[0] - b[0])**2 + (a[1] - b[1])**2) for a in poly1_points for b in poly2_points])
# slower
# distance = min([np.linalg.norm(a - b) for a in poly1_points for b in poly2_points])
return distance
I have an OpenGL program (written in Delphi) that lets user draw a polygon. I want to automatically revolve (lathe) it around an axis (say, Y asix) and get a 3D shape.
How can I do this?
For simplicity, you could force at least one point to lie on the axis of rotation. You can do this easily by adding/subtracting the same value to all the x values, and the same value to all the y values, of the points in the polygon. It will retain the original shape.
The rest isn't really that hard. Pick an angle that is fairly small, say one or two degrees, and work out the coordinates of the polygon vertices as it spins around the axis. Then just join up the points with triangle fans and triangle strips.
To rotate a point around an axis is just basic Pythagoras. At 0 degrees rotation you have the points at their 2-d coordinates with a value of 0 in the third dimension.
Lets assume the points are in X and Y and we are rotating around Y. The original 'X' coordinate represents the hypotenuse. At 1 degree of rotation, we have:
sin(1) = z/hypotenuse
cos(1) = x/hypotenuse
(assuming degree-based trig functions)
To rotate a point (x, y) by angle T around the Y axis to produce a 3d point (x', y', z'):
y' = y
x' = x * cos(T)
z' = x * sin(T)
So for each point on the edge of your polygon you produce a circle of 360 points centered on the axis of rotation.
Now make a 3d shape like so:
create a GL 'triangle fan' by using your center point and the first array of rotated points
for each successive array, create a triangle strip using the points in the array and the points in the previous array
finish by creating another triangle fan centered on the center point and using the points in the last array
One thing to note is that usually, the kinds of trig functions I've used measure angles in radians, and OpenGL uses degrees. To convert degrees to radians, the formula is:
degrees = radians / pi * 180
Essentially the strategy is to sweep the profile given by the user around the given axis and generate a series of triangle strips connecting adjacent slices.
Assume that the user has drawn the polygon in the XZ plane. Further, assume that the user intends to sweep around the Z axis (i.e. the line X = 0) to generate the solid of revolution, and that one edge of the polygon lies on that axis (you can generalize later once you have this simplified case working).
For simple enough geometry, you can treat the perimeter of the polygon as a function x = f(z), that is, assume there is a unique X value for every Z value. When we go to 3D, this function becomes r = f(z), that is, the radius is unique over the length of the object.
Now, suppose we want to approximate the solid with M "slices" each spanning 2 * Pi / M radians. We'll use N "stacks" (samples in the Z dimension) as well. For each such slice, we can build a triangle strip connecting the points on one slice (i) with the points on slice (i+1). Here's some pseudo-ish code describing the process:
double dTheta = 2.0 * pi / M;
double dZ = (zMax - zMin) / N;
// Iterate over "slices"
for (int i = 0; i < M; ++i) {
double theta = i * dTheta;
double theta_next = (i+1) * dTheta;
// Iterate over "stacks":
for (int j = 0; j <= N; ++j) {
double z = zMin + i * dZ;
// Get cross-sectional radius at this Z location from your 2D model (was the
// X coordinate in the 2D polygon):
double r = f(z); // See above definition
// Convert 2D to 3D by sweeping by angle represented by this slice:
double x = r * cos(theta);
double y = r * sin(theta);
// Get coordinates of next slice over so we can join them with a triangle strip:
double xNext = r * cos(theta_next);
double yNext = r * sin(theta_next);
// Add these two points to your triangle strip (heavy pseudocode):
strip.AddPoint(x, y, z);
strip.AddPoint(xNext, yNext, z);
}
}
That's the basic idea. As sje697 said, you'll possibly need to add end caps to keep the geometry closed (i.e. a solid object, rather than a shell). But this should give you enough to get you going. This can easily be generalized to toroidal shapes as well (though you won't have a one-to-one r = f(z) function in that case).
If you just want it to rotate, then:
glRotatef(angle,0,1,0);
will rotate it around the Y-axis. If you want a lathe, then this is far more complex.