/// <summary> /// Distance between this and the test point. /// </summary> /// <param name="TestPoint">The test point.</param> /// <param name="ptOnThis">The closest point on this to the given point as a returned value.</param> public override double Distance(C2DPoint TestPoint, C2DPoint ptOnThis) { C2DPoint ptCen = new C2DPoint(GetCircleCentre()); C2DCircle Circle = new C2DCircle(ptCen, Radius); C2DPoint ptOnCircle = new C2DPoint(); double dCircleDist = Circle.Distance(TestPoint, ptOnCircle); if (ArcOnRight ^ Line.IsOnRight(ptOnCircle)) { // The closest point on the circle isn't on the curve double d1 = TestPoint.Distance(Line.point); double d2 = TestPoint.Distance(Line.GetPointTo()); if (d1 < d2) { ptOnThis.Set(Line.point); return(d1); } else { ptOnThis.Set(Line.GetPointTo()); return(d2); } } else { // The closest point on the circle IS on the curve ptOnThis.Set(ptOnCircle); return(Math.Abs(dCircleDist)); } }
/// <summary> /// Returns the distance from this to the point. /// </summary> /// <param name="TestPoint">The test pointt.</param> /// <param name="ptOnThis">Output. The closest point on this.</param> public override double Distance(C2DPoint TestPoint, C2DPoint ptOnThis) { var vP1ToPoint = new C2DVector(point, TestPoint); var dLength = GetLength(); var dProjLength = vP1ToPoint.Dot(vector); if (dProjLength < 0) { ptOnThis.Set(point); return(TestPoint.Distance(point)); } else { dProjLength = dProjLength / dLength; if (dProjLength < dLength) { // The projection is on the line var dFactorOnLine = dProjLength / dLength; var PtOnLine = new C2DPoint(point.x + vector.i * dFactorOnLine, point.y + vector.j * dFactorOnLine); ptOnThis.Set(PtOnLine); return(TestPoint.Distance(PtOnLine)); } else { ptOnThis.Set(GetPointTo()); return(TestPoint.Distance(GetPointTo())); } } }
/// <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> /// Distance from the polygon provided. /// </summary> /// <param name="Poly">Polygon to find the distance to.</param> /// <param name="ptOnThis">Closest point on this to recieve the result.</param> /// <param name="ptOnOther">Closest point on the other to recieve the result.</param> public double Distance(C2DPolyBase Poly, C2DPoint ptOnThis, C2DPoint ptOnOther) { var ptOnThisResult = new C2DPoint(); var ptOnOtherResult = new C2DPoint(); var dResult = _Rim.Distance(Poly, ptOnThis, ptOnOther); if (dResult == 0) { return(0); } ptOnThisResult.Set(ptOnThis); ptOnOtherResult.Set(ptOnOther); var bInside = dResult < 0; dResult = Math.Abs(dResult); for (var i = 0; i < _Holes.Count; i++) { var dDist = _Holes[i].Distance(Poly, ptOnThis, ptOnOther); if (dDist == 0) { return(0); } if (dDist < 0) { bInside = false; } if (Math.Abs(dDist) < dResult) { ptOnThisResult.Set(ptOnThis); ptOnOtherResult.Set(ptOnOther); dResult = Math.Abs(dDist); } } ptOnThis.Set(ptOnThisResult); ptOnOther.Set(ptOnOtherResult); if (bInside) { return(dResult); } else { return(-dResult); } }
/// <summary> /// Distance to a another. /// </summary> /// <param name="Other">The other triangle.</param> /// <param name="ptOnThis">Output. The closest point on the triangle.</param> /// <param name="ptOnOther">Output. The closest point on the other triangle.</param> public double Distance(C2DTriangle Other, C2DPoint ptOnThis, C2DPoint ptOnOther) { var ptTemp = new C2DPoint(); var dMinDist = Distance(Other.P1, ptOnThis); ptOnOther.Set(Other.P1); var dDist = Distance(Other.P2, ptTemp); if (dDist < dMinDist) { ptOnOther.Set(Other.P2); ptOnThis.Set(ptTemp); dMinDist = dDist; } dDist = Distance(Other.P3, ptTemp); if (dDist < dMinDist) { ptOnOther.Set(Other.P3); ptOnThis.Set(ptTemp); dMinDist = dDist; } dDist = Other.Distance(P1, ptTemp); if (dDist < dMinDist) { ptOnOther.Set(ptTemp); ptOnThis.Set(P1); dMinDist = dDist; } dDist = Other.Distance(P2, ptTemp); if (dDist < dMinDist) { ptOnOther.Set(ptTemp); ptOnThis.Set(P2); dMinDist = dDist; } dDist = Other.Distance(P3, ptTemp); if (dDist < dMinDist) { ptOnOther.Set(ptTemp); ptOnThis.Set(P3); dMinDist = dDist; } return(dMinDist); }
/// <summary> /// True if the point projects onto the line given and returns the point on the line. /// Also returns whether the line projects above or below the line if relevant. /// </summary> /// <param name="line">The line to project this on.</param> /// <param name="ptOnLine">The point to recieve the result.</param> /// <param name="bAbove">The flag to indicate whether it projects above or below.</param> public bool ProjectsOnLine(C2DLine line, C2DPoint ptOnLine, ref bool bAbove) { var vecthis = new C2DVector(x - line.point.x, y - line.point.y); var dProj = vecthis.Dot(line.vector); if (dProj < 0) { bAbove = false; return(false); } var dLength = line.vector.GetLength(); dProj /= dLength; if (dProj > dLength) { bAbove = true; return(false); } var dFactor = dProj / dLength; var vProj = new C2DVector(line.vector); vProj.Multiply(dFactor); ptOnLine.Set(line.point.x + vProj.i, line.point.y + vProj.j); return(true); }
/// <summary> /// True if the point projects onto the line given and returns the point on the line. /// Also returns whether the line projects above or below the line if relevant. /// </summary> /// <param name="Line">The line to project this on.</param> /// <param name="ptOnLine">The point to recieve the result.</param> /// <param name="bAbove">The flag to indicate whether it projects above or below.</param> public bool ProjectsOnLine(C2DLine Line, C2DPoint ptOnLine, ref bool bAbove) { C2DVector vecthis = new C2DVector(x - Line.point.x, y - Line.point.y); double dProj = vecthis.Dot(Line.vector); if (dProj < 0) { bAbove = false; return(false); } double dLength = Line.vector.GetLength(); dProj /= dLength; if (dProj > dLength) { bAbove = true; return(false); } double dFactor = dProj / dLength; C2DVector vProj = new C2DVector(Line.vector); vProj.Multiply(dFactor); ptOnLine.Set(Line.point.x + vProj.i, Line.point.y + vProj.j); return(true); }
/// <summary> /// Distance to a point, returns the closest point on the circle. /// </summary> /// <param name="TestPoint">Point to calculate the distance to.</param> /// <param name="ptOnThis">Closest point on the circle to recieve the result.</param> public double Distance(C2DPoint TestPoint, C2DPoint ptOnThis) { double dDist = _Centre.Distance(TestPoint); if (dDist == 0) { // point is the centre so just arbitrary point to the circle C2DVector V1 = new C2DVector(Radius, 0); ptOnThis.Set(_Centre.GetPointTo(V1)); } else { // find the point on the circle. C2DLine LineCenToPt = new C2DLine(_Centre, TestPoint); LineCenToPt.vector.SetLength(Radius); ptOnThis.Set(LineCenToPt.GetPointTo()); } return(dDist - Radius); // -ve indicates inside. }
/// <summary> /// Returns the distance from this to the point with this as a ray. /// </summary> /// <param name="TestPoint"></param> /// <param name="ptOnThis"></param> /// <returns></returns> public double DistanceAsRay(C2DPoint TestPoint, C2DPoint ptOnThis) { var vP1ToPoint = new C2DVector(point, TestPoint); // The projection is on the line var dFactorOnLine = vP1ToPoint.Dot(vector) / (vector.i * vector.i + vector.j * vector.j); ptOnThis.Set(point.x + vector.i * dFactorOnLine, point.y + vector.j * dFactorOnLine); return(TestPoint.Distance(ptOnThis)); }
/// <summary> /// True if this crosses the line and returns the intersectin points. /// </summary> /// <param name="Line">The line.</param> /// <param name="IntersectionPts">The point set to recieve the result.</param> public bool Crosses(C2DLine Line, List <C2DPoint> IntersectionPts) { double x1 = Line.point.x; double x2 = Line.point.x + Line.vector.i; double x3 = _Centre.x; double y1 = Line.point.y; double y2 = Line.point.y + Line.vector.j; double y3 = _Centre.y; double r = Radius; double a = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); double b = 2 * ((x2 - x1) * (x1 - x3) + (y2 - y1) * (y1 - y3)); double c = x3 * x3 + y3 * y3 + x1 * x1 + y1 * y1 - 2 * (x3 * x1 + y3 * y1) - r * r; double u = -b / (2 * a); C2DPoint ptClosestToCen = new C2DPoint(); if (u < 0) { ptClosestToCen.Set(Line.point); } else if (u > 1) { ptClosestToCen.Set(Line.GetPointTo()); } else { C2DVector V1 = new C2DVector(Line.vector); V1.Multiply(u); ptClosestToCen = Line.point.GetPointTo(V1); } double dDist = ptClosestToCen.Distance(_Centre); if (dDist > Radius) { return(false); } else { // Calculate the points. double d1 = b * b - 4 * a * c; Debug.Assert(d1 >= 0); if (d1 < 0) { return(false); } else if (d1 == 0) { double p1 = -b / (2 * a); IntersectionPts.Add(Line.GetPointOn(p1)); return(true); } else { d1 = Math.Sqrt(d1); double p1 = (-b + d1) / (2 * a); double p2 = (-b - d1) / (2 * a); bool bResult = false; if (p2 >= 0 && p2 <= 1) { bResult = true; IntersectionPts.Add(Line.GetPointOn(p2)); } if (p1 >= 0 && p1 <= 1) { bResult = true; IntersectionPts.Add(Line.GetPointOn(p1)); } return(bResult); } } }
/// <summary> /// True if the point projects onto the line given and returns the point on the line. /// Also returns whether the line projects above or below the line if relevant. /// </summary> /// <param name="Line">The line to project this on.</param> /// <param name="ptOnLine">The point to recieve the result.</param> /// <param name="bAbove">The flag to indicate whether it projects above or below.</param> public bool ProjectsOnLine(C2DLine Line, C2DPoint ptOnLine , ref bool bAbove) { C2DVector vecthis = new C2DVector(x - Line.point.x, y - Line.point.y); double dProj = vecthis.Dot(Line.vector); if (dProj < 0) { bAbove = false; return false; } double dLength = Line.vector.GetLength(); dProj /= dLength; if (dProj > dLength) { bAbove = true; return false; } double dFactor = dProj / dLength; C2DVector vProj = new C2DVector(Line.vector); vProj.Multiply(dFactor); ptOnLine.Set(Line.point.x + vProj.i, Line.point.y + vProj.j); return true; }
/// <summary> /// Distance from the polygon provided. /// </summary> /// <param name="Poly">Polygon to find the distance to.</param> /// <param name="ptOnThis">Closest point on this to recieve the result.</param> /// <param name="ptOnOther">Closest point on the other to recieve the result.</param> public double Distance(C2DPolyBase Poly, C2DPoint ptOnThis, C2DPoint ptOnOther) { C2DPoint ptOnThisResult = new C2DPoint(); C2DPoint ptOnOtherResult = new C2DPoint(); double dResult = _Rim.Distance(Poly, ptOnThis, ptOnOther); if (dResult == 0) return 0; ptOnThisResult.Set(ptOnThis); ptOnOtherResult.Set(ptOnOther); bool bInside = dResult < 0; dResult = Math.Abs(dResult); for (int i = 0; i < _Holes.Count; i++) { double dDist = _Holes[i].Distance(Poly, ptOnThis, ptOnOther); if (dDist == 0) return 0; if (dDist < 0) bInside = false; if (Math.Abs(dDist) < dResult) { ptOnThisResult.Set(ptOnThis); ptOnOtherResult.Set(ptOnOther); dResult = Math.Abs(dDist); } } ptOnThis.Set(ptOnThisResult); ptOnOther.Set(ptOnOtherResult); if (bInside) return dResult; else return - dResult; }
/// <summary> /// Distance of the poly from the shape. /// </summary> /// <param name="Other">The other polygon test.</param> /// <param name="ptOnThis">Output. The closest point on this.</param> /// <param name="ptOnOther">The closest point on the other.</param> public double Distance(C2DPolyBase Other, C2DPoint ptOnThis, C2DPoint ptOnOther) { if (Lines.Count == 0) return 0; if (Other.Lines.Count == 0) return 0; if (Other.LineRects.Count != Other.Lines.Count) return 0; if (Lines.Count != LineRects.Count) return 0; // First we find the closest line rect to the other's bounding rectangle. int usThisClosestLineGuess = 0; C2DRect OtherBoundingRect = Other.BoundingRect; double dClosestDist = LineRects[0].Distance(OtherBoundingRect); for (int i = 1; i < LineRects.Count; i++) { double dDist = LineRects[i].Distance(OtherBoundingRect); if (dDist < dClosestDist) { dClosestDist = dDist; usThisClosestLineGuess = i; } } // Now cycle through all the other poly's line rects to find the closest to the // guessed at closest line on this. int usOtherClosestLineGuess = 0; dClosestDist = Other.LineRects[0].Distance(LineRects[usThisClosestLineGuess]); for (int j = 1; j < Other.LineRects.Count; j++) { double dDist = Other.LineRects[j].Distance(LineRects[usThisClosestLineGuess]); if (dDist < dClosestDist) { dClosestDist = dDist; usOtherClosestLineGuess = j; } } // Now we have a guess at the 2 closest lines. double dMinDistGuess = Lines[usThisClosestLineGuess].Distance( Other.Lines[usOtherClosestLineGuess], ptOnThis, ptOnOther); // If its 0 then return 0. if (dMinDistGuess == 0) return 0; C2DPoint ptOnThisTemp = new C2DPoint(); C2DPoint ptOnOtherTemp = new C2DPoint(); // Now go through all of our line rects and only check further if they are closer // to the other's bounding rect than the min guess. for (int i = 0; i < Lines.Count; i++) { if (LineRects[i].Distance( OtherBoundingRect ) < dMinDistGuess) { for ( int j = 0 ; j < Other.Lines.Count ; j++) { double dDist = Lines[i].Distance(Other.Lines[j], ptOnThisTemp, ptOnOtherTemp); if (dDist < dMinDistGuess) { ptOnThis.Set(ptOnThisTemp); ptOnOther.Set(ptOnOtherTemp); if (dDist == 0) return 0; dMinDistGuess = dDist; } } } } // if we are here, there is no intersection but the other could be inside this or vice-versa if ( BoundingRect.Contains(Other.BoundingRect) && Contains(ptOnOtherTemp) ) { dMinDistGuess *= -1.0; } else if ( Other.BoundingRect.Contains(BoundingRect) && Other.Contains( ptOnThisTemp )) { dMinDistGuess *= -1.0; } return dMinDistGuess; }
/// <summary> /// The distance between this and another arc. /// </summary> /// <param name="Other">The test point.</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(C2DArc Other, C2DPoint ptOnThis, C2DPoint ptOnOther) { List<C2DPoint> IntPts1 = new List<C2DPoint>(); List<C2DPoint> IntPts2 = new List<C2DPoint>(); C2DPoint ptThisCen = new C2DPoint( GetCircleCentre() ); C2DPoint ptOtherCen = new C2DPoint(Other.GetCircleCentre()); C2DCircle CircleThis = new C2DCircle( ptThisCen, Radius); C2DCircle CircleOther = new C2DCircle( ptOtherCen, Other.Radius ); if (CircleThis.Crosses( CircleOther , IntPts1 ) ) { for (int i = 0; i < IntPts1.Count; i++) { if ( (Line.IsOnRight( IntPts1[i] ) == ArcOnRight ) && (Other.Line.IsOnRight( IntPts1[i] ) == Other.ArcOnRight ) ) { ptOnThis.Set(IntPts1[i]); ptOnOther.Set(IntPts1[i]); return 0; } } IntPts1.Clear(); } C2DLine LineCenToOther = new C2DLine(); LineCenToOther.point = new C2DPoint(ptThisCen); LineCenToOther.vector = new C2DVector(ptThisCen, ptOtherCen); LineCenToOther.GrowFromCentre( Math.Max(Radius, Other.Radius) * 10); double dMinDist = 1.7E308; double dDist = 0; if ( Crosses(LineCenToOther, IntPts1) && Other.Crosses(LineCenToOther, IntPts2)) { for (int i = 0 ; i < IntPts1.Count; i++) { for (int j = 0 ; j < IntPts2.Count; j++) { dDist = IntPts1[i].Distance(IntPts2[j]); if (dDist < dMinDist) { ptOnThis.Set( IntPts1[i]); ptOnOther.Set( IntPts2[j]); dMinDist = dDist; } } } } C2DPoint ptOnThisTemp = new C2DPoint(); dDist = Distance(Other.GetPointFrom(), ptOnThisTemp); if (dDist < dMinDist) { ptOnThis.Set(ptOnThisTemp); ptOnOther.Set(Other.GetPointFrom()); dMinDist = dDist; } dDist = Distance(Other.GetPointTo(), ptOnThisTemp); if (dDist < dMinDist) { ptOnThis.Set(ptOnThisTemp); ptOnOther.Set(Other.GetPointTo()); dMinDist = dDist; } C2DPoint ptOnOtherTemp = new C2DPoint(); dDist = Other.Distance(GetPointFrom(), ptOnOtherTemp); if (dDist < dMinDist) { ptOnThis.Set( GetPointFrom()); ptOnOther.Set( ptOnOtherTemp); dMinDist = dDist; } dDist = Other.Distance(GetPointTo(), ptOnOtherTemp); if (dDist < dMinDist) { ptOnThis.Set( GetPointTo()); ptOnOther.Set( ptOnOtherTemp); dMinDist = dDist; } return dMinDist; }
/// <summary> /// Distance to a line, returns the closest point on the circle and the line. /// </summary> /// <param name="Line">Line to calculate the distance to.</param> /// <param name="ptOnThis">Closest point on the circle to recieve the result.</param> /// <param name="ptOnOther">Closest point on the line to recieve the result.</param> public double Distance(C2DLine Line, C2DPoint ptOnThis, C2DPoint ptOnOther) { CInterval ProjInt = new CInterval(); Project(Line, ProjInt); if (ProjInt.dMax < 0) { // This means that the circle projects entirely "below" the line so the nearest point // To this is the first point on the line and there are no interections. ptOnOther.Set(Line.point); return Distance(Line.point, ptOnThis); } double dLength = Line.GetLength(); if (ProjInt.dMin > dLength) { // This means that the circle projects entirely "above" the line so the nearest point // To this is the second point on the line and there are no interections. C2DPoint ptClosest = new C2DPoint(Line.GetPointTo()); ptOnOther.Set( ptClosest ); return Distance(ptClosest, ptOnThis); } // Now find out if there's an intersection. List<C2DPoint> IntPts = new List<C2DPoint>(); if (Crosses(Line, IntPts)) { ptOnThis.Set( IntPts[0]); ptOnOther.Set( IntPts[0]); return 0; } // Now find out if the line is entirely inside if (ProjInt.dMin > 0 && ProjInt.dMax < dLength && this.Contains(Line.point)) { double d1 = Distance(Line.point, ptOnThis); C2DPoint ptThisTemp = new C2DPoint(); double d2 = Distance(Line.GetPointTo(), ptThisTemp); Debug.Assert(d1 < 0 && d2 < 0); if (d2 > d1) // NOTE USE OF > AS d2 and d1 are -ve. { ptOnThis.Set(ptThisTemp); ptOnOther.Set(Line.GetPointTo()); return d2; } else { ptOnOther.Set(Line.point); return d1; } } // We now know the line is entirely outside. // Now find out if this is closest to a point on the line. double dCenOnLine = (ProjInt.dMax + ProjInt.dMin) / 2.0; if (dCenOnLine > 0) { if (dCenOnLine < dLength) { // The centre is projected on the line double dFactor = dCenOnLine / dLength; C2DVector vProj = new C2DVector(Line.vector); vProj.Multiply( dFactor); C2DPoint ptOnLine = new C2DPoint( Line.point.GetPointTo(vProj)); ptOnOther.Set( ptOnLine ); return Distance(ptOnLine, ptOnThis); } else { // The centre is projected above the line. C2DPoint ptClosest = new C2DPoint (Line.GetPointTo()); ptOnOther.Set(ptClosest); return Distance(ptClosest, ptOnThis); } } else { // This means that the circle projects entirely "below" the line. ptOnOther.Set( Line.point); return Distance(Line.point, ptOnThis); } }
/// <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> /// 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> /// True if this crosses the line and returns the intersectin points. /// </summary> /// <param name="Line">The line.</param> /// <param name="IntersectionPts">The point set to recieve the result.</param> public bool Crosses(C2DLine Line, List<C2DPoint> IntersectionPts) { double x1 = Line.point.x; double x2 = Line.point.x + Line.vector.i; double x3 = _Centre.x; double y1 = Line.point.y; double y2 = Line.point.y + Line.vector.j; double y3 = _Centre.y; double r = Radius; double a = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); double b = 2 * ((x2 - x1) * (x1 - x3) + (y2 - y1) * (y1 - y3)); double c = x3 * x3 + y3 * y3 + x1 * x1 + y1 * y1 - 2 * (x3 * x1 + y3 * y1) - r * r; double u = -b / (2 * a); C2DPoint ptClosestToCen = new C2DPoint(); if (u < 0) { ptClosestToCen.Set( Line.point ); } else if (u > 1) { ptClosestToCen.Set( Line.GetPointTo()); } else { C2DVector V1 = new C2DVector(Line.vector); V1.Multiply(u); ptClosestToCen = Line.point.GetPointTo(V1); } double dDist = ptClosestToCen.Distance(_Centre); if (dDist > Radius) { return false; } else { // Calculate the points. double d1 = b * b - 4 * a * c; Debug.Assert(d1 >= 0); if (d1 < 0) return false; else if (d1 == 0) { double p1 = -b / (2 * a); IntersectionPts.Add(Line.GetPointOn(p1)); return true; } else { d1 = Math.Sqrt(d1); double p1 = (-b + d1) / (2 * a); double p2 = (-b - d1) / (2 * a); bool bResult = false; if (p2 >= 0 && p2 <= 1) { bResult = true; IntersectionPts.Add(Line.GetPointOn(p2)); } if (p1 >= 0 && p1 <= 1) { bResult = true; IntersectionPts.Add(Line.GetPointOn(p1)); } return bResult; } } }
/// <summary> /// Distance to a circle, returns the closest point on both circles. /// </summary> /// <param name="Other">Circle to calculate the distance to.</param> /// <param name="ptOnThis">Closest point on this circle to recieve the result.</param> /// <param name="ptOnOther">Closest point on the other circle to recieve the result.</param> public double Distance(C2DCircle Other, C2DPoint ptOnThis, C2DPoint ptOnOther) { double dCenCenDist = _Centre.Distance(Other.Centre); double dOtherRadius = Other.Radius; // C2DPoint ptThis; // C2DPoint ptOther; double dDist = dCenCenDist - Radius - dOtherRadius; if (dDist > 0 ) { // they do not interect and they are outside each other. C2DLine Line = new C2DLine(_Centre, Other.Centre); Line.vector.SetLength( Radius); ptOnThis.Set( Line.GetPointTo() ); Line.vector.Reverse(); Line.SetPointFrom(Other.Centre); Line.vector.SetLength(Other.Radius); ptOnOther.Set(Line.GetPointTo()); } else { if ( (dCenCenDist + Radius) < dOtherRadius) { // This is inside the other dDist = dCenCenDist + Radius - dOtherRadius ; // -ve if inside C2DVector vec = new C2DVector( Other.Centre, Centre); vec.Multiply( Radius /dCenCenDist ); // set the vector to be the length of my radius. ptOnThis.Set( _Centre.GetPointTo( vec)); vec.Multiply( dDist /Radius ); // set the vector to be the distance. ptOnOther.Set(ptOnThis.GetPointTo( vec)); } else if ( (dCenCenDist + dOtherRadius) < Radius) { // The other is inside this. dDist = dCenCenDist + dOtherRadius - Radius; // -ve if inside C2DVector vec = new C2DVector( _Centre, Other.Centre); vec.Multiply ( dOtherRadius /dCenCenDist ); // set the vector to be the length of my radius. ptOnOther.Set( Other.Centre.GetPointTo( vec)); vec.Multiply( dDist / dOtherRadius ); // set the vector to be the distance. ptOnThis.Set(ptOnOther.GetPointTo( vec)); } else { // there is an intersection dDist = 0; List<C2DPoint> Ints = new List<C2DPoint>(); if (Crosses(Other, Ints)) { ptOnThis.Set(Ints[0]); ptOnOther.Set(ptOnThis); } else { Debug.Assert(false); return 0; } } } // if (ptOnThis) // *ptOnThis = ptThis; // if (ptOnOther) // *ptOnOther = ptOther; return dDist; }
/// <summary> /// Distance to a line, returns the closest point on the circle and the line. /// </summary> /// <param name="Line">Line to calculate the distance to.</param> /// <param name="ptOnThis">Closest point on the circle to recieve the result.</param> /// <param name="ptOnOther">Closest point on the line to recieve the result.</param> public double Distance(C2DLine Line, C2DPoint ptOnThis, C2DPoint ptOnOther) { CInterval ProjInt = new CInterval(); Project(Line, ProjInt); if (ProjInt.dMax < 0) { // This means that the circle projects entirely "below" the line so the nearest point // To this is the first point on the line and there are no interections. ptOnOther.Set(Line.point); return(Distance(Line.point, ptOnThis)); } double dLength = Line.GetLength(); if (ProjInt.dMin > dLength) { // This means that the circle projects entirely "above" the line so the nearest point // To this is the second point on the line and there are no interections. C2DPoint ptClosest = new C2DPoint(Line.GetPointTo()); ptOnOther.Set(ptClosest); return(Distance(ptClosest, ptOnThis)); } // Now find out if there's an intersection. List <C2DPoint> IntPts = new List <C2DPoint>(); if (Crosses(Line, IntPts)) { ptOnThis.Set(IntPts[0]); ptOnOther.Set(IntPts[0]); return(0); } // Now find out if the line is entirely inside if (ProjInt.dMin > 0 && ProjInt.dMax < dLength && this.Contains(Line.point)) { double d1 = Distance(Line.point, ptOnThis); C2DPoint ptThisTemp = new C2DPoint(); double d2 = Distance(Line.GetPointTo(), ptThisTemp); Debug.Assert(d1 < 0 && d2 < 0); if (d2 > d1) // NOTE USE OF > AS d2 and d1 are -ve. { ptOnThis.Set(ptThisTemp); ptOnOther.Set(Line.GetPointTo()); return(d2); } else { ptOnOther.Set(Line.point); return(d1); } } // We now know the line is entirely outside. // Now find out if this is closest to a point on the line. double dCenOnLine = (ProjInt.dMax + ProjInt.dMin) / 2.0; if (dCenOnLine > 0) { if (dCenOnLine < dLength) { // The centre is projected on the line double dFactor = dCenOnLine / dLength; C2DVector vProj = new C2DVector(Line.vector); vProj.Multiply(dFactor); C2DPoint ptOnLine = new C2DPoint(Line.point.GetPointTo(vProj)); ptOnOther.Set(ptOnLine); return(Distance(ptOnLine, ptOnThis)); } else { // The centre is projected above the line. C2DPoint ptClosest = new C2DPoint(Line.GetPointTo()); ptOnOther.Set(ptClosest); return(Distance(ptClosest, ptOnThis)); } } else { // This means that the circle projects entirely "below" the line. ptOnOther.Set(Line.point); return(Distance(Line.point, ptOnThis)); } }
/// <summary> /// Returns the distance from this to the point. /// </summary> /// <param name="TestPoint">The test pointt.</param> /// <param name="ptOnThis">Output. The closest point on this.</param> public override double Distance(C2DPoint TestPoint, C2DPoint ptOnThis) { C2DVector vP1ToPoint = new C2DVector(point, TestPoint); double dLength = GetLength(); double dProjLength = vP1ToPoint.Dot(vector); if (dProjLength < 0) { ptOnThis.Set(point); return TestPoint.Distance(point); } else { dProjLength = dProjLength / dLength; if (dProjLength < dLength) { // The projection is on the line double dFactorOnLine = dProjLength / dLength; C2DPoint PtOnLine = new C2DPoint(point.x + vector.i * dFactorOnLine, point.y + vector.j * dFactorOnLine); ptOnThis.Set(PtOnLine); return TestPoint.Distance(PtOnLine); } else { ptOnThis .Set(GetPointTo()); return TestPoint.Distance( GetPointTo() ); } } }
/// <summary> /// Distance to a circle, returns the closest point on both circles. /// </summary> /// <param name="Other">Circle to calculate the distance to.</param> /// <param name="ptOnThis">Closest point on this circle to recieve the result.</param> /// <param name="ptOnOther">Closest point on the other circle to recieve the result.</param> public double Distance(C2DCircle Other, C2DPoint ptOnThis, C2DPoint ptOnOther) { double dCenCenDist = _Centre.Distance(Other.Centre); double dOtherRadius = Other.Radius; // C2DPoint ptThis; // C2DPoint ptOther; double dDist = dCenCenDist - Radius - dOtherRadius; if (dDist > 0) { // they do not interect and they are outside each other. C2DLine Line = new C2DLine(_Centre, Other.Centre); Line.vector.SetLength(Radius); ptOnThis.Set(Line.GetPointTo()); Line.vector.Reverse(); Line.SetPointFrom(Other.Centre); Line.vector.SetLength(Other.Radius); ptOnOther.Set(Line.GetPointTo()); } else { if ((dCenCenDist + Radius) < dOtherRadius) { // This is inside the other dDist = dCenCenDist + Radius - dOtherRadius; // -ve if inside C2DVector vec = new C2DVector(Other.Centre, Centre); vec.Multiply(Radius / dCenCenDist); // set the vector to be the length of my radius. ptOnThis.Set(_Centre.GetPointTo(vec)); vec.Multiply(dDist / Radius); // set the vector to be the distance. ptOnOther.Set(ptOnThis.GetPointTo(vec)); } else if ((dCenCenDist + dOtherRadius) < Radius) { // The other is inside this. dDist = dCenCenDist + dOtherRadius - Radius; // -ve if inside C2DVector vec = new C2DVector(_Centre, Other.Centre); vec.Multiply(dOtherRadius / dCenCenDist); // set the vector to be the length of my radius. ptOnOther.Set(Other.Centre.GetPointTo(vec)); vec.Multiply(dDist / dOtherRadius); // set the vector to be the distance. ptOnThis.Set(ptOnOther.GetPointTo(vec)); } else { // there is an intersection dDist = 0; List <C2DPoint> Ints = new List <C2DPoint>(); if (Crosses(Other, Ints)) { ptOnThis.Set(Ints[0]); ptOnOther.Set(ptOnThis); } else { Debug.Assert(false); return(0); } } } // if (ptOnThis) // *ptOnThis = ptThis; // if (ptOnOther) // *ptOnOther = ptOther; return(dDist); }
/// <summary> /// Distance to a point, returns the closest point on the circle. /// </summary> /// <param name="TestPoint">Point to calculate the distance to.</param> /// <param name="ptOnThis">Closest point on the circle to recieve the result.</param> public double Distance(C2DPoint TestPoint, C2DPoint ptOnThis) { double dDist = _Centre.Distance(TestPoint); if (dDist == 0) { // point is the centre so just arbitrary point to the circle C2DVector V1 = new C2DVector( Radius, 0); ptOnThis.Set( _Centre.GetPointTo(V1)); } else { // find the point on the circle. C2DLine LineCenToPt = new C2DLine (_Centre, TestPoint); LineCenToPt.vector.SetLength(Radius); ptOnThis.Set(LineCenToPt.GetPointTo()); } return (dDist - Radius); // -ve indicates inside. }
/// <summary> /// Distance to a another. /// </summary> /// <param name="Other">The other triangle.</param> /// <param name="ptOnThis">Output. The closest point on the triangle.</param> /// <param name="ptOnOther">Output. The closest point on the other triangle.</param> public double Distance(C2DTriangle Other, C2DPoint ptOnThis, C2DPoint ptOnOther) { C2DPoint ptTemp = new C2DPoint(); double dMinDist = Distance(Other.P1, ptOnThis); ptOnOther.Set( Other.P1 ); double dDist = Distance(Other.P2, ptTemp); if (dDist < dMinDist) { ptOnOther.Set(Other.P2); ptOnThis.Set(ptTemp); dMinDist = dDist; } dDist = Distance(Other.P3, ptTemp); if (dDist < dMinDist) { ptOnOther.Set( Other.P3); ptOnThis.Set(ptTemp); dMinDist = dDist; } dDist = Other.Distance(P1, ptTemp); if (dDist < dMinDist) { ptOnOther.Set(ptTemp); ptOnThis.Set(P1); dMinDist = dDist; } dDist = Other.Distance(P2, ptTemp); if (dDist < dMinDist) { ptOnOther.Set(ptTemp); ptOnThis.Set(P2); dMinDist = dDist; } dDist = Other.Distance(P3, ptTemp); if (dDist < dMinDist) { ptOnOther.Set(ptTemp); ptOnThis.Set(P3); dMinDist = dDist; } return dMinDist; }
/// <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> /// The distance between this and another arc. /// </summary> /// <param name="Other">The test point.</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(C2DArc Other, C2DPoint ptOnThis, C2DPoint ptOnOther) { List <C2DPoint> IntPts1 = new List <C2DPoint>(); List <C2DPoint> IntPts2 = new List <C2DPoint>(); C2DPoint ptThisCen = new C2DPoint(GetCircleCentre()); C2DPoint ptOtherCen = new C2DPoint(Other.GetCircleCentre()); C2DCircle CircleThis = new C2DCircle(ptThisCen, Radius); C2DCircle CircleOther = new C2DCircle(ptOtherCen, Other.Radius); if (CircleThis.Crosses(CircleOther, IntPts1)) { for (int i = 0; i < IntPts1.Count; i++) { if ((Line.IsOnRight(IntPts1[i]) == ArcOnRight) && (Other.Line.IsOnRight(IntPts1[i]) == Other.ArcOnRight)) { ptOnThis.Set(IntPts1[i]); ptOnOther.Set(IntPts1[i]); return(0); } } IntPts1.Clear(); } C2DLine LineCenToOther = new C2DLine(); LineCenToOther.point = new C2DPoint(ptThisCen); LineCenToOther.vector = new C2DVector(ptThisCen, ptOtherCen); LineCenToOther.GrowFromCentre(Math.Max(Radius, Other.Radius) * 10); double dMinDist = 1.7E308; double dDist = 0; if (Crosses(LineCenToOther, IntPts1) && Other.Crosses(LineCenToOther, IntPts2)) { for (int i = 0; i < IntPts1.Count; i++) { for (int j = 0; j < IntPts2.Count; j++) { dDist = IntPts1[i].Distance(IntPts2[j]); if (dDist < dMinDist) { ptOnThis.Set(IntPts1[i]); ptOnOther.Set(IntPts2[j]); dMinDist = dDist; } } } } C2DPoint ptOnThisTemp = new C2DPoint(); dDist = Distance(Other.GetPointFrom(), ptOnThisTemp); if (dDist < dMinDist) { ptOnThis.Set(ptOnThisTemp); ptOnOther.Set(Other.GetPointFrom()); dMinDist = dDist; } dDist = Distance(Other.GetPointTo(), ptOnThisTemp); if (dDist < dMinDist) { ptOnThis.Set(ptOnThisTemp); ptOnOther.Set(Other.GetPointTo()); dMinDist = dDist; } C2DPoint ptOnOtherTemp = new C2DPoint(); dDist = Other.Distance(GetPointFrom(), ptOnOtherTemp); if (dDist < dMinDist) { ptOnThis.Set(GetPointFrom()); ptOnOther.Set(ptOnOtherTemp); dMinDist = dDist; } dDist = Other.Distance(GetPointTo(), ptOnOtherTemp); if (dDist < dMinDist) { ptOnThis.Set(GetPointTo()); ptOnOther.Set(ptOnOtherTemp); dMinDist = dDist; } 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) { 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 point with this as a ray. /// </summary> /// <param name="TestPoint"></param> /// <param name="ptOnThis"></param> /// <returns></returns> public double DistanceAsRay(C2DPoint TestPoint, C2DPoint ptOnThis) { C2DVector vP1ToPoint = new C2DVector(point, TestPoint); // The projection is on the line double dFactorOnLine = vP1ToPoint.Dot(vector) / (vector.i * vector.i + vector.j * vector.j); ptOnThis.Set(point.x + vector.i * dFactorOnLine, point.y + vector.j * dFactorOnLine); return TestPoint.Distance(ptOnThis); }
/// <summary> /// Distance of the poly from the shape. /// </summary> /// <param name="Other">The other polygon test.</param> /// <param name="ptOnThis">Output. The closest point on this.</param> /// <param name="ptOnOther">The closest point on the other.</param> public double Distance(C2DPolyBase Other, C2DPoint ptOnThis, C2DPoint ptOnOther) { if (Lines.Count == 0) { return(0); } if (Other.Lines.Count == 0) { return(0); } if (Other.LineRects.Count != Other.Lines.Count) { return(0); } if (Lines.Count != LineRects.Count) { return(0); } // First we find the closest line rect to the other's bounding rectangle. var usThisClosestLineGuess = 0; var OtherBoundingRect = Other.BoundingRect; double dClosestDist = LineRects[0].Distance(OtherBoundingRect); for (var i = 1; i < LineRects.Count; i++) { double dDist = LineRects[i].Distance(OtherBoundingRect); if (dDist < dClosestDist) { dClosestDist = dDist; usThisClosestLineGuess = i; } } // Now cycle through all the other poly's line rects to find the closest to the // guessed at closest line on this. var usOtherClosestLineGuess = 0; dClosestDist = Other.LineRects[0].Distance(LineRects[usThisClosestLineGuess]); for (var j = 1; j < Other.LineRects.Count; j++) { double dDist = Other.LineRects[j].Distance(LineRects[usThisClosestLineGuess]); if (dDist < dClosestDist) { dClosestDist = dDist; usOtherClosestLineGuess = j; } } // Now we have a guess at the 2 closest lines. double dMinDistGuess = Lines[usThisClosestLineGuess].Distance( Other.Lines[usOtherClosestLineGuess], ptOnThis, ptOnOther); // If its 0 then return 0. if (dMinDistGuess == 0) { return(0); } var ptOnThisTemp = new C2DPoint(); var ptOnOtherTemp = new C2DPoint(); // Now go through all of our line rects and only check further if they are closer // to the other's bounding rect than the min guess. for (var i = 0; i < Lines.Count; i++) { if (LineRects[i].Distance(OtherBoundingRect) < dMinDistGuess) { for (var j = 0; j < Other.Lines.Count; j++) { double dDist = Lines[i].Distance(Other.Lines[j], ptOnThisTemp, ptOnOtherTemp); if (dDist < dMinDistGuess) { ptOnThis.Set(ptOnThisTemp); ptOnOther.Set(ptOnOtherTemp); if (dDist == 0) { return(0); } dMinDistGuess = dDist; } } } } // if we are here, there is no intersection but the other could be inside this or vice-versa if (BoundingRect.Contains(Other.BoundingRect) && Contains(ptOnOtherTemp)) { dMinDistGuess *= -1.0; } else if (Other.BoundingRect.Contains(BoundingRect) && Other.Contains(ptOnThisTemp)) { dMinDistGuess *= -1.0; } return(dMinDistGuess); }
/// <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 between this and the test point. /// </summary> /// <param name="TestPoint">The test point.</param> /// <param name="ptOnThis">The closest point on this to the given point as a returned value.</param> public override double Distance(C2DPoint TestPoint, C2DPoint ptOnThis) { C2DPoint ptCen = new C2DPoint( GetCircleCentre()); C2DCircle Circle = new C2DCircle(ptCen, Radius); C2DPoint ptOnCircle = new C2DPoint(); double dCircleDist = Circle.Distance(TestPoint, ptOnCircle); if (ArcOnRight ^ Line.IsOnRight(ptOnCircle)) { // The closest point on the circle isn't on the curve double d1 = TestPoint.Distance(Line.point); double d2 = TestPoint.Distance(Line.GetPointTo()); if (d1 < d2) { ptOnThis.Set(Line.point); return d1; } else { ptOnThis.Set(Line.GetPointTo()); return d2; } } else { // The closest point on the circle IS on the curve ptOnThis.Set(ptOnCircle); return Math.Abs(dCircleDist); } }