How can I tell if a point is nearby a certain line? - c#

I asked "How can I tell if a point belongs to a certain line?" before and I found a suitable answer so thank you very much.
Now, I would like to know how to tell if a certain point is close to my line.

You need to calculate the right angle distance to the line. Then you have to define what "close" is and test if it is within that distance.
The equation you want is:

#Alan Jackson's answer is almost perfect - but his first (and most up-voted) comment suggests that endpoints are not correctly handled. To ensure the point is on the segment, simply create a box where the segment is a diagonal, then check if the point is contained within. Here is the pseudo-code:
Given Line ab, comprised of points a and b, and Point p, in question:
int buffer = 25;//this is the distance that you would still consider the point nearby
Point topLeft = new Point(minimum(a.x, b.x), minimum(a.y, b.y));
Point bottomRight = new Point(maximum(a.x, b.x), maximum(a.y, b.y));
Rect box = new Rect(topLeft.x - buffer, topLeft.y - buffer, bottomRight.x + buffer, bottomRight.y + buffer);
if (box.contains(p))
{
//now run the test provided by Alan
if (test)
return true;
}
return false;

Here's a python function which does the trick. It should work in 2 or 3 dimensions (or more) and handles vertical and horizontal lines without special cases. If you set clipToSegment to true the returned point is clipped to the ends if the projected line extends beyond the supplied line segment.
def nearestPointOnLine(pt, r0, r1, clipToSegment = True):
r01 = r1 - r0 # vector from r0 to r1
d = np.linalg.norm(r01) # length of r01
r01u = r01 / d # unit vector from r0 to r1
r = pt - r0 # vector from r0 to pt
rid = np.dot(r, r01u) # projection (length) of r onto r01u
ri = r01u * rid # projection vector
lpt = r0 + ri # point on line
if clipToSegment: # if projection is not on line segment
if rid > d: # clip to endpoints if clipToSegment set
return r1
if rid < 0:
return r0
return lpt
Usage: (distance of point [4,5] from the line segment from [2,4] to [4,6])
r0 = np.array([2,4])
r1 = np.array([4,6])
rpt = np.array([4,5])
pt = nearestPointOnLine(rpt, r0, r1, True)
dist = np.linalg.norm(rpt-pt)
print('dist', dist)

Basically, what you want to do it find the normal line — that is, a line perpendicular to your line — that intersects your point and the line, and then compute the distance along that line.

How close is near?
Some geometry will give you the answer you need, you just need to be aware of the following steps.
Assuming your like is of the form y=mx+b, the shortest distance to your point will be the line perpendicular to your starting line (m1=-1/m), intersecting your point in question.
From there you calculate the distance between the intersection point and the point in question.

Calculate the point on your line that is closest to that point.
Assuming the line segment is a and b, and the point is p.
float vAPx = p.x - a.x;
float vAPy = p.y - a.y;
float vABx = b.x - a.x;
float vABy = b.y - a.y;
float sqDistanceAB = a.distanceSq(b);
float ABAPproduct = vABx*vAPx + vABy*vAPy;
float amount = ABAPproduct / sqDistanceAB;
if (amount > 1) amount = 1;
if (amount < 0) amount = 0;
Which gives you 'amount', how far through the line segment you are between A and B (properly bounded).
float nx = (amount * (b.x - a.x)) + a.x;
float ny = (amount * (b.y - a.y)) + a.y;
Gives you point (nx,ny).
if (p.distance(nx,ny) > threshold) reject;
This will properly work beyond the end of the line segment, because it keeps 'amount' between 0 and 1.
If you don't want it a bounded line segment get rid of the bounds for amount. The rest of the code will still work, calculating positions beyond and before A and beyond B.
There was another question that claimed this question was a duplicate but, it's asking for a different thing hence my solution solves for the position of the point and then just solves the Euclidean distance (which actually solves both questions).
a.distanceSq(b) can also be done as vABxvABx + vAByvABy, since we already have those done.

Google is your friend: Point-Line Distance (2-Dimensional). You can just use the equation at the bottom and there you go.

Related

How to get a parabola shape according to a moved point and nearest points

Being not very good at math, I have a problem with my project.
The objective is boundary correction on 3D files.
In my application, the user moves a 3D point on X-axis in order to correct or modify the boundary of the object.
I want to move the nearest boundary points in the same direction but decreasingly. I mean no point should move more than the main point. The nearest points move most and, the farthest points should move less.
On the image, the red dots represent the initial status of points. And the user pulls the P0 in the x-direction. And the other points follow it. The last status of the points is represented by violet dots.
Here is what I tried.
//On point moved event
//Get nearest boundary Points (Uses Geometry3D to get boundary points).
(var clothDMesh, _) = Utilities3D.BuildDMesh(baseMesh);
CreateClothModel(clothDMesh);
var boundryVertices = nodes.Where(ro => ro.Value.isBorder).Select(ro => ro.Value.vertex).ToList();
var refPoint = CustomPoint.FromPoint3D(movedPoint);
//Gets the delta X.
var deltaX = p.X - initialX;
//Gets nearest country points, so 15 points above and 15 points below to move only a given number of points (I know maybe this should be calculated according to delta).
var nearestPoints = refPoint.GetNearesPoints(boundryVertices, 30);
foreach (var item in nearestPoints)
{
//This is only one of what I tried as a function. None of them worked correctly.
item.X += deltaX - (deltaX * 1/ Math.Pow(item.Distance, 2));
}
Any help will be appreciated.
Thanks in advance.
Here's the math part:
I call "a" your "deltaX".
We also need a second parameter: "b", the maximum height of the red dots. I assume it is symetrical and "-b" would be the minimum height of the red dots.
So, if you look for the value X, horizontal move, in fonction of the coordinate Y of the dot:
X = a - a * Y * Y / (b * b);
You can verify that for Y = 0, you obtain X = a and for Y = b (or -b) you get X = 0.
You have your parabola (X is function of Y^2).

How to let the program know if a point is at the right or the left of a line?

I wanted to let my program know whether a point X is at the right or the left of a line that crosses A and B
I found that solution in this forum (How to tell whether a point is to the right or left side of a line) and it was really helpful, but once I changed the angle of the line it just stopped working and started to give me the result of a line that has 0° as heading
I work with Lines that rarely have 0°
I tried also to rotate the point I have using an equation but still giving me the same result
I'm trying to achieve the results I want in Unity Engine so I can visualize what I'm doing before actually jumping to the original program
float Ax = Stop.transform.position.x;
float Ay = Stop.transform.position.y;
float Bx = Ref.transform.position.x;
float By = Ref.transform.position.y;
float X = Wheel.transform.position.x;
float Y = Wheel.transform.position.y;
float x = X * Cos(Gate.transform.rotation.eulerAngles.y) - Y * Sin(Gate.transform.rotation.eulerAngles.y);
float y = Y * Cos(Gate.transform.rotation.eulerAngles.y) + X * Sin(Gate.transform.rotation.eulerAngles.y);
float position = System.Math.Sign((Bx - Ax) * (Y - Ay) - (By - Ay) * (X - Ax));
if (position > 0)
{
lg.Log("Left");
}
else
{
lg.Log("Right");
}
I expect the program to return right or left whatever the heading of the line is and whatever is the distance between A & B & X but it just gives me results of straight 0° heading line which is weird as the B point is not aligned with the Y axes :|
You are calculating orientation of Wheel position (large X/Y) relative to Stop-Ref line. Coordinates of rotated point (small x/y) are ignored.
You can first find out the equation of the line with:
float m = (By - Ay) / (Bx - Ax);
float n = (Ay * Bx + By * Ax) / (Bx - Ax);
The equation of the line is:
y = mx + n
This is simply implementing the line equation from Wikipedia.
Now you can easily find out if a point is above or below the line. Just insert your x coordinate into the line, then you get the y coordinate of the line at that point. Now compare that y value with your y coordinate and you know if it's above or below. Depending on what you define as the direction of the line, you'll now also be able to tell if that's left or right of the line.
An exact vertical line won't work though since its slope would be approaching infinity.
so I found a solution
first of all, it was my mistake from the beginning
so after analyzing all of your answers and others from other questions on this website
I finally got it
First, my mistake is that I was using the Y value of a point in a left-handed 3D space plan
wich uses Y as altitude and not as Longitude
so I switched to Z and I started to see some results
this justifies the fact that the results I always get are vertical based
I think all of your answers may work but I finally used one of mine
so here is my logic
float Ax = Stop.transform.position.x;
float Ay = Stop.transform.position.z;
float Bx = Ref.transform.position.x;
float By = Ref.transform.position.y;
float X = Wheel.transform.position.x;
float Y = Wheel.transform.position.z;
// set the point coordinates in a new virtual plan that has the A point as origin
float x = X - Ax;
float y = Y - Ay;
// set a new B point and ignore the first one
// it seems not logical at all but in my next program i won't be able to set a virtual point so it is needed
Bx = 0;
By = 5;
//let the program know that Apoint now is the origin
Ax = 0;
Ay = 0;
//get the line heading using euler angles
float angle = Gate.transform.rotation.eulerAngles.y;
//small log to check the values
lg.Log(angle.ToString());
//rotate the point coordinates arround the orgin (0 ; 0)
var rotatedX = Cos(angle) * (x - Ax) - Sin(angle) * (y - Ay) + Ax;
var rotatedY = Sin(angle) * (x - Ax) + Cos(angle) * (y - Ay) + Ay;
//check the X value instead of the Y value, again my misatake
if(rotatedX > 0)
{
// i created big boxed to view the left/right sign instead of logs just to not get confused :)
left.SetActive(true);
right.SetActive(false);
}
else
{
left.SetActive(false);
right.SetActive(true);
}
I'm using unity for tests cus it has a render engine that helps visualize the results before jumping to the actual program
thank you all for the help :)

Find nearest position to target position by a specific distance

I have two positions and want to calculate the position where the red star is. (I want to move B to the "red star location" but I don't know the coordinates.)
I have the position of A and B and a minimum distance from position A. So my question is how do I calculate the nearest position to B within the specified distance.
Hope someone understand what i'm trying to accomplish.
Assuming that:
You want B to be in the same direction from A as before
You want to move B to a specific distance from A
If B is farther away, move it closer to A to get to the distance
If B is closer than the specific distance, move it away from A to get to the distance
Then this is the way to do it:
Calculate the current distance from A to B
Calculate the difference in position between A and B (in 2 or 3 dimensions)
Divide this difference by a ratio that is "current distance / wanted distance"
For instance, if the current distance is 2x as far away from A as you want, you would divide the difference in position by 2
Set the new position of B to be A + the new differences
Here's some sample code:
var wantedDistance = 40.0;
var distance = Math.Sqrt((A.x - B.x)*(A.x - B.x) + (A.y - B.y)*(A.y - B.y));
var diffX = B.x - A.x;
var diffY = B.y - A.y;
var ratio = distance / wantedDistance;
var newDiffX = diffX / ratio;
var newDiffY = diffY / ratio;
var newB = new PointF(A.x + newDiffX, A.y + newDiffY);
In a comment you say that if B is inside the radius, then it is in range so it should not be moved. You would simply handle this by comparing distance with wantedDistance and if lower, then you're done. Simply add this line of code after the var distance = ... line:
if (distance < wantedDistance)
return B; // or whatever you want to do when "done"
If you need to do this in 3D space, simply augment every calculation and diff to handle the Z dimension as well.

algorithm for a random space bordered by elements of equal length

I am an architecture student trying to solve a spatial problem with C# in Grasshopper for Rhino.
The space I am trying to create is an exhibition space in an airport. The space will be made up of elements of similar length. The idea is to connect them with a hinge and thereby allow them to create spaces of different layout and size according to how many elements are used.
As you can see from the illustration I would like the space to end with an opening an element length away from the starting point.
My first attempt has been to create equilateral triangles depending on the number of segments (walls) needed.
In short, from the starting point, triangles are created, and then the sides of the triangle that form the outer border are added to a list of points. This point list is returned to the Grasshopper application, which draws lines between the points. A little point is that I made the creation of the next triangle randomly either from the side AC or BC from the last triangle.
Here is an example of the spaces created (for 12 - 8 - 14 - 20 elements):
Here is the source code that creates these point lists:
private void RunScript(double radius, int walls, ref object A)
{
//
List<Point3d> pointList = new List<Point3d>();
List<Point3d> lastList = new List<Point3d>();
bool alternate = true;
bool swapped = false;
Random turn = new Random();
// set up the first part of the triangle
Point3d point1 = new Point3d(0, 0, 0);
Point3d point2 = new Point3d(0, radius, 0);
pointList.Add(point1);
pointList.Add(point2);
Point3d calcPoint;
for(int i = 0; i < walls - 1; i++) // walls - 1, is because I need one less triangle to get to the amount of walls
{
// use the method to create two similar circles and return the intersection point
// in order to create an equilateral triangle
calcPoint = FindCircleIntersections(point1.X, point1.Y, point2.X, point2.Y, radius, alternate);
// random generator: will decide if the new triangle should be created from side BC or AC
bool rotate = turn.Next(2) != 0;
Print("\n" + rotate);
// set the 2nd and 3rd point as 1st and 2nd - depending on random generator.
if(rotate)
{
point1 = point2;
if(swapped == true)
swapped = false;
else
swapped = true;
}
// if the direction is swapped, the next point created will not be a part of the outer border
if(swapped)
lastList.Add(calcPoint);
else
pointList.Add(calcPoint);
point2 = calcPoint;
// swap direction of intersection
if(rotate)
{
if(alternate)
alternate = false;
else
alternate = true;
}
}
lastList.Reverse();
foreach (Point3d value in lastList)
{
pointList.Add(value);
}
A = pointList;
}
// Find the points where the two circles intersect.
private Point3d FindCircleIntersections(
double cx0, double cy0, double cx1, double cy1, double rad, bool alternate)
{
// Find the distance between the centers.
double dx = cx0 - cx1;
double dy = cy0 - cy1;
double dist = Math.Sqrt(dx * dx + dy * dy);
// Find a and h.
double a = (rad * rad - rad * rad + dist * dist) / (2 * dist);
double h = Math.Sqrt(rad * rad - a * a);
// Find P2.
double cx2 = cx0 + a * (cx1 - cx0) / dist;
double cy2 = cy0 + a * (cy1 - cy0) / dist;
// Get the points P3.
if(alternate)
return new Point3d((double) (cx2 + h * (cy1 - cy0) / dist), (double) (cy2 - h * (cx1 - cx0) / dist), 0);
else
return new Point3d((double) (cx2 - h * (cy1 - cy0) / dist), (double) (cy2 + h * (cx1 - cx0) / dist), 0);
}
What I would like to do, is to vary the creation of these shapes, so that they are not only corridors, but resemble my initial sketches. I would like an algorithm to take an input of segments (number and length) and then propose different space layouts which are possible to create with this number of segments. I guess because of tesselation the space would have to be created with triangles, squares or hexagons? Do you think I should look into this "maximum area" algorithm : Covering an arbitrary area with circles of equal radius here on stackoverflow?
I would greatly appreciate any help on this algorithm. Cheers, Eirik
If you're merely interested in a program to generate instances to be externally evaluated (and not all such instances), you could "inflate" your curve. For example, in the 14-segment instance in your second image, there is a place where the curve goes inward and doubles back -- so your list of points has one point repeated. For curves like this you could cut out everything between the two (identical) points (A and B), as well as one of the surrounding points (A or B), and you have reclaimed some points to expand your curve - possibly resulting in a non-corridor structure. You may have to work some magic to ensure it is a "closed" curve, though, buy alternately adding segments to the front and the back of the curve.
Another opportunity: if you can identify the curve's interior (and there are algorithms for this), then anywhere that two segments form a concave angle with respect to your curve, you could blow it out to make a non-corridorish area. E.g. the second and third segments of your 14-segment curve above could be blown out to the left.
Successively applying these two methods to your corridor-like curve should generate many of the shapes you're looking for. Good luck!

The algorithm to find the point of intersection of two 3D line segment

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));
}

Categories