/// <summary> /// Returns the lines that go to make this up based on the set of points /// provided which are assumed to be on the line. /// </summary> /// <param name="PtsOnLine">The points defining how the line is to be split.</param> /// <param name="LineSet">The line set to recieve the result.</param> public override void GetSubLines(List <C2DPoint> PtsOnLine, List <C2DLineBase> LineSet) { // if there are no points on the line to split on then add a copy of this and return. int usPointsCount = PtsOnLine.Count; if (usPointsCount == 0) { LineSet.Add(new C2DArc(this)); return; } else { // Make a copy of the points for sorting. C2DPointSet TempPts = new C2DPointSet(); TempPts.MakeCopy(PtsOnLine); if (usPointsCount > 1) // They need sorting { // Make a line from the mid point of my line to the start C2DLine CenToStart = new C2DLine(Line.GetMidPoint(), Line.point); // Now sort the points according to the order in which they will be encountered if (ArcOnRight) { TempPts.SortByAngleToLeft(CenToStart); } else { TempPts.SortByAngleToRight(CenToStart); } } C2DPoint ptCentre = new C2DPoint(GetCircleCentre()); // Add the line from the start of this to the first. C2DLine NewLine = new C2DLine(Line.point, TempPts[0]); LineSet.Add(new C2DArc(NewLine, Radius, NewLine.IsOnRight(ptCentre), ArcOnRight)); // Add all the sub lines. for (int i = 1; i < usPointsCount; i++) { NewLine.Set(TempPts[i - 1], TempPts[i]); LineSet.Add(new C2DArc(NewLine, Radius, NewLine.IsOnRight(ptCentre), ArcOnRight)); } // Add the line from the last point on this to the end of this. NewLine.Set(TempPts[TempPts.Count - 1], Line.GetPointTo()); LineSet.Add(new C2DArc(NewLine, Radius, NewLine.IsOnRight(ptCentre), ArcOnRight)); } }
/// <summary> /// Static version of Fermat point function. /// </summary> public static C2DPoint GetFermatPoint(C2DPoint pt1, C2DPoint pt2, C2DPoint pt3) { var Line12 = new C2DLine(pt1, pt2); var Line23 = new C2DLine(pt2, pt3); var Line31 = new C2DLine(pt3, pt1); var dAng2 = Constants.conPI - Line12.vector.AngleBetween(Line23.vector); if (dAng2 >= Constants.conTWOTHIRDPI) // greater than 120 degrees { return(new C2DPoint(pt2)); } else if (dAng2 < Constants.conTHIRDPI) // if less than 60 then 1 of the other 2 could be greater than 120 { var dAng3 = Constants.conPI - Line23.vector.AngleBetween(Line31.vector); if (dAng3 >= Constants.conTWOTHIRDPI) // greater than 120 degrees { return(new C2DPoint(pt3)); } else if ((Constants.conPI - dAng2 - dAng3) >= Constants.conTWOTHIRDPI) // if least angle is greater than 120 { return(new C2DPoint(pt1)); } } var bClockwise = Line12.IsOnRight(pt3); if (bClockwise) { Line12.vector.TurnLeft(Constants.conTHIRDPI); // 60 degrees Line23.vector.TurnLeft(Constants.conTHIRDPI); // 60 degrees } else { Line12.vector.TurnRight(Constants.conTHIRDPI); // 60 degrees Line23.vector.TurnRight(Constants.conTHIRDPI); // 60 degrees } Line12.SetPointFrom(pt3); Line23.SetPointFrom(pt1); var IntPt = new List <C2DPoint>(); bool B1 = true, B2 = true; if (Line12.Crosses(Line23, IntPt, ref B1, ref B2, false)) { return(IntPt[0]); } else { Debug.Assert(false); } return(new C2DPoint(0, 0)); }
/// <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> /// Static version of Fermat point function. /// </summary> public static C2DPoint GetFermatPoint(C2DPoint pt1, C2DPoint pt2, C2DPoint pt3) { C2DLine Line12 = new C2DLine(pt1, pt2); C2DLine Line23 = new C2DLine(pt2, pt3); C2DLine Line31 = new C2DLine(pt3, pt1); double dAng2 = Constants.conPI - Line12.vector.AngleBetween(Line23.vector); if (dAng2 >= Constants.conTWOTHIRDPI) // greater than 120 degrees { return new C2DPoint(pt2); } else if (dAng2 < Constants.conTHIRDPI) // if less than 60 then 1 of the other 2 could be greater than 120 { double dAng3 = Constants.conPI - Line23.vector.AngleBetween(Line31.vector); if (dAng3 >= Constants.conTWOTHIRDPI) // greater than 120 degrees { return new C2DPoint(pt3); } else if ((Constants.conPI - dAng2 - dAng3) >= Constants.conTWOTHIRDPI) // if least angle is greater than 120 { return new C2DPoint(pt1); } } bool bClockwise = Line12.IsOnRight(pt3); if (bClockwise) { Line12.vector.TurnLeft(Constants.conTHIRDPI); // 60 degrees Line23.vector.TurnLeft(Constants.conTHIRDPI); // 60 degrees } else { Line12.vector.TurnRight(Constants.conTHIRDPI); // 60 degrees Line23.vector.TurnRight(Constants.conTHIRDPI); // 60 degrees } Line12.SetPointFrom(pt3); Line23.SetPointFrom(pt1); List<C2DPoint> IntPt = new List<C2DPoint>(); bool B1 = true, B2 = true; if (Line12.Crosses(Line23, IntPt, ref B1, ref B2, false)) { return IntPt[0]; } else { Debug.Assert(false); } return new C2DPoint(0, 0); }
/// <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 lines that go to make this up based on the set of points /// provided which are assumed to be on the line. /// </summary> /// <param name="PtsOnLine">The points defining how the line is to be split.</param> /// <param name="LineSet">The line set to recieve the result.</param> public override void GetSubLines(List<C2DPoint> PtsOnLine, List<C2DLineBase> LineSet) { // if there are no points on the line to split on then add a copy of this and return. int usPointsCount = PtsOnLine.Count; if (usPointsCount == 0 ) { LineSet.Add(new C2DArc(this)); return; } else { // Make a copy of the points for sorting. C2DPointSet TempPts = new C2DPointSet(); TempPts.MakeCopy(PtsOnLine); if (usPointsCount > 1) // They need sorting { // Make a line from the mid point of my line to the start C2DLine CenToStart = new C2DLine( Line.GetMidPoint(), Line.point ); // Now sort the points according to the order in which they will be encountered if (ArcOnRight) TempPts.SortByAngleToLeft( CenToStart ); else TempPts.SortByAngleToRight( CenToStart ); } C2DPoint ptCentre = new C2DPoint(GetCircleCentre()); // Add the line from the start of this to the first. C2DLine NewLine = new C2DLine( Line.point, TempPts[0] ); LineSet.Add(new C2DArc(NewLine, Radius, NewLine.IsOnRight(ptCentre), ArcOnRight)); // Add all the sub lines. for (int i = 1; i < usPointsCount; i++) { NewLine.Set(TempPts[i - 1], TempPts[i]); LineSet.Add(new C2DArc(NewLine, Radius, NewLine.IsOnRight(ptCentre), ArcOnRight)); } // Add the line from the last point on this to the end of this. NewLine.Set(TempPts[TempPts.Count - 1], Line.GetPointTo()); LineSet.Add(new C2DArc(NewLine, Radius, NewLine.IsOnRight(ptCentre), ArcOnRight)); } }
/// <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; }