I have been working on a problem and through all of my research I have been unable to find an existing resolution. I do not have the required math knowledge to produce an elegant solution.
There are several examples of working (and very elegant) line - line intersections with either complete lines or line segment (see links) :
https://dl.dropboxusercontent.com/u/99937114/Forums/Eileens%20Lounge%20-%20LinearIntersect_Corrected.xls
(other examples in the dropbox shared folder)
The problem I have is illustrated using the attached image. There is a defined line, starting at L1 (x,y) and finishing at L2 (x,y). There is no second line - instead there are the coordinates for another point (effectively L3) and an axis or angle of travel. I need to calculate the distance to and coordinates of the intersect if the point L3 was continued along the axis / angle of travel.
It would also be useful to get the coordinates of a position when provided with an origin, a bearing and a distance e.g. x, y with a distance of 10m on a bearing of 195 degrees arrives you at x, y? This is effectively the same function, except the distance is defines vs calculating the distance and x, y of the intersection
Coming from a background of projective geometry, computing cross products of homogeneous coordinates is my favorite way to elegantly join points or intersect (infinite) lines. In your case, I'd first rename points. Suppose the first line is defined by A and B, and the second line passes through C and has angle z as you indicated. Then I'd compute
⎡Dx⎤ ⎛⎡Ax⎤ ⎡Bx⎤⎞ ⎛⎡Cx⎤ ⎡sin z⎤⎞ ⎡(Ay Bx - Ax By) sin z - (Cx cos z - Cy sin z) (Ax - Bx)⎤
⎢Dy⎥ = ⎜⎢Ay⎥ × ⎢By⎥⎟ × ⎜⎢Cy⎥ × ⎢cos z⎥⎟ = ⎢(Ay Bx - Ax By) cos z - (Cx cos z - Cy sin z) (Ay - By)⎥
⎣Dz⎦ ⎝⎣1 ⎦ ⎣1 ⎦⎠ ⎝⎣1 ⎦ ⎣ 0 ⎦⎠ ⎣(Ay - By) sin z - (Ax - Bx ) cos z ⎦
Then (Dx/Dz, Dy/Dz) are the coordinates of the point of intersection, and the distance from that to C can be computed in the usual way using Pythagoras. The first inner cross product describes the line joining A and B. The second inner cross product joins C with a point at infinity in the direction you indicated. The outer cross product then intersects these two lines, yielding homogeneous coordinates for the point of intersection.
Related
I think there is a pretty straightForward answer to this, but i cant find it. My geometry lessons are too far away for this. the problem is:
Given 2 points A and B (coordinates Ax Ay Bx and By), I want to find the coordinates of points C and D so that [AB] and [CD] segments intersect at their center and [CD] has a length of d (a variable).
I want to find the equation giving me Cx,Cy,Dx and Dy from Ax,Ay,Bx,By and d.
Here is a little schema of the problem:
and an image of the intended result:
I already know how to find the center point of [AB] (Ax+Bx/2, Ay+By/2), how to find the slope of the [AB] segment (By-Ay/Bx-Ax) and then one of the [CD] segment (Ax-Bx/By-Ay). But then i get stuck on how to get my two points. I thought i could calculate the angle from the slope, then use it with some trigonometry to get the coordinates but it sounds like a quite heavy, ugly and unnecessary calculation...
It feels so close, but i still cant get it.
I also found this post, which is almost perfect, but the length cannot be defined: it must be the same as the first segment.
I dont think this is language-dependent, but if you must know, i'm doing a mini prototype on processing and will probably get it on javascript later.
Thanks for any help.
The basic trick here is that, in 2d, the perpendicular to a vector (x, y) is merely ± (-y, x). (One gets this by computing the cross product with the (0, 0, 1) vector in 3d, and projecting to 2d.) So what you need to do is:
Get the midpoint between A and B (you have done that).
Get the vector from A to B, which is B - A = (x, y) = (bx - ax, by - ay).
Get the perpendicular vector: (-y, x).
Normalize it. Let length = sqrt(y*y + x*x), then norm = (-y/length, x/length).
Multiply the normalized perpendicular by your desired distance ± d/2 (since you want the distance between C and D to be d), and add to the center point.
No slopes or trig functions are required.
I have the plane equation describing the points belonging to a plane in 3D and the origin of the normal X, Y, Z. This should be enough to be able to generate something like a 3D arrow. In pcl this is possible via the viewer but I would like to actually store those 3D points inside the cloud. How to generate them then ? A cylinder with a cone on top ?
To generate a line perpendicular to the plane:
You have the plane equation. This gives you the direction of the normal to the plane. If you used PCL to get the plane, this is in ModelCoefficients. See the details here: SampleConsensusModelPerpendicularPlane
The first step is to make a line perpendicular to the normal at the point you mention (X,Y,Z). Let (NORMAL_X,NORMAL_Y,NORMAL_Z) be the normal you got from your plane equation. Something like.
pcl::PointXYZ pnt_on_line;
for(double distfromstart=0.0;distfromstart<LINE_LENGTH;distfromstart+=DISTANCE_INCREMENT){
pnt_on_line.x = X + distfromstart*NORMAL_X;
pnt_on_line.y = Y + distfromstart*NORMAL_Y;
pnt_on_line.z = Z + distfromstart*NORMAL_Z;
my_cloud.points.push_back(pnt_on_line);
}
Now you want to put a hat on your arrow and now pnt_on_line contains the end of the line exactly where you want to put it. To make the cone you could loop over angle and distance along the arrow, calculate a local x and y and z from that and convert them to points in point cloud space: the z part would be converted into your point cloud's frame of reference by multiplying with the normal vector as with above, the x and y would be multiplied into vectors perpendicular to this normal vectorE. To get these, choose an arbitrary unit vector perpendicular to the normal vector (for your x axis) and cross product it with the normal vector to find the y axis.
The second part of this explanation is fairly terse but the first part may be the more important.
Update
So possibly the best way to describe how to do the cone is to start with a cylinder, which is an extension of the line described above. In the case of the line, there is (part of) a one dimensional manifold embedded in 3D space. That is we have one variable that we loop over adding points. The cylinder is a two dimensional object so we have to loop over two dimensions: the angle and the distance. In the case of the line we already have the distance. So the above loop would now look like:
for(double distfromstart=0.0;distfromstart<LINE_LENGTH;distfromstart+=DISTANCE_INCREMENT){
for(double angle=0.0;angle<2*M_PI;angle+=M_PI/8){
//calculate coordinates of point and add to cloud
}
}
Now in order to calculate the coordinates of the new point, well we already have the point on the line, now we just need to add it to a vector to move it away from the line in the appropriate direction of the angle. Let's say the radius of our cylinder will be 0.1, and let's say an orthonormal basis that we have already calculated perpendicular to the normal of the plane (which we will see how to calculate later) is perpendicular_1 and perpendicular_2 (that is, two vectors perpendicular to each other, of length 1, also perpendicular to the vector (NORMAL_X,NORMAL_Y,NORMAL_Z)):
//calculate coordinates of point and add to cloud
pnt_on_cylinder.x = pnt_on_line.x + 0.1 * perpendicular_1.x * 0.1 * cos(angle) + perpendicular_2.x * sin(angle)
pnt_on_cylinder.y = pnt_on_line.y + perpendicular_1.y * 0.1 * cos(angle) + perpendicular_2.y * 0.1 * sin(angle)
pnt_on_cylinder.z = pnt_on_line.z + perpendicular_1.z * 0.1 * cos(angle) + perpendicular_2.z * 0.1 * sin(angle)
my_cloud.points.push_back(pnt_on_cylinder);
Actually, this is a vector summation and if we were to write the operation as vectors it would look like:
pnt_on_line+perpendicular_1*cos(angle)+perpendicular_2*sin(angle)
Now I said I would talk about how to calculate perpendicular_1 and perpendicular_2. Let K be any unit vector that is not parallel to (NORMAL_X,NORMAL_Y,NORMAL_Z) (this can be found by trying e.g. (1,0,0) then (0,1,0)).
Then
perpendicular_1 = K X (NORMAL_X,NORMAL_Y,NORMAL_Z)
perpendicular_2 = perpendicular_1 X (NORMAL_X,NORMAL_Y,NORMAL_Z)
Here X is the vector cross product and the above are vector equations. Note also that the original calculation of pnt_on_line involved a vector dot product and a vector summation (I am just writing this for completeness of the exposition).
If you can manage this then the cone is easy just by changing a couple of things in the double loop: the radius just changes along its length until it is zero at the end of the loop and in the loop distfromstart will not start at 0.
I have two normalized vectors:
A) 0,0,-1
B) 0.559055,0.503937,0.653543
I want to know, what rotations about the axes would it take to take the vector at 0,0,-1 to 0.559055,0.503937,0.653543?
How would I calculate this? Something like, rotate over X axis 40 degrees and Y axis 220 (that's just example, but I don't know how to do it).
Check this out. (google is a good thing)
This calculates the angle between two vectors.
If Vector A is (ax, ay, az) and
Vector B is (bx, by, bz), then
The cos of angle between them is:
(ax*bx + ay*by + az*bz)
--------------------------------------------------------
sqrt(ax*ax + ay*ay + az*az) * sqrt(bx*bx + by*by + bz*bz)
To calculate the angle between the two vectors as projected onto the x-y plane, just ignore the z-coordinates.
Cosine of Angle in x-y plane =
(ax*bx + ay*by)
--------------------------------------
sqrt(ax*ax + ay*ay) * sqrt(bx*bx + by*by
Similarly, to calculate the angle between the projections of the two vectors in the x-z plane, ignore the y-coordinates.
It sounds like you're trying convert from Cartesian coordinates (x,y,z) into spherical coordinates (rho,theta,psi).
Since they're both unit vectors, rho, the radius, will be 1. This means your magnitudes will also be 1 and you can skip the whole denominator and just use the dot-product.
Rotating in the X/Y plane (about the Z axis) will be very difficult with your first example (0,0,-1) because it has no extension in X or Y. So there's nothing to rotate.
(0,0,-1) is 90 degrees from (1,0,0) or (0,1,0). If you take the x-axis to be the 0-angle for theta, then you calculate the phi (rotation off of the X/Y plane) by applying the inverse cos upon (x,y,z) and (x,y,0), then you can skip dot-products and get theta (the x/y rotation) with atan2(y,x).
Beware of gimbal lock which may cause problems.
How do I find the closest intersection in 2D between a ray:
x = x0 + t*cos(a), y = y0 + t*sin(a)
and m polylines:
{(x1,y1), (x2,y2), ..., (xn,yn)}
QUICKLY?
I started by looping trough all linesegments and for each linesegment;
{(x1,y1),(x2,y2)} solving:
x1 + u*(x2-x1) = x0 + t*cos(a)
y1 + u*(y2-y1) = y0 + t*sin(a)
by Cramer's rule, and afterward sorting the intersections on distance, but that was slow :-(
BTW: the polylines happens to be monotonically increasing in x.
Coordinate system transformation
I suggest you first transform your setup to something with easier coordinates:
Take your point p = (x, y).
Move it by (-x0, -y0) so that the ray now starts at the center.
Rotate it by -a so that the ray now lies on the x axis.
So far the above operations have cost you four additions and four multiplications per point:
ca = cos(a) # computed only once
sa = sin(a) # likewise
x' = x - x0
y' = y - y0
x'' = x'*ca + y'*sa
y'' = y'*ca - x'*sa
Checking for intersections
Now you know that a segment of the polyline will only intersect the ray if the sign of its y'' value changes, i.e. y1'' * y2'' < 0. You could even postpone the computation of the x'' values until after this check. Furthermore, the segment will only intersect the ray if the intersection of the segment with the x axis occurs for x > 0, which can only happen if either value is greater than zero, i.e. x1'' > 0 or x2'' > 0. If both x'' are greater than zero, then you know there is an intersection.
The following paragraph is kind of optional, don't worry if you don't understand it, there is an alternative noted later on.
If one x'' is positive but the other is negative, then you have to check further. Suppose that the sign of y'' changed from negative to positive, i.e. y1'' < 0 < y2''. The line from p1'' to p2'' will intersect the x axis at x > 0 if and only if the triangle formed by p1'', p2'' and the origin is oriented counter-clockwise. You can determine the orientation of that triangle by examining the sign of the determinant x1''*y2'' - x2''*y1'', it will be positive for a counter-clockwise triangle. If the direction of the sign change is different, the orientation has to be different as well. So to take this together, you can check whether
(x1'' * y2'' - x2'' * y1'') * y2'' > 0
If that is the case, then you have an intersection. Notice that there were no costly divisions involved so far.
Computing intersections
As you want to not only decide whether an intersection exists, but actually find a specific one, you now have to compute that intersection. Let's call it p3. It must satisfy the equations
(x2'' - x3'')/(y2'' - y3'') = (x1'' - x3'')/(y1'' - y3'') and
y3'' = 0
which results in
x3'' = (x1'' * y1'' - x2'' * y2'')/(y1'' - y2'')
Instead of the triangle orientation check from the previous paragraph, you could always compute this x3'' value and discard any results where it turns out to be negative. Less code, but more divisions. Benchmark if in doubt about performance.
To find the point closest to the origin of the ray, you take the result with minimal x3'' value, which you can then transform back into its original position:
x3 = x3''*ca + x0
y3 = x3''*sa + y0
There you are.
Note that all of the above assumed that all numbers were either positive or negative. If you have zeros, it depends on the exact interpretation of what you actually want to compute, how you want to handle these border cases.
To avoid checking intersection with all segments, some space partition is needed, like Quadtree, BSP tree. With space partition it is needed to check ray intersection with space partitions.
In this case, since points are sorted by x-coordinate, it is possible to make space partition with boxes (min x, min y)-(max x, max y) for parts of polyline. Root box is min-max of all points, and it is split in 2 boxes for first and second part of a polyline. Number of segments in parts is same or one box has one more segment. This box splitting is done recursively until only one segment is in a box.
To check ray intersection start with root box and check is it intersected with a ray, if it is than check 2 sub-boxes for an intersection and first test closer sub-box then farther sub-box.
Checking ray-box intersection is checking if ray is crossing axis aligned line between 2 positions. That is done for 4 box boundaries.
Using the following start and end point coordinate values of a baseline:
X1 = 5296823.36
Y1 = 2542131.23
X2 = 5311334.21
Y2 = 2548768.66
I would like to calculate the start and end coordinates of a pendicular line that intersects the baseline at the mid-point. This intersecting, perpendicular line should extend at a given distance either side of the baseline (e.g. Dist=100).
I would be very grateful if anyone could provide some guidance using simple formulas that can be tranferred to Excel or VB.
Many thanks in advance.
Steps to do:
Find the midpoint of the two coordinates (xmid, ymid)
Find the gradient of the line segment joining the two coordinates (call it m).
The gradient of a line perpendicular to this line is -1/m.
Use this new gradient and the coordinates of the midpoint (xmid, ymid) to find the equation of the perpendicular line (substitute xmid, ymid and -1/m into the equation of a line), call it y = -1x/m + k
Imagine a right angled triangle from xmid, ymid to your target point (r units along the perpendicular line is the hypotenuse). The x component will be X units across, the y component will be (-1X/m + k) units up.
Solve
r^2 = X^2 + (-1X/m + k)^2
to find X. Where you have already found r, m and k in the previous steps.
Substitute the +ve and -ve values of this into y = -1x/m + k to get the y coordinates of your endpoints, and Bob's your Uncle.
It should be relatively straight forward to translate this into any given programming language in a very short space of time but you may need to understand the underlying maths to do so, and as a Maths teacher I'm not going to do your Homework for you.