The Algorithm to Find the Point of Intersection of

2020-01-31 03:08发布

Finding the point of intersection for two 2D line segment is easy; the formula is straight forward. But finding the point of intersection for two 3D line segment 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?

标签: c# math
7条回答
2楼-- · 2020-01-31 03:23

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.

查看更多
老娘就宠你
3楼-- · 2020-01-31 03:32

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.

enter image description here

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.

查看更多
Melony?
4楼-- · 2020-01-31 03:35

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.

查看更多
劳资没心,怎么记你
5楼-- · 2020-01-31 03:39

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.

查看更多
女痞
6楼-- · 2020-01-31 03:41

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.

查看更多
叼着烟拽天下
7楼-- · 2020-01-31 03:45
// 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;
}
查看更多
登录 后发表回答