I have two 3D Points viz. (x1,y1,z1) and (x2,y2,z2) and a 3D Point (x,y,z).
I would like to know if (x,y,z) lies on the line connecting (x1,y1,z1) and (x2,y2,z2).
I tried the following algorithm:
if ((((x - x1) / x2-x1) == ((y - y1) / y2-y1)) && (((x - x1) / x2 - x1)
== ((z - z1) / z2- z1)) --> then,the 3D Line intersects (x,y,z)
But,what if my x1 = x2 (or) y1 = y2 (or) z1=z2? Then I would be getting an error saying "Division by zero" is not possible.
I would be glad,if someone can propose some alternative method.
Thanks in Advance.
I would use point-line distance measurement, and return true if the distance is less than some error threshold close to zero.
To elaborate, we are using a line made of two points, p1 and p2. We want to know if p3 is on the line. First we find d using the point-to-line distance formula.
d = ((p0 - p1).cross(p0 - p2)).length() / (p2 - p1).length()
That is, assuming you can use +, -, cross, length operations. You might prefer to find d squared for performance reasons.
d2 = ((p0 - p1).cross(p0 - p2)).lengthSquared() / (p2 - p1).lengthSquared()
Now, if d or d2 are exactly zero, then you must be on the line. But this is floating point arithmetic so I would allow a little bit of leeway depending on your application. So in essence, d < 1e6 or something should do the trick.
simple dot product can do this easily ... so let consider we got line defined by two points p0,p1. Any point p on that line will have the same or negative slope to any of the endpoints so
|dot(p1-p0,p-p0)|/(|p1-p0|*|p-p0|) = 1.0
to make it more robust with floating point compare like this:
|dot(p1-p0,p-p0)|/(|p1-p0|*|p-p0|) >= 1.0-1e-10;
Where 1e-10 is small enough epsilon ... rewriten to code:
dx=x1-x0;
dy=y1-y0;
dz=z1-z0;
ex=x-x0;
ey=y-y0;
ez=z-z0;
q =dx*ex;
q+=dy*ey;
q+=dz*zy;
q*=q;
q/=(dx*dx+dy*dy+dz*dz);
q/=(ex*ex+ey*ey+ez*ez);
if (q>=1.0-1e-10) point p(x,y) is on the line
else p(x,y) is not on line
As you can see no need for the sqrt we can compare the power instead ...
However you should handle edge case when p==p0 then either use p1 or return true right away.
In case you want points only inside the line segment (not outside the edge points) then you need a slight change in code
0.0 <= dot(p1-p0,p-p0)/|p-p0| <= 1.0
So:
dx=x1-x0;
dy=y1-y0;
dz=z1-z0;
ex=x-x0;
ey=y-y0;
ez=z-z0;
q =dx*ex;
q+=dy*ey;
q+=dz*zy;
if (q<0.0) p(x,y) is not on line
q*=q;
q/=(ex*ex+ey*ey+ez*ez);
if (q<=1.0) point p(x,y) is on the line
else p(x,y) is not on line
btw the result of the dot product gives you ratio of one vector projected to another perpendicularly or cos of the angle between them (if they are normalized) so for parallel vectors the result is 100% of length or 1.0. If you tweak the 1e-10 value using goniometry and p-p0 you can convert this to detect points up to some perpendicular distance to line (which might get handy for thick lines and or mouse selecting).
To solve the above-mentioned problem you need to check the area of the triangle considering them as 3 points in the 3-d space. To find the area go through this link. If area = 0 then given points are collinear.
if you are not concerned about performance issue you can use the parametric equation of a segment in the space.
P(t) = P0 + t(P1 - P0)
where P0 and P1 are 3d point and t is a parameter ranging from 0 to 1.
this lead to 3 equations
x(t) = x0 + t(x1 - x0)
y(t) = y0 + t(y1 - y0)
z(t) = z0 + t(z1 - z0)
so to check if your (x,y,z) point lies in the line, you could get an initial value for t, for example t = (x - x0)/(x1-x0) then check if that satisfies the other two equations
t = (x - x0)/(x1-x0)
if ( (y0 + t(y1-y0) == y) and (z0 + t(z1-z0) == z) ) then
---> we are in the line
Like #Jay pointed out, this is floating point math you have to deal with some tolerance with values. For example to test y could be y0 + t(y1-y0) - y < 0.001
As you yourself point out, doing this in a robust way is not trivial. Therefore, I suggest you don't reinvent the wheel and use a geometric library. I have good experience with using Wild Magic from geometrictools.com.
In your case, the predicate to use would be gte::DCPQuery to get the distance between a point and the line, and then test if it's close enough to zero for your purpose of "on the line."
An example of use could look like this:
using namespace gte;
Line3<double> line({x1, y1, z1}, {x2 - x1, y2 - y1, z2 - z1});
Vector3<double> point{x, y, z};
DCPPoint3Line3 query;
auto result = query(point, line);
bool pointIsOnLine = (result.distance < some_epsilon);
(Code note touched by compiler, intended to show the approach, not to be "semicolon-perfect").
I have Line segment AB defined by two 2D points A,B.
What I am trying to do is find a point C, with distance d away from B.
The two constraints are that BC has to be perpendicular to AB and BC is always 90 degrees anti-clockwise relative to AB.
So far I have the following
double d = .01;
Coordinate C = new Coordinate(A.Lat - B.Lat, A.Long - B.Long);
C.Long = C.Long * A.Long * Math.Cos(90);
C.Lat = C.Lat * A.Lat * Math.Cos(90);
C.Long = A.Long + C.Long * d;
C.Lat = A.Lat + C.Lat * d;
Essentially what I am asking is, where am I going wrong with this? Is it the c# code? Is it the logic? What are the steps to solve for C using those two constraints.
Normalize AB vector and rotate it by 90 degrees:
ABY = B.Y - A.Y
ABX = B.X - A.X
Len = Sqrt(ABY*ABY + ABX*ABX)
C.X = B.X - d * ABY / Len
C.Y = B.Y + d * ABX / Len
Note that for geographic coordinates (Lat/Long) and large distances result is not exact.
Link for further reference (sections Bearing then Destination point given distance and bearing from start point)
MBo has the correct answer for your task (as you got 90 degrees turn) I just wanted to show you how to repair your own code (I deduced you wanted to do this) which is usable to any angular turn (but slower as it require goniometric):
d = .01;
a = atan2(B.y - A.y,B.x - A.x) (+/-) 90.0; // sign depends on your coordinate system
C.x = B.x + d*cos(a)
C.y = B.y + d*sin(a)
So you should obtain directional angle a of your AB and shift it by 90 deg. Then you just add d rotated by the a to the C which can be done by parametric circle equation.
Beware all the angles should be in units your goniometric functions accepts (so either degrees or radians) as I do not code in C# I have not a clue but in languages I code in it is usually in radians. In which case line:
a = atan2(B.y - A.y,B.x - A.x) (+/-) 90.0; // sign depends on your
Would change to:
a = atan2(B.y - A.y,B.x - A.x) (+/-) 90.0*Pi/180.0; // sign depends on your
Where Pi=3.1415926535897932384626433832795.
I am building a windows form application that works with PolyLineZ (ESRI Shapefile) data and rewrites outlying Z values. The minimum and maximum Z-values are defined by the user through the interface
Let's take the following as an example, let's say the minimum is 0 and the maximum is 10:
XY Z
1,1 0
1,3 1
1,5 7
1,7 11*
1,10 10
The value with the 11 would need to be interpolated as it does not fall into the range defined by the user. This is a very simplified example obviously. Some PolyLines can be missing more values.
What I've done:
I've researched linear interpolation. Looked at example youtube videos, having a hard time wrapping my head around it.
What I need:
Code examples from either any language or an "English" explanation of the theory behind linear/bilinear/trilinear interpolation so that I can implement it into my program. My math skills aren't the greatest, so I have a hard time understanding wikipedias definition of it.
I'm also assuming that linear interpolation is what I need to research,
EDIT: Currently implementing the following, stop me if I'm wrong
I'm using what I think is Pythagorean Theory type approach. I haven't made it catch exceptions yet (ie, making sure the left point is actually left, make sure the list doesn't run out of bounds, etc), that can come later
internal static double calculateDistance(XYPoints a, XYPoints b)
{
double xd = b.X - a.X;
double yd = b.Y - a.Y;
return Math.Sqrt(xd * xd + yd * yd);
}
for (var i = 0; i < polylinez.ZPoints.Count;i++)
{
if (polylinez.ZPoints[i] > maxValue || (polylinez.ZPoints[i] < minValue))
{
//polylinez.ZPoints[i] = (((1 - polylinez.XYpoints[i].X) * polylinez.ZPoints[i - 1]) + (polylinez.XYpoints[i].X * polylinez.ZPoints[i + 1]));
double prevdistance = calculateDistance(polylinez.XYpoints[i - 1], polylinez.XYpoints[i]);
double nextdistance = calculateDistance(polylinez.XYpoints[i], polylinez.XYpoints[i + 1]);
double fraction = prevdistance / nextdistance;
double diffsBetweensZ = polylinez.ZPoints[i + 1] - polylinez.ZPoints[i - 1];
Console.WriteLine(polylinez.ZPoints[i - 1] + (diffsBetweensZ * fraction));
}
}
return polylinez;
It returns 9.12 as an answer for the above example table. This sounds about right to me. I checked my distance calculator method with sample data on the internet, and it seems to be doing the trick.
First step, create a routine for calculating distances:
internal static double calculateDistance(XYPoints a, XYPoints b)
{
double xd = b.X - a.X;
double yd = b.Y - a.Y;
return Math.Sqrt(xd * xd + yd * yd);
}
I changed the variable names to something more logical (my variable names were different)
//get distance frpm previous point to point in question
double prevdistance = calculateDistance(prevXYpoint, currentXYPoint);
//get distance frpm point in question to the next point
double nextdistance = calculateDistance(currentXYPoint, nextXYPoint);
//generate a ratio
double fraction = prevdistance / (nextdistance + prevdistance);
//find out the difference between the two known points
double diffsBetweensZ = nextZpointValue - prevZpointValue;
//interpolate!
double newZvalue = (prevZpointValue + (diffsBetweensZ * fraction));
I checked this on several sets of data and it's the most accurate thing I can find... what blows my mind is that I couldn't find any existing code anywhere to do this.
Finding the point of intersection for two 2D line segments is easy; the formula is straight forward. But finding the point of intersection for two 3D line segments is not, I afraid.
What is the algorithm, in C# preferably that finds the point of intersection of two 3D line segments?
I found a C++ implementation here. But I don't trust the solution because it makes preference of a certain plane (look at the way perp is implemented under the implementation section, it assumes a preference for z plane. Any generic algorithm must not assume any plane orientation or preference).
Is there a better solution?
Most 3D lines do not intersect. A reliable method is to find the shortest line between two 3D lines. If the shortest line has a length of zero (or distance less than whatever tolerance you specify) then you know that the two original lines intersect.
A method for finding the shortest line between two 3D lines, written by Paul Bourke is summarized / paraphrased as follows:
In what follows a line will be defined by two points lying on it, a
point on line "a" defined by points P1 and P2 has an equation
Pa = P1 + mua (P2 - P1)
similarly a point on a second line "b" defined by points P4 and P4
will be written as
Pb = P3 + mub (P4 - P3)
The values of mua and mub range from negative to positive infinity.
The line segments between P1 P2 and P3 P4 have their corresponding mu
between 0 and 1.
There are two approaches to finding the shortest line segment between
lines "a" and "b".
Approach one:
The first is to write down the length of the line
segment joining the two lines and then find the minimum. That is,
minimise the following
|| Pb - Pa ||^2
Substituting the equations of the lines gives
|| P1 - P3 + mua (P2 - P1) - mub (P4 - P3) ||^2
The above can then be expanded out in the (x,y,z) components.
There are conditions to be met at the minimum, the derivative with
respect to mua and mub must be zero. ...the above function only has
one minima and no other minima or maxima. These two equations can then
be solved for mua and mub, the actual intersection points found by
substituting the values of mu into the original equations of the line.
Approach two:
An alternative approach but one that gives the exact same equations is
to realise that the shortest line segment between the two lines will
be perpendicular to the two lines. This allows us to write two
equations for the dot product as
(Pa - Pb) dot (P2 - P1) = 0
(Pa - Pb) dot (P4 - P3) = 0
Expanding these given the equation of the lines
( P1 - P3 + mua (P2 - P1) - mub (P4 - P3) ) dot (P2 - P1) = 0
( P1 - P3 + mua (P2 - P1) - mub (P4 - P3) ) dot (P4 - P3) = 0
Expanding these in terms of the coordinates (x,y,z) ...
the result is as follows
d1321 + mua d2121 - mub d4321 = 0
d1343 + mua d4321 - mub d4343 = 0
where
dmnop = (xm - xn)(xo - xp) + (ym - yn)(yo - yp) + (zm - zn)(zo - zp)
Note that dmnop = dopmn
Finally, solving for mua gives
mua = ( d1343 d4321 - d1321 d4343 ) / ( d2121 d4343 - d4321 d4321 )
and back-substituting gives mub
mub = ( d1343 + mua d4321 ) / d4343
This method was found on Paul Bourke's website which is an excellent geometry resource. The site has been reorganized, so scroll down to find the topic.
// This code in C++ works for me in 2d and 3d
// assume Coord has members x(), y() and z() and supports arithmetic operations
// that is Coord u + Coord v = u.x() + v.x(), u.y() + v.y(), u.z() + v.z()
inline Point
dot(const Coord& u, const Coord& v)
{
return u.x() * v.x() + u.y() * v.y() + u.z() * v.z();
}
inline Point
norm2( const Coord& v )
{
return v.x() * v.x() + v.y() * v.y() + v.z() * v.z();
}
inline Point
norm( const Coord& v )
{
return sqrt(norm2(v));
}
inline
Coord
cross( const Coord& b, const Coord& c) // cross product
{
return Coord(b.y() * c.z() - c.y() * b.z(), b.z() * c.x() - c.z() * b.x(), b.x() * c.y() - c.x() * b.y());
}
bool
intersection(const Line& a, const Line& b, Coord& ip)
// http://mathworld.wolfram.com/Line-LineIntersection.html
// in 3d; will also work in 2d if z components are 0
{
Coord da = a.second - a.first;
Coord db = b.second - b.first;
Coord dc = b.first - a.first;
if (dot(dc, cross(da,db)) != 0.0) // lines are not coplanar
return false;
Point s = dot(cross(dc,db),cross(da,db)) / norm2(cross(da,db));
if (s >= 0.0 && s <= 1.0)
{
ip = a.first + da * Coord(s,s,s);
return true;
}
return false;
}
I tried #Bill answer and it actually does not work every time, which I can explain. Based on the link in his code.Let's have for example these two line segments AB and CD.
A=(2,1,5), B=(1,2,5) and C=(2,1,3) and D=(2,1,2)
when you try to get the intersection it might tell you It's the point A (incorrect) or there is no intersection (correct). Depending on the order you put those segments in.
x = A+(B-A)s
x = C+(D-C)t
Bill solved for s but never solved t. And since you want that intersection point to be on both line segments both s and t have to be from interval <0,1>. What actually happens in my example is that only s if from that interval and t is -2. A lies on line defined by C and D, but not on line segment CD.
var s = Vector3.Dot(Vector3.Cross(dc, db), Vector3.Cross(da, db)) / Norm2(Vector3.Cross(da, db));
var t = Vector3.Dot(Vector3.Cross(dc, da), Vector3.Cross(da, db)) / Norm2(Vector3.Cross(da, db));
where da is B-A, db is D-C and dc is C-A, I just preserved names provided by Bill.
Then as I said you have to check if both s and t are from <0,1> and you can calculate the result. Based on formula above.
if ((s >= 0 && s <= 1) && (k >= 0 && k <= 1))
{
Vector3 res = new Vector3(this.A.x + da.x * s, this.A.y + da.y * s, this.A.z + da.z * s);
}
Also another problem with Bills answer is when two lines are collinear and there is more than one intersection point. There would be division by zero. You want to avoid that.
The original source you mention is only for the 2d case. The implementation for perp is fine. The use of x and y are just variables not an indication of preference for a specific plane.
The same site has this for the 3d case:
"http://geomalgorithms.com/a07-_distance.html"
Looks like Eberly authored a response:
"https://www.geometrictools.com/Documentation/DistanceLine3Line3.pdf"
Putting this stuff here because google points to geomalgorithms and to this post.
I found a solution: it's here.
The idea is to make use of vector algebra, to use the dot and cross to simply the question until this stage:
a (V1 X V2) = (P2 - P1) X V2
and calculate the a.
Note that this implementation doesn't need to have any planes or axis as reference.
But finding the point of intersection for two 3D line segment is not, I afraid.
I think it is. You can find the point of intersection in exactly the same way as in 2d (or any other dimension). The only difference is, that the resulting system of linear equations is more likely to have no solution (meaning the lines do not intersect).
You can solve the general equations by hand and just use your solution, or solve it programmatically, using e.g. Gaussian elemination.
I found an answer!
in an answer from above, I found these equations:
Eq#1: var s = Vector3.Dot(Vector3.Cross(dc, db), Vector3.Cross(da, db)) / Norm2(Vector3.Cross(da, db));
Eq#2: var t = Vector3.Dot(Vector3.Cross(dc, da), Vector3.Cross(da, db)) / Norm2(Vector3.Cross(da, db));
Then I modified #3rd Equation:
Eq#3:
if ((s >= 0 && s <= 1) && (k >= 0 && k <= 1))
{
Vector3 res = new Vector3(this.A.x + da.x * s, this.A.y + da.y * s, this.A.z + da.z * s);
}
And while keeping Eq#1 and Eq#2 just the same, I created this equations:
MyEq#1: Vector3f p0 = da.mul(s).add(A<vector>);
MyEq#2: Vector3f p1 = db.mul(t).add(C<vector>);
then I took a wild guess at creating these three more equations:
MyEq#3: Vector3f p0z = projUV(da, p0).add(A<vector>);
MyEq#4: Vector3f p1z = projUV(db, p1).add(C<vector>);
and finally to get the subtraction of the two magnitudes of the projUV(1, 2) gives you the margin of the error between 0 and 0.001f to find whether the two lines intersect.
MyEq#5: var m = p0z.magnitude() - p1z.magnitude();
Now I mind you, this was done in Java. This explanation is not java convention ready. Just put it to work from the above equations. (Tip: Don't transform to World Space yet so that both projection of UV equations fall exactly where you want them).
And these equations are visually correct in my program.
In addition to Bobs answer:
I find on testing that the intersection() function as written solves half the original problem, which was an algorithm to find the point of intersection of two 3D line segments.
Assuming the lines are coplanar, there are 5 possible outcomes to this question:
The line segments are parallel, so they don't intersect, or,
The line segments aren't parallel, and the infinite length lines they lie upon do intersect, but the intersection point is not within the bounds of either line segment, or,
The lines intersect and the intersection point is within the bounds of line a but not line b, or,
The lines intersect and the intersection point is within the bounds of line b but not line a, or,
The lines intersect and the intersection point is within the bounds of both line segments.
Bob's intersection() function returns true when the lines intersect and the point of intersection is within the bounds of line a, but returns false if the lines intersect and the point of intersection is within the bounds of only line b.
But if you call intersect() twice, first with lines a then b and then a second time with lines b and a (first and second params swapped), then if both calls return true, then the intersect is contained within both line segments (case 5). If both calls return false, then neither line segment contains the intersect (case 2). If only one of the calls returns true, then the segment passed as the first parameter on that call contains the point of intersection (cases 3 or 4).
Also, if the return from the call to norm2(cross(da,db)) equals 0.0, then the line segments are parallel (case 1).
The other thing I noted in testing is that with fixed precision floating point numbers of the kind code is often implemented with, it can be quite unusual for dot(dc, cross(da,db)) to return 0.0, so returning false when its not the case might not be what you want. You might want to introduce a threshold below which the code continues to execute rather than return false. This indicates the line segments are skew in 3D, but depending on your application you might want to tolerate a small amount of skew.
The final thing I noticed was this statement in Bill's code:
ip = a.first + da * Coord(s,s,s);
That da * Coord(s,s,s) looks to be a vector times vector multiply. When I replaced it with a scalar multiple of da * s, I found it worked fine.
But in any case, many thanks to Bob. He figured out the hard part.
https://bloodstrawberry.tistory.com/1037
This blog was implemented by Unity c#.
Vector3 getContactPoint(Vector3 normal, Vector3 planeDot, Vector3 A, Vector3 B)
{
Vector3 nAB = (B - A).normalized;
return A + nAB * Vector3.Dot(normal, planeDot - A) / Vector3.Dot(normal, nAB);
}
(Vector3 point1, Vector3 point2) getShortestPath(Vector3 A, Vector3 B, Vector3 C, Vector3 D)
{
Vector3 AB = A - B;
Vector3 CD = C - D;
Vector3 line = Vector3.Cross(AB, CD);
Vector3 crossLineAB = Vector3.Cross(line, AB);
Vector3 crossLineCD = Vector3.Cross(line, CD);
return (getContactPoint(crossLineAB, A, C, D), getContactPoint(crossLineCD, C, A, B));
}
I am trying to implement a Point3.Slerp method, so was looking for some samples but the ones I found seems like it's a whole brand new class to host all the code.
Is there a simple, straightforward way to implement it? Basically the ones I have seen was using Matrix types. Can I implement Slerp without matrices, or would that be a disadvantage (performance, etc)?
Pseudo codes are fine too.
Spherical linear interpolation typically used with Quaternions, not Points. It's only really meaningful when you are trying to interpolate between two specific rotations.
The only place where I can see this being directly related to Point3 would be if you had 2 points on the surface of a sphere, and you wanted to "slerp" between them around the geodesic path. In that case, your points aren't really points being interpolated - they're being used to compute two axes and angles (which define quaternions) and interpolating between those.
If you're interpolating between two point3 values, direct linear interpolation is probably what you would want to do.
As for using matrices - if you get your points into quaternion form, you can use quaternion math directly - no matrices required.
A point slerp is meaningful if you're working with a spherical space (such as a planet's surface or likewise).
Off the top of my head I would take the cross product of your start and end points (as vectors) to get a rotation axis then you can calculate a rotation for the X, Y, and Z (to avoid having to create your own matrix class, as you seem to want to).
http://en.wikipedia.org/wiki/Rotation_matrix#Dimension_three
That link shows a rotation matrix for an axis/angle pair. Just write out the multiplication for each component and simplify to get a matrix-less tranformation.
edit:
Heres a simple decomposed rotation about an axis (x, y, z):
X' = (x^2 + (1 - x^2) * cos(theta) + (x * y * (1 - cos(theta)) - x * sin(theta)) + (x * z * (1 - cos(theta)) + y * sin(theta))
Y' = (x * y * (1 - cos(theta)) + z * sin(theta)) + (y^2 + (1 - y^2) * cos(theta)) + (y * z * (1 - cos(theta)) - x * sin(theta))
Z' = (x * z * (1 - cos(theta)) - y * sin(theta)) + (y * z * (1 - cos(theta)) + x * sin(theta)) + (z^2 + (1 - z^2) * cos(theta))
Since you want a parameterized rotation as well, make sure you calculate the angle between your vectors (the inverse cosine of the scalar product of the two points) and set your theta as a value between 0 and that angle based on your interpolation parameter.
To Slerp you need quaternions, which is why there is a whole new class.