/// <summary> /// Distance between this and another straight line. /// </summary> /// <param name="TestLine">The test line.</param> /// <param name="ptOnThis">The closest point on this to the other as a returned value.</param> /// <param name="ptOnOther">The closest point on the other to this as a returned value.</param> public double Distance(C2DLine TestLine, C2DPoint ptOnThis, C2DPoint ptOnOther) { C2DCircle Circle = new C2DCircle(GetCircleCentre(), Radius); double dCircDist = Circle.Distance(TestLine, ptOnThis, ptOnOther); double dDist = 0; if (TestLine.IsOnRight(ptOnThis) ^ ArcOnRight) { // The point found isn't on this. // This means the 2 closest points cannot be ON both lines, we must have a end point as one. ptOnThis.Set(Line.point); dDist = TestLine.Distance(ptOnThis, ptOnOther); C2DPoint ptThisTemp = new C2DPoint(Line.GetPointTo()); C2DPoint ptOtherTemp = new C2DPoint(); double d2 = TestLine.Distance(ptThisTemp, ptOtherTemp); if (d2 < dDist) { dDist = d2; ptOnThis.Set(ptThisTemp); ptOnOther.Set(ptOtherTemp); } // If the line was outside the circle then stop here as no need to go any further. // This is because the closest point on this must be one of the end points. if (dCircDist < 0) { double d3 = Distance(TestLine.point, ptThisTemp); if (d3 < dDist) { dDist = d3; ptOnThis.Set(ptThisTemp); ptOnOther.Set(Line.point); } double d4 = Distance(TestLine.GetPointTo(), ptThisTemp); if (d4 < dDist) { dDist = d4; ptOnThis.Set(ptThisTemp); ptOnOther.Set(Line.GetPointTo()); } } } else { dDist = Math.Abs(dCircDist); } // ptOnThis.Set(ptThis); // ptOnOther.Set(ptOther); return(dDist); }
/// <summary> /// Returns the distance from this to the other line. /// </summary> /// <param name="Other">The Other line.</param> /// <param name="ptOnThis">Output. The closest point on this.</param> /// <param name="ptOnOther">Output. The closest point on the other line.</param> public double Distance(C2DLine Other, C2DPoint ptOnThis , C2DPoint ptOnOther) { // First, project the other line onto this and if it falls entirely below it or // above it then 1. There is no intersection, 2. This is closest to one end on this line. C2DPoint ptOtherP2 = new C2DPoint(Other.GetPointTo()); C2DVector vThisP1OtherP1 = new C2DVector(point, Other.point); C2DVector vThisP1OtherP2 = new C2DVector(point, ptOtherP2); C2DPoint ptThisP2 = new C2DPoint(GetPointTo()); double dOtherP1Proj = vThisP1OtherP1.Dot(vector); double dOtherP2Proj = vThisP1OtherP2.Dot(vector); // If they are both less than 0 then the projection falls below the line. if (dOtherP1Proj <= 0 && dOtherP2Proj <= 0) { ptOnThis.Set(point); return Other.Distance(point, ptOnOther); } // Now modify the projection so it is the length along this line. double dThisLength = GetLength(); dOtherP1Proj = dOtherP1Proj / dThisLength; dOtherP2Proj = dOtherP2Proj / dThisLength; // If the projections are both above the line then the second point is closest if (dOtherP1Proj >= dThisLength && dOtherP2Proj >= dThisLength) { ptOnThis.Set(ptThisP2); return Other.Distance( ptThisP2, ptOnOther); } // This hasn't worked so try the same on the other line. C2DVector vOtherP1ThisP1 = new C2DVector (Other.point, point); C2DVector vOtherP1ThisP2 = new C2DVector(Other.point, ptThisP2); double dThisP1Proj = vOtherP1ThisP1.Dot(Other.vector); double dThisP2Proj = vOtherP1ThisP2.Dot(Other.vector); // If they are both less than 0 then the projection falls below the line. if (dThisP1Proj <= 0 && dThisP2Proj <= 0) { ptOnOther.Set( Other.point); return Distance(Other.point, ptOnThis); } // Now modify the projection so it is the length along this line. double dOtherLength = Other.GetLength(); dThisP1Proj = dThisP1Proj / dOtherLength; dThisP2Proj = dThisP2Proj / dOtherLength; // If the projections are both above the line then the second point is closest if (dThisP1Proj >= dOtherLength && dThisP2Proj >= dOtherLength) { ptOnOther.Set(ptOtherP2); return Distance( ptOtherP2, ptOnThis); } // Now test for an intersection. List<C2DPoint> IntPoint = new List<C2DPoint>(); bool B1 = true, B2 = true; if (this.Crosses(Other, IntPoint,ref B1, ref B2, false)) { ptOnOther.Set(IntPoint[0]); ptOnThis.Set(IntPoint[0]); return 0; } // Otherwise, there MUST be a point projection on one of the lines otherwise both // lines project on either side of each other which is impossible. // So find the distances to all these projections and take the minimum. double dDist = 0; double dMinDist = 0; bool bSet = false; C2DPoint ptOnThisTemp = new C2DPoint(); C2DPoint ptOnOtherTemp = new C2DPoint(); // Is the other lines first point projected on this? if (dOtherP1Proj >= 0 && dOtherP1Proj <= dThisLength) { // If so find the point on this line and get distance to it. double dFactor = dOtherP1Proj / dThisLength; ptOnThisTemp.Set(new C2DPoint(point.x + vector.i * dFactor, point.y + vector.j * dFactor) ); dMinDist = Other.point.Distance(ptOnThisTemp); bSet = true; ptOnOther.Set(Other.point); ptOnThis.Set(ptOnThisTemp); } // Is the other lines second point projected onto this? if (dOtherP2Proj >= 0 && dOtherP2Proj <= dThisLength) { // If so find the point on this and then the distance. Is it less? double dFactor = dOtherP2Proj / dThisLength; ptOnThisTemp.Set( new C2DPoint(point.x + vector.i * dFactor, point.y + vector.j * dFactor) ); dDist = ptOtherP2.Distance(ptOnThisTemp); if (!bSet || dDist < dMinDist) { ptOnOther.Set(ptOtherP2); ptOnThis.Set(ptOnThisTemp); dMinDist = dDist; bSet = true; } } // Is the first point on this projected onto the other line? if (dThisP1Proj >= 0 && dThisP1Proj <= dOtherLength) { // If so find the point and the distance. Is it less? double dFactor = dThisP1Proj / dOtherLength; ptOnOtherTemp.Set( new C2DPoint(Other.point.x + Other.vector.i * dFactor, Other.point.y + Other.vector.j * dFactor)); dDist = point.Distance(ptOnOtherTemp); if (!bSet || dDist < dMinDist) { ptOnThis.Set(point); ptOnOther.Set(ptOnOtherTemp); dMinDist = dDist; bSet = true; } } // Is the second point on this projected onto the other line? if (dThisP2Proj >= 0 && dThisP2Proj <= dOtherLength) { // If so find the point and the distance. Is it less? double dFactor = dThisP2Proj / dOtherLength; ptOnOtherTemp.Set( new C2DPoint(Other.point.x + Other.vector.i * dFactor, Other.point.y + Other.vector.j * dFactor)); dDist = ptThisP2.Distance(ptOnOtherTemp); if (!bSet || dDist < dMinDist) { ptOnThis.Set(ptThisP2); ptOnOther.Set(ptOnOtherTemp); dMinDist = dDist; bSet = true; } } Debug.Assert( bSet ); // Now return the minimum distance return dMinDist; }
/// <summary> /// Distance to a point. /// </summary> /// <param name="ptTest">The test point.</param> /// <param name="ptOnThis">Output. The closest point on the triangle.</param> public double Distance(C2DPoint ptTest, C2DPoint ptOnThis) { double dArea = GetAreaSigned(); bool BTemp = true; // Construct the lines. C2DLine Line12 = new C2DLine(P1, P2); C2DLine Line23 = new C2DLine(P2, P3); C2DLine Line31 = new C2DLine(P3, P1); if (dArea == 0) { // Colinear so find the biggest line and return the distance from that double d1 = Line12.GetLength(); double d2 = Line23.GetLength(); double d3 = Line31.GetLength(); if (d1 > d2 && d1 > d3) return Line12.Distance(ptTest, ptOnThis); else if (d2 > d3) return Line23.Distance(ptTest, ptOnThis); else return Line31.Distance(ptTest, ptOnThis); } // Find out it the triangle is clockwise or not. bool bClockwise = dArea < 0; // Set up some pointers to record the lines that the point is "above", "above" meaning that the // point is on the opposite side of the line to the rest of the triangle C2DLine LineAbove1 = null; C2DLine LineAbove2 = null; // Find out which Lines have the point above. if ( Line12.IsOnRight( ptTest ) ^ bClockwise ) // if the pt is on the opposite side to the triangle LineAbove1 = Line12; if ( Line23.IsOnRight( ptTest ) ^ bClockwise) { if (LineAbove1 != null) LineAbove2 = Line23; else LineAbove1 = Line23; } if ( Line31.IsOnRight( ptTest ) ^ bClockwise) { if (LineAbove1 != null) { // We can't have all the lines with the point above. Debug.Assert(LineAbove2 != null); LineAbove2 = Line31; } else LineAbove1 = Line31; } // Check for containment (if there isn't a single line that its above then it must be inside) if (LineAbove1 == null) { // Pt inside so project onto all the lines and find the closest projection (there must be one). // Set up a record of the point projection on the lines. C2DPoint ptOnLine = new C2DPoint(); bool bSet = false; double dMinDist = 0; if (ptTest.ProjectsOnLine(Line12, ptOnLine, ref BTemp)) { dMinDist = ptTest.Distance(ptOnLine); ptOnThis.Set(ptOnLine); bSet = true; } if (ptTest.ProjectsOnLine(Line23, ptOnLine, ref BTemp)) { double dDist = ptTest.Distance(ptOnLine); if (!bSet || dDist < dMinDist) { dMinDist = dDist; ptOnThis.Set(ptOnLine); bSet = true; } } if (ptTest.ProjectsOnLine(Line31, ptOnLine, ref BTemp)) { double dDist = ptTest.Distance(ptOnLine); if (!bSet || dDist < dMinDist) { dMinDist = dDist; ptOnThis.Set(ptOnLine); bSet = true; } } Debug.Assert(bSet); return -dMinDist; //-ve if inside } else if (LineAbove2 == null) { // it is only above 1 of the lines so simply return the distance to that line return LineAbove1.Distance(ptTest, ptOnThis); } else { // It's above 2 lines so first check them both for projection. Can only be projected on 1. // If the point can be projected onto the line then that's the closest point. C2DPoint ptOnLine = new C2DPoint(); if (ptTest.ProjectsOnLine(LineAbove1, ptOnLine, ref BTemp)) { ptOnThis = ptOnLine; return ptOnLine.Distance(ptTest); } else if (ptTest.ProjectsOnLine(LineAbove2, ptOnLine, ref BTemp)) { ptOnThis = ptOnLine; return ptOnLine.Distance(ptTest); } else { // The point doesn't project onto either line so find the closest point if (LineAbove1 == Line12) { if (LineAbove2 == Line23) { ptOnThis = P2; return ptTest.Distance(P2); } else { ptOnThis = P1; return ptTest.Distance(P1); } } else { ptOnThis = P3; return ptTest.Distance(P3); } } } }
/// <summary> /// Distance to a point. /// </summary> /// <param name="ptTest">The test point.</param> /// <param name="ptOnThis">Output. The closest point on the triangle.</param> public double Distance(C2DPoint ptTest, C2DPoint ptOnThis) { var dArea = GetAreaSigned(); var BTemp = true; // Construct the lines. var Line12 = new C2DLine(P1, P2); var Line23 = new C2DLine(P2, P3); var Line31 = new C2DLine(P3, P1); if (dArea == 0) { // Colinear so find the biggest line and return the distance from that var d1 = Line12.GetLength(); var d2 = Line23.GetLength(); var d3 = Line31.GetLength(); if (d1 > d2 && d1 > d3) { return(Line12.Distance(ptTest, ptOnThis)); } else if (d2 > d3) { return(Line23.Distance(ptTest, ptOnThis)); } else { return(Line31.Distance(ptTest, ptOnThis)); } } // Find out it the triangle is clockwise or not. var bClockwise = dArea < 0; // Set up some pointers to record the lines that the point is "above", "above" meaning that the // point is on the opposite side of the line to the rest of the triangle C2DLine LineAbove1 = null; C2DLine LineAbove2 = null; // Find out which Lines have the point above. if (Line12.IsOnRight(ptTest) ^ bClockwise) // if the pt is on the opposite side to the triangle { LineAbove1 = Line12; } if (Line23.IsOnRight(ptTest) ^ bClockwise) { if (LineAbove1 != null) { LineAbove2 = Line23; } else { LineAbove1 = Line23; } } if (Line31.IsOnRight(ptTest) ^ bClockwise) { if (LineAbove1 != null) { // We can't have all the lines with the point above. Debug.Assert(LineAbove2 != null); LineAbove2 = Line31; } else { LineAbove1 = Line31; } } // Check for containment (if there isn't a single line that its above then it must be inside) if (LineAbove1 == null) { // Pt inside so project onto all the lines and find the closest projection (there must be one). // Set up a record of the point projection on the lines. var ptOnLine = new C2DPoint(); var bSet = false; double dMinDist = 0; if (ptTest.ProjectsOnLine(Line12, ptOnLine, ref BTemp)) { dMinDist = ptTest.Distance(ptOnLine); ptOnThis.Set(ptOnLine); bSet = true; } if (ptTest.ProjectsOnLine(Line23, ptOnLine, ref BTemp)) { var dDist = ptTest.Distance(ptOnLine); if (!bSet || dDist < dMinDist) { dMinDist = dDist; ptOnThis.Set(ptOnLine); bSet = true; } } if (ptTest.ProjectsOnLine(Line31, ptOnLine, ref BTemp)) { var dDist = ptTest.Distance(ptOnLine); if (!bSet || dDist < dMinDist) { dMinDist = dDist; ptOnThis.Set(ptOnLine); bSet = true; } } Debug.Assert(bSet); return(-dMinDist); //-ve if inside } else if (LineAbove2 == null) { // it is only above 1 of the lines so simply return the distance to that line return(LineAbove1.Distance(ptTest, ptOnThis)); } else { // It's above 2 lines so first check them both for projection. Can only be projected on 1. // If the point can be projected onto the line then that's the closest point. var ptOnLine = new C2DPoint(); if (ptTest.ProjectsOnLine(LineAbove1, ptOnLine, ref BTemp)) { ptOnThis = ptOnLine; return(ptOnLine.Distance(ptTest)); } else if (ptTest.ProjectsOnLine(LineAbove2, ptOnLine, ref BTemp)) { ptOnThis = ptOnLine; return(ptOnLine.Distance(ptTest)); } else { // The point doesn't project onto either line so find the closest point if (LineAbove1 == Line12) { if (LineAbove2 == Line23) { ptOnThis = P2; return(ptTest.Distance(P2)); } else { ptOnThis = P1; return(ptTest.Distance(P1)); } } else { ptOnThis = P3; return(ptTest.Distance(P3)); } } } }
/// <summary> /// Returns the distance from this to the other line. /// </summary> /// <param name="Other">The Other line.</param> /// <param name="ptOnThis">Output. The closest point on this.</param> /// <param name="ptOnOther">Output. The closest point on the other line.</param> public double Distance(C2DLine Other, C2DPoint ptOnThis, C2DPoint ptOnOther) { // First, project the other line onto this and if it falls entirely below it or // above it then 1. There is no intersection, 2. This is closest to one end on this line. var ptOtherP2 = new C2DPoint(Other.GetPointTo()); var vThisP1OtherP1 = new C2DVector(point, Other.point); var vThisP1OtherP2 = new C2DVector(point, ptOtherP2); var ptThisP2 = new C2DPoint(GetPointTo()); var dOtherP1Proj = vThisP1OtherP1.Dot(vector); var dOtherP2Proj = vThisP1OtherP2.Dot(vector); // If they are both less than 0 then the projection falls below the line. if (dOtherP1Proj <= 0 && dOtherP2Proj <= 0) { ptOnThis.Set(point); return(Other.Distance(point, ptOnOther)); } // Now modify the projection so it is the length along this line. var dThisLength = GetLength(); dOtherP1Proj = dOtherP1Proj / dThisLength; dOtherP2Proj = dOtherP2Proj / dThisLength; // If the projections are both above the line then the second point is closest if (dOtherP1Proj >= dThisLength && dOtherP2Proj >= dThisLength) { ptOnThis.Set(ptThisP2); return(Other.Distance(ptThisP2, ptOnOther)); } // This hasn't worked so try the same on the other line. var vOtherP1ThisP1 = new C2DVector(Other.point, point); var vOtherP1ThisP2 = new C2DVector(Other.point, ptThisP2); var dThisP1Proj = vOtherP1ThisP1.Dot(Other.vector); var dThisP2Proj = vOtherP1ThisP2.Dot(Other.vector); // If they are both less than 0 then the projection falls below the line. if (dThisP1Proj <= 0 && dThisP2Proj <= 0) { ptOnOther.Set(Other.point); return(Distance(Other.point, ptOnThis)); } // Now modify the projection so it is the length along this line. var dOtherLength = Other.GetLength(); dThisP1Proj = dThisP1Proj / dOtherLength; dThisP2Proj = dThisP2Proj / dOtherLength; // If the projections are both above the line then the second point is closest if (dThisP1Proj >= dOtherLength && dThisP2Proj >= dOtherLength) { ptOnOther.Set(ptOtherP2); return(Distance(ptOtherP2, ptOnThis)); } // Now test for an intersection. var IntPoint = new List <C2DPoint>(); bool B1 = true, B2 = true; if (this.Crosses(Other, IntPoint, ref B1, ref B2, false)) { ptOnOther.Set(IntPoint[0]); ptOnThis.Set(IntPoint[0]); return(0); } // Otherwise, there MUST be a point projection on one of the lines otherwise both // lines project on either side of each other which is impossible. // So find the distances to all these projections and take the minimum. double dDist = 0; double dMinDist = 0; var bSet = false; var ptOnThisTemp = new C2DPoint(); var ptOnOtherTemp = new C2DPoint(); // Is the other lines first point projected on this? if (dOtherP1Proj >= 0 && dOtherP1Proj <= dThisLength) { // If so find the point on this line and get distance to it. var dFactor = dOtherP1Proj / dThisLength; ptOnThisTemp.Set(new C2DPoint(point.x + vector.i * dFactor, point.y + vector.j * dFactor)); dMinDist = Other.point.Distance(ptOnThisTemp); bSet = true; ptOnOther.Set(Other.point); ptOnThis.Set(ptOnThisTemp); } // Is the other lines second point projected onto this? if (dOtherP2Proj >= 0 && dOtherP2Proj <= dThisLength) { // If so find the point on this and then the distance. Is it less? var dFactor = dOtherP2Proj / dThisLength; ptOnThisTemp.Set(new C2DPoint(point.x + vector.i * dFactor, point.y + vector.j * dFactor)); dDist = ptOtherP2.Distance(ptOnThisTemp); if (!bSet || dDist < dMinDist) { ptOnOther.Set(ptOtherP2); ptOnThis.Set(ptOnThisTemp); dMinDist = dDist; bSet = true; } } // Is the first point on this projected onto the other line? if (dThisP1Proj >= 0 && dThisP1Proj <= dOtherLength) { // If so find the point and the distance. Is it less? var dFactor = dThisP1Proj / dOtherLength; ptOnOtherTemp.Set(new C2DPoint(Other.point.x + Other.vector.i * dFactor, Other.point.y + Other.vector.j * dFactor)); dDist = point.Distance(ptOnOtherTemp); if (!bSet || dDist < dMinDist) { ptOnThis.Set(point); ptOnOther.Set(ptOnOtherTemp); dMinDist = dDist; bSet = true; } } // Is the second point on this projected onto the other line? if (dThisP2Proj >= 0 && dThisP2Proj <= dOtherLength) { // If so find the point and the distance. Is it less? var dFactor = dThisP2Proj / dOtherLength; ptOnOtherTemp.Set(new C2DPoint(Other.point.x + Other.vector.i * dFactor, Other.point.y + Other.vector.j * dFactor)); dDist = ptThisP2.Distance(ptOnOtherTemp); if (!bSet || dDist < dMinDist) { ptOnThis.Set(ptThisP2); ptOnOther.Set(ptOnOtherTemp); dMinDist = dDist; bSet = true; } } Debug.Assert(bSet); // Now return the minimum distance return(dMinDist); }
/// <summary> /// Distance between this and another straight line. /// </summary> /// <param name="TestLine">The test line.</param> /// <param name="ptOnThis">The closest point on this to the other as a returned value.</param> /// <param name="ptOnOther">The closest point on the other to this as a returned value.</param> public double Distance(C2DLine TestLine, C2DPoint ptOnThis, C2DPoint ptOnOther) { C2DCircle Circle = new C2DCircle( GetCircleCentre(), Radius); double dCircDist = Circle.Distance(TestLine, ptOnThis, ptOnOther); double dDist = 0; if (TestLine.IsOnRight(ptOnThis) ^ ArcOnRight) { // The point found isn't on this. // This means the 2 closest points cannot be ON both lines, we must have a end point as one. ptOnThis.Set(Line.point); dDist = TestLine.Distance(ptOnThis, ptOnOther); C2DPoint ptThisTemp = new C2DPoint(Line.GetPointTo()); C2DPoint ptOtherTemp = new C2DPoint(); double d2 = TestLine.Distance(ptThisTemp, ptOtherTemp); if (d2 < dDist) { dDist = d2; ptOnThis.Set(ptThisTemp); ptOnOther.Set(ptOtherTemp); } // If the line was outside the circle then stop here as no need to go any further. // This is because the closest point on this must be one of the end points. if (dCircDist < 0) { double d3 = Distance(TestLine.point, ptThisTemp); if (d3 < dDist) { dDist = d3; ptOnThis.Set(ptThisTemp); ptOnOther.Set(Line.point); } double d4 = Distance(TestLine.GetPointTo(), ptThisTemp); if (d4 < dDist) { dDist = d4; ptOnThis.Set(ptThisTemp); ptOnOther.Set(Line.GetPointTo()); } } } else { dDist = Math.Abs(dCircDist); } // ptOnThis.Set(ptThis); // ptOnOther.Set(ptOther); return dDist; }