How to find the point of collision between an irregular shape (built out of 3 circles) and a line - objective-c

I'm making a program in which many weird shapes are drawn onto a canvas. Right now i'm trying to implement the last, and possebly hardest, one.
In this particular shape i need a way to find the location (on a 2d canvas) where the line hits the shape. The following image is an example of what i have right now.
The black dots are the points that a known to me (i also have the location of the center of the three open circles and the radius of these circles). Each of the three outer lines needs a line towards the center dot, ending at the point that it hits the circle. This shape can be turned 90, 180 or 270 degrees.
The shape should look something like the following:
If you need any other information, please ask me in the comments. I'm not very good at math so please be gentle, thanks!

If A and B are points forming a line, then you can describe any point on that line using coordinates:
x = t·Ax + (1−t)·Bx
y = t·Ay + (1−t)·By
0 ≤ t ≤ 1
You can also describe the circle with center M and radius r as
(x − Mx)2 + (y − My)2 = r2
So take the x and y from the equations of the line, and plug them into the equation of the circle. You obtain a quadratic equation in t. Its two solutions describe the two points of intersection between the line and circle. In your example, only one of them lies on the line segment, i.e. satisfies 0 ≤ t ≤ 1. The other describes a point on the extension of the segment past its endpoint. Take the correct value for t back to the equations of the line, and you obtain the x and y coordinates of the point of intersection.
If you don't know up front which circle you want to intersect with a given line, then intersect all three and choose the most appropriate point afterwards. Probably that is the point closest to the outside starting point of the line segment. The same goes in cases where both points of intersection lie on the segment.

Related

How to find a point on a b-spline that is on the normal plane of a point on another b-spline using goemdl / nurbs

So the first problem will be explaining what I am after clearly.
I have two non-rational 3D b-splines. The first b-spline it the guiding spline. The second b-spline is a reference and it is essentially 'inside' of the first spline. ( the splines were generated in Solidworks )
Imagine a circular playground slide. The first spline is the center line of the slide. The second spline is the inside edge of the slide.
The inside spline will tend to be shorter than the center spline. The inside will also tend to have more curvature at any given point than the center.
The path of the slide is not perfectly circular. But the inside spline is always 'parallel' to the outside. ( very liberal use of the word parallel here )
What I am after:
Given a point along the center curve, I would like to find the point on the inside curve that is on the plane that is defined by the normal to the tangent of the center spline at that point.
Where I am at:
I am using the geomdl library in python to manipulate the splines.
I can choose a distance along the center spline and from geomdl I get the 3D point and the tangent vector (A,B,C) of that point and therefore the plane at that point that is normal to the spline at that point.
What I am doing:
From the tangent vector and the point I compute the equation of the plane in the form of:
Ax + By + Cz = D.
From there I guess at the point at the same distance on the inside spline and plug it into the equation for the plane that I already have. I use the error in D to guess at which way I should bump my guess on where the point on the inside curve might really be.
[ I understand that over the entire length of the two splines there may be more than one solution. i.e. if the curve wraps more than 180° there would be more than one point on the inside curve that lands on the plane defined by the center curve. In the local area that i am interested in this will not be a problem. Any second point would also be a long ways away from the center line. i.e. the correct point will be no more than 25 mm from the center point. A non-local point will be at least 3000 mm away. ]
This mostly works. But from time to time it fails. i.e. if D is very near 0 my guesses will diverge from the answer.
Currently I make 10 guesses, each guess having a smaller delta guess than the last.
I have a great number of these points to evaluate. My solution requires 10 X the number of calculations so it is not terribly efficient.
From my Google searches I believe that using the error in D in the equation of a plane may not be correct. I 'think' that D is the distance of the plane to the origin.(yes /no?) Therefore I am really comparing the distance of the two planes from the origin and not really from each other. If my guess happens to be on the "other side" of the origin then the distance's may be the same but opposite.
My Question:
What is the correct way to go about this?
Is my assumption that D is the distance from the plane to the origin?
Is driving the error in D between the two points valid?
What is the correct way to do this?
Restate my question in different terms
Given a plane (Ax + By + Cz = D) how do I find the point on a given b-spline that pierces ( or is coincident to ) that plane (using geomdl.bcurve)?
( I am very much in over my head here so please forgive if this does not make sense )

Most efficient way to check if a point is in or on a convex quad polygon

I'm trying to figure out the most efficient/fast way to add a large number of convex quads (four given x,y points) into an array/list and then to check against those quads if a point is within or on the border of those quads.
I originally tried using ray casting but thought that it was a little overkill since I know that all my polygons will be quads and that they are also all convex.
currently, I am splitting each quad into two triangles that share an edge and then checking if the point is on or in each of those two triangles using their areas.
for example
Triangle ABC and test point P.
if (areaPAB + areaPAC + areaPBC == areaABC) { return true; }
This seems like it may run a little slow since I need to calculate the area of 4 different triangles to run the check and if the first triangle of the quad returns false, I have to get 4 more areas. (I include a bit of an epsilon in the check to make up for floating point errors)
I'm hoping that there is an even faster way that might involve a single check of a point against a quad rather than splitting it into two triangles.
I've attempted to reduce the number of checks by putting the polygon's into an array[,]. When adding a polygon, it checks the minimum and maximum x and y values and then using those, places the same poly into the proper array positions. When checking a point against the available polygons, it retrieves the proper list from the array of lists.
I've been searching through similar questions and I think what I'm using now may be the fastest way to figure out if a point is in a triangle, but I'm hoping that there's a better method to test against a quad that is always convex. Every polygon test I've looked up seems to be testing against a polygon that has many sides or is an irregular shape.
Thanks for taking the time to read my long winded question to what's prolly a simple problem.
I believe that fastest methods are:
1: Find mutual orientation of all vector pairs (DirectedEdge-CheckedPoint) through cross product signs. If all four signs are the same, then point is inside
Addition: for every edge
EV[i] = V[i+1] - V[i], where V[] - vertices in order
PV[i] = P - V[i]
Cross[i] = CrossProduct(EV[i], PV[i]) = EV[i].X * PV[i].Y - EV[i].Y * PV[i].X
Cross[i] value is positive, if point P lies in left semi-plane relatively to i-th edge (V[i] - V[i+1]), and negative otherwise. If all the Cross[] values are positive, then point p is inside the quad, vertices are in counter-clockwise order. f all the Cross[] values are negative, then point p is inside the quad, vertices are in clockwise order. If values have different signs, then point is outside the quad.
If quad set is the same for many point queries, then dmuir suggests to precalculate uniform line equation for every edge. Uniform line equation is a * x + b * y + c = 0. (a, b) is normal vector to edge. This equation has important property: sign of expression
(a * P.x + b * Y + c) determines semi-plane, where point P lies (as for crossproducts)
2: Split quad to 2 triangles and use vector method for each: express CheckedPoint vector in terms of basis vectors.
P = a*V1+b*V2
point is inside when a,b>=0 and their sum <=1
Both methods require about 10-15 additions, 6-10 multiplications and 2-7 comparisons (I don't consider floating point error compensation)
If you could afford to store, with each quad, the equation of each of its edges then you could save a little time over MBo's answer.
For example if you have an inward pointing normal vector N for each edge of the quad, and a constant d (which is N.p for one of the vertcies p on the edge) then a point x is in the quad if and only if N.x >= d for each edge. So thats 2 multiplications, one addition and one comparison per edge, and you'll need to perform up to 4 tests per point.This technique works for any convex polygon.

Objective C Game Geometry question

I'm creating simple game and reached the point where I feel helpless. I was good in geometry but it was long time back in school, now trying to refresh my mind.
Let's say i have iPad screen. Object's xy position at one given point of time and xy position at another point of time stored in 2 variables .
Question:
how to find the third position of the object at the end of the screen being given previous 2 position, considering the object moves in the same direction (line) from point 1 to point 2.
Thanks in advance.
Let us have that v1 and v2 are the vectors representing the two points. Let t0 be the time between the two points. Let t be the current time.
Then our location vector v3 is given by v3 = v1 + (v2 - v1)t/t0
If the object is moving in the same direction and you have an horizontal line, the next position given x and y would be
x+1, y
If the object is moving in the same direction in a vertical line it would be
x, y+1
If the object is moving in a diagonal up-right
x+1,y+1
diagonal down-right
x+1, y+1
diagonal down-left
x-1, y-1
diagonal up-left
x-1, y+1
So something general would be :
newPosition = (x+1,y) //if you wish to move forward to the right, try to handle all
cases
All the cases above work if the object is moving forward, if it is moving backwards just change the + by - . Basically think of the object as moving in a cartesian coordinate system, where x is horizontal and y is vertical.
I think you can get the idea out of this three cases ;)

Placement of "good" control points in Bezier curves

I've been working on this problem for awhile now, and haven't been able to come up with a good solution thusfar.
The problem: I have an ordered list of three (or more) 2D points, and I want to stroke through these with a cubic Bezier curve, in such a way that it "looks good." The "looks good" part is pretty simple: I just want the wedge at the second point smoothed out (so, for example, the curve doesn't double-back on itself). So given three points, where should one place the two control points that would surround the second point in the triplet when drawing the curve.
My solution so far is as follows, but is incomplete. The idea might also help communicate the look that I'm after.
Given three points, (x1,y1), (x2,y2), (x3,y3). Take the circle inscribed by each triplet of points (if they are collinear, we just draw a straight line between them and move on). Take the line tangent to this circle at point (x2,y2) -- we will place the control points that surround (x2,y2) on this tangent line.
It's the last part that I'm stuck on. The problem I'm having is finding a way to place the two control points on this tangent line -- I have a good enough heuristic on how far from (x2,y2) on this line they should be, but of course, there are two points on this line that are that distance away. If we compute the one in the "wrong" direction, the curve loops around on itself.
To find the center of the circle described by the three points (if any of the points have the same x value, simply reorder the points in the calculation below):
double ma = (point2.y - point1.y) / (point2.x - point1.x);
double mb = (point3.y - point2.y) / (point3.x - point2.x);
CGPoint c; // Center of a circle passing through all three points.
c.x = (((ma * mb * (point1.y - point3.y)) + (mb * (point1.x + point2.x)) - (ma * (point2.x + point3.x))) / (2 * (mb - ma)));
c.y = (((-1 / ma) * (c.x - ((point1.x + point2.x) / 2))) + ((point1.y + point2.y) / 2));
Then, to find the points on the tangent line, in this case, finding the control point for the curve going from point2 to point3:
double d = ...; // distance we want the point. Based on the distance between
// point2 and point3.
// mc: Slope of the line perpendicular to the line between
// point2 and c.
double mc = - (c.x - point2.x) / (c.y - point2.y);
CGPoint tp; // point on the tangent line
double c = point2.y - mc * point2.x; // c == y intercept
tp.x = ???; // can't figure this out, the question is whether it should be
// less than point2.x, or greater than?
tp.y = mc * tp.x + c;
// then, compute a point cp that is distance d from point2 going in the direction
// of tp.
It sounds like you might need to figure out the direction the curve is going, in order to set the tangent points so that it won't double back on itself. From what I understand, it would be simply finding out the direction from (x1, y1) to (x2, y2), and then travelling on the tangent line your heuristic distance in the direction closest to the (x1, y1) -> (x2, y2) direction, and plopping the tangent point there.
If you're really confident that you have a good way of choosing how far along the tangent line your points should be, and you only need to decide which side to put each one on, then I would suggest that you look once again at that circle to which the line is tangent. You've got z1,z2,z3 in that order on the circle; imagine going around the circle from z2 towards z1, but go along the tangent line instead; that's which side the control point "before z2" should be; the control point "after z2" should be on the other side.
Note that this guarantees always to put the two control points on opposite sides of z2, which is important. (Also: you probably want them to be the same distance from z2, because otherwise you'll get a discontinuity at z2 in, er, the second derivative of your curve, which is likely to look a bit suboptimal.) I bet there will still be pathological cases.
If you don't mind a fair bit of code complexity, there's a sophisticated and very effective algorithm for exactly your problem (and more) in Don Knuth's METAFONT program (whose main purpose is drawing fonts). The algorithm is due to John Hobby. You can find a detailed explanation, and working code, in METAFONT or, perhaps better, the closely related METAPOST (which generates PostScript output instead of huge bitmaps).
Pointing you at it is a bit tricky, though, because METAFONT and METAPOST are "literate programs", which means that their source code and documentation consist of a kind of hybrid of Pascal code (for METAFONT) or C code (for METAPOST) and TeX markup. There are programs that will turn this into a beautifully typeset document, but so far as I know no one has put the result on the web anywhere. So here's a link to the source code, which you may or may not find entirely incomprehensible: http://foundry.supelec.fr/gf/project/metapost/scmsvn/?action=browse&path=%2Ftrunk%2Fsource%2Ftexk%2Fweb2c%2Fmplibdir%2Fmp.w&view=markup -- in which you should search for "Choosing control points".
(The beautifully-typeset document for METAFONT is available as a properly bound book under the title "METAFONT: the program". But it costs actual money, and the code is in Pascal.)

How can I find the first point along a heading that is a specified distance away from a line segment?

Given a starting point, a heading, a distance, and a line segment, find the first point along this heading that is the specified distance away from this line segment.
I covered two cases, but I haven't been able to cover the last one.
First case: heading away from the line. Ignore it even if the starting point is within the specified distance.
Second case: It intersects the line. I solved it using trig and triangles. Initially didn't consider the next case.
Third case: It is heading towards the line, but it does not intersect it. I think this will solve the second case as well if it's done correctly.
Three subcases:
The minimum line distance is greater than the specified distance. Ignore it.
The minimum line distance is equal to the specified distance. Found the points already.
The minimum line distance is less than the specified distance. This means there is a perpendicular line from the along the heading to an endpoint of the line segment that is less than the distance needed. This also means that on either side of this perpendicular line will be two lines of the distance needed. One is perpendicular to the heading, while the other is closest to the same endpoint and not perpendicular to the heading. Just a matter of finding those points and seeing which one is closer to the start point.
This is where I am stuck today. Drawing it up was easy, but doing the vector calc or whatever turned out tricky.
It's possible to rephrase this as:
At what time(s) is P(t) = P0 + t*v at a distance D from the line segment L((x1,y1), (x2,y2))?
v=(sin(heading), -cos(heading)) in my case.
Shoot mang your solution doesn't always work. I found a counter example:
Line Segment = (0,0) -> (0,14)
Start Point = (19, 6) # heading -159.5 or 200.5 in west/counter-clockwise
It will intersect the line at (2.952, 0.0) so I ask, where does it it come within a distance of 0.0.
The result I get is incorrect.
http://img5.imageshack.us/i/failuref.png/
How I can tell which ones will work using your solution and which ones do not work depends whether the minimum starting distance between the point and the line segment creates a perpendicular line.
If I can post another picture in the next post, I will put the successful example.
I would have liked to post some code for Sage which produced those images, but the code tags are accepting python unfortunately.
A successful result where the minimum starting distance between the point and the line segment is perpendicular to the line segment:
http://img46.imageshack.us/i/success.png/
Hi the solution I eventually came up with.
Does the ray intersect line segments that are parallel and the specified distance D away from the line segment. Just drawing a rectangle and checking the sides parallel to the line segment.
Does the ray intersect circles of radius D at each end point of the line segment.
Minimize for total unit time to find the first point along the ray that is D away from the line segment.
Possible Border case: Is the start point within D and heads away from the line? Up to the user how to handle this case.
Thanks, that works.
I found the alpha this way:
heading = 45.0*pi/180. #heading 45 degrees.
if x1 > x2: #line segment (x1,y1)<->(x2,y2)
dx = x2 - x1
dy = y2 - y1
else:
dx = x1 - x2
dy = y1 - y2
segmentHeading = atan2(dx, dy)
if heading > 0:
alpha = segmentHeading + heading
else:
alpha = -segmentHeading + heading
t = abs( (dStart - D) / -cos(alpha) ) #-cos in python, sin in C.