/// <summary> /// Draws a line. /// </summary> public void Draw(C2DLine Line, Graphics graphics, Pen pen) { C2DPoint pt1 = Line.GetPointFrom(); C2DPoint pt2 = Line.GetPointTo(); this.ScaleAndOffSet(pt1); this.ScaleAndOffSet(pt2); graphics.DrawLine(pen, (int)pt1.x, (int)pt1.y, (int)pt2.x, (int)pt2.y); }
/// <summary> /// Contructor. /// </summary> /// <param name="ArcLine">The line defining the start and end point of the arc.</param> /// <param name="dRadius">The corresponding circles radius.</param> /// <param name="bCentreOnRight">Whether the centre is on the right.</param> /// <param name="bArcOnRight">Whether the arc is to the right of the line.</param> public C2DArc(C2DLine ArcLine, double dRadius, bool bCentreOnRight, bool bArcOnRight) { Line.Set(ArcLine); Radius = dRadius; CentreOnRight = bCentreOnRight; ArcOnRight = bArcOnRight; }
/// <summary> /// Adds a point which is a striaght line from the previous. /// </summary> /// <param name="Point">The point to go to.</param> public void LineTo(C2DPoint Point) { if (Lines.Count == 0) return; C2DLine pLine = new C2DLine( Lines[Lines.Count - 1].GetPointTo(), Point ); if (Lines.Count == 1 && Lines[0] is C2DLine && Lines[0].GetPointTo().PointEqualTo(Lines[0].GetPointFrom())) // CR 19-1-09 { Lines[0] = pLine; } else { Lines.Add(pLine); } }
/// <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> /// Reflects this through the line given. /// </summary> /// <param name="Line">The line to reflect this through.</param> public override void Reflect(C2DLine Line) { // First find the point along the line that this projects onto. // Make a vector from the point on the line given to this point. C2DVector vecthis = new C2DVector(Line.point, this ); // Find the length of the line given. double dLength = Line.vector.GetLength(); // Now make the projection of this point on the line. double dProj = vecthis.Dot(Line.vector); dProj /= dLength; // Find the factor along the line that the projection is. double dFactor = dProj / dLength; // Now set up a copy of the vector of the line given. C2DVector vProj = new C2DVector(Line.vector); // Multiply that by that factor calculated. vProj.Multiply(dFactor); // Use the vector to find the point on the line. C2DPoint ptOnLine = new C2DPoint(Line.point.GetPointTo(vProj) ); // Noe simply reflect this in the point. this.Reflect(ptOnLine); }
/// <summary> /// True if the point projects onto the line given and returns the /// point on the line. /// </summary> /// <param name="Line"></param> public void ProjectOnRay(C2DLine Line) { C2DVector vecthis = new C2DVector(Line.point, this ); double dProj = vecthis.Dot(Line.vector); double dFactor = dProj / (Line.vector.i * Line.vector.i + Line.vector.j * Line.vector.j ); C2DVector vProj = new C2DVector(Line.vector); vProj.i *= dFactor; vProj.j *= dFactor; this.Set(Line.point.x + vProj.i, Line.point.y + vProj.j); }
/// <summary> /// Projects the point on the line given returning a distance along the line from the start. /// </summary> /// <param name="Line">The line to project this on.</param> public double Project(C2DLine Line) { C2DVector vecthis = new C2DVector(Line.point, this ); return (vecthis.Dot(Line.vector)) / Line.vector.GetLength(); }
/// <summary> /// Assignment. /// </summary> /// <param name="Other">The other line.</param> public void Set(C2DLine Other) { point.Set(Other.point); vector.Set(Other.vector); }
/// <summary> /// True if the ray provided (infinite line starting from the first point) crosses this. /// </summary> /// <param name="Ray">The other line to test.</param> /// <param name="IntersectionPts">Output. The intersection points.</param> public bool CrossesRay(C2DLine Ray, List<C2DPoint> IntersectionPts) { C2DPoint p1 = point; C2DPoint p2 = GetPointTo(); C2DPoint p3 = Ray.point; C2DPoint p4 = Ray.GetPointTo(); double Ua = (p4.x - p3.x)*(p1.y - p3.y) - (p4.y - p3.y) * (p1.x - p3.x); double Ub = (p2.x - p1.x)*(p1.y - p3.y) - (p2.y - p1.y) * (p1.x - p3.x); double dDenominator = (p4.y - p3.y)*(p2.x - p1.x) - (p4.x - p3.x) * (p2.y - p1.y); if (dDenominator == 0) return false; Ua = Ua / dDenominator; Ub = Ub / dDenominator; bool bResult = (Ua >= 0 && Ua <= 1) && (Ub >= 0); if (bResult) { IntersectionPts.Add(new C2DPoint(p1.x + Ua*(p2.x - p1.x) , p1.y + Ua*(p2.y - p1.y))); } return bResult; }
/// <summary> /// True if this line would cross the other if this were infinite. /// </summary> /// <param name="Other">The other line to test.</param> public bool WouldCross(C2DLine Other) { bool bPointOnRight = IsOnRight(Other.point); bool bPointToOnRight = IsOnRight(Other.GetPointTo()); return (bPointOnRight^bPointToOnRight); }
/// <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) { var dCenCenDist = _Centre.Distance(Other.Centre); var dOtherRadius = Other.Radius; // C2DPoint ptThis; // C2DPoint ptOther; var dDist = dCenCenDist - Radius - dOtherRadius; if (dDist > 0) { // they do not interect and they are outside each other. var 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 var 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 var 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; var 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) { var 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)); } var 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. var ptClosest = new C2DPoint(Line.GetPointTo()); ptOnOther.Set(ptClosest); return(Distance(ptClosest, ptOnThis)); } // Now find out if there's an intersection. var 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)) { var d1 = Distance(Line.point, ptOnThis); var ptThisTemp = new C2DPoint(); var 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. var dCenOnLine = (ProjInt.dMax + ProjInt.dMin) / 2.0; if (dCenOnLine > 0) { if (dCenOnLine < dLength) { // The centre is projected on the line var dFactor = dCenOnLine / dLength; var vProj = new C2DVector(Line.vector); vProj.Multiply(dFactor); var ptOnLine = new C2DPoint(Line.point.GetPointTo(vProj)); ptOnOther.Set(ptOnLine); return(Distance(ptOnLine, ptOnThis)); } else { // The centre is projected above the line. var 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> /// Reflection trhough a line. /// </summary> /// <param name="Line">The line to reflect this through.</param> public override void Reflect(C2DLine Line) { _Centre.Reflect(Line); }
/// <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) { var x1 = Line.point.x; var x2 = Line.point.x + Line.vector.i; var x3 = _Centre.x; var y1 = Line.point.y; var y2 = Line.point.y + Line.vector.j; var y3 = _Centre.y; var r = Radius; var a = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); var b = 2 * ((x2 - x1) * (x1 - x3) + (y2 - y1) * (y1 - y3)); var c = x3 * x3 + y3 * y3 + x1 * x1 + y1 * y1 - 2 * (x3 * x1 + y3 * y1) - r * r; var u = -b / (2 * a); var ptClosestToCen = new C2DPoint(); if (u < 0) { ptClosestToCen.Set(Line.point); } else if (u > 1) { ptClosestToCen.Set(Line.GetPointTo()); } else { var V1 = new C2DVector(Line.vector); V1.Multiply(u); ptClosestToCen = Line.point.GetPointTo(V1); } var dDist = ptClosestToCen.Distance(_Centre); if (dDist > Radius) { return(false); } else { // Calculate the points. var d1 = b * b - 4 * a * c; Debug.Assert(d1 >= 0); if (d1 < 0) { return(false); } else if (d1 == 0) { var p1 = -b / (2 * a); IntersectionPts.Add(Line.GetPointOn(p1)); return(true); } else { d1 = Math.Sqrt(d1); var p1 = (-b + d1) / (2 * a); var p2 = (-b - d1) / (2 * a); var 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> /// 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> /// Projects this onto the line given. /// </summary> /// <param name="Line">Line to project on.</param> /// <param name="Interval">Ouput. Projection.</param> public override void Project(C2DLine Line, CInterval Interval) { P1.Project(Line, Interval); Interval.ExpandToInclude(P2.Project(Line)); Interval.ExpandToInclude(P3.Project(Line)); }
/// <summary> /// Projects the point on the vector given returning a distance along the vector. /// </summary> /// <param name="line">The vector to project this on.</param> /// <param name="interval">The interval to recieve the result. /// Both the min and max of the interval will be set to the result.</param> public override void Project(C2DLine line, CInterval interval) { interval.dMax = Project(line); interval.dMin = interval.dMax; }
/// <summary> /// True if this line crosses the other. Returns the point is a collection is provided. /// Returns whether it would cross on this or on the other. Can opt to get the point /// where the cross would occur (if not parallel) even if they don't cross. /// </summary> /// <param name="Other">The other line</param> /// <param name="IntersectionPts">To recieve the result</param> /// <param name="bOnThis">Output. True is the intersection would be on this line.</param> /// <param name="bOnOther">Output. True is the intersection would be on the other line.</param> /// <param name="bAddPtIfFalse">Input. True to add the intersection point even if there is no intersection.</param> /// <returns></returns> public bool Crosses(C2DLine Other, List<C2DPoint> IntersectionPts , ref bool bOnThis, ref bool bOnOther, bool bAddPtIfFalse) { bOnThis = false; bOnOther = false; C2DPoint p1 = point; C2DPoint p2 = GetPointTo(); C2DPoint p3 = Other.point; C2DPoint p4 = Other.GetPointTo(); double Ua = (p4.x - p3.x)*(p1.y - p3.y) - (p4.y - p3.y) * (p1.x - p3.x); double Ub = (p2.x - p1.x)*(p1.y - p3.y) - (p2.y - p1.y) * (p1.x - p3.x); double dDenominator = (p4.y - p3.y)*(p2.x - p1.x) - (p4.x - p3.x) * (p2.y - p1.y); if (dDenominator == 0) return false; Ua = Ua / dDenominator; Ub = Ub / dDenominator; bOnThis = (Ua >= 0 && Ua < 1); // For ints we need the line to be the point set [a,b); bOnOther = (Ub >= 0 && Ub < 1); // For ints we need the line to be the point set [a,b); bool bResult = bOnThis && bOnOther; if (bAddPtIfFalse || bResult) { IntersectionPts.Add(new C2DPoint(p1.x + Ua*(p2.x - p1.x) , p1.y + Ua*(p2.y - p1.y))); } return (bResult); }
/// <summary> /// Projection onto the line. /// </summary> /// <param name="Line">Line to project this on.</param> /// <param name="Interval">Interval to recieve the result.</param> public void Project(C2DLine Line, CInterval Interval) { _Rim.Project(Line, Interval); }
/// <summary> /// Point reflection. /// </summary> /// <param name="Line">The line through which to reflect this.</param> public override void Reflect(C2DLine Line) { C2DPoint pointTo = new C2DPoint(GetPointTo()); point.Reflect(Line); pointTo.Reflect(Line); SetPointTo(pointTo); }
/// <summary> /// True if part of this line is above the other. Returns the point /// on this and on the other. /// </summary> /// <param name="Other"></param> /// <param name="dVerticalDistance"></param> /// <param name="ptOnThis"></param> /// <param name="ptOnOther"></param> /// <returns></returns> public bool OverlapsAbove(C2DLine Other, ref double dVerticalDistance, C2DPoint ptOnThis, C2DPoint ptOnOther) { // Get the 2 points for both lines C2DPoint OtherTo = new C2DPoint(Other.point.x + Other.vector.i, Other.point.y + Other.vector.j); C2DPoint ThisTo = new C2DPoint(point.x + vector.i, point.y + vector.j); // Make an interval for both in the x plane CInterval iThis = new CInterval(point.x, point.x); iThis.ExpandToInclude(ThisTo.x); CInterval iOther = new CInterval(Other.point.x, Other.point.x); iOther.ExpandToInclude(OtherTo.x); // This is an interval for the overlap between the 2 CInterval iOverlap = new CInterval(); // If there is an overlap... if (iThis.Overlaps(iOther, iOverlap)) { double dThisYMin; double dThisYMax; double dOtherYMin; double dOtherYMax; // If the line is vertical then y at the x min / max can be set to the ends of the line. if (vector.i == 0) { dThisYMin = point.y; dThisYMax = ThisTo.y; } else // otherwise, caluclate the y values at the interval ends { dThisYMin = GetY(iOverlap.dMin); dThisYMax = GetY(iOverlap.dMax); } // Now do the same for the other line if (Other.vector.i == 0) { dOtherYMin = Other.point.y; dOtherYMax = OtherTo.y; } else { dOtherYMin = Other.GetY(iOverlap.dMin); dOtherYMax = Other.GetY(iOverlap.dMax); } // Now find the distance between the 2 at the ends double dDistMin = dThisYMin - dOtherYMin; double dDistMax = dThisYMax - dOtherYMax; // If they are both > 0 then no intersection if ((dDistMin > 0) && (dDistMax > 0)) { dDistMin = Math.Abs(dDistMin); dDistMax = Math.Abs(dDistMax); // find which one is smallest if (dDistMin > dDistMax) { dVerticalDistance = dDistMax; // distance at the max is smallest ptOnThis.x = iOverlap.dMax; ptOnThis.y = dThisYMax; ptOnOther.x = iOverlap.dMax; ptOnOther.y = dOtherYMax; } else { dVerticalDistance = dDistMin; // distance at the min is smallest ptOnThis.x = iOverlap.dMin; ptOnThis.y = dThisYMin; ptOnOther.x = iOverlap.dMin; ptOnOther.y = dOtherYMin; } return(true); } else if ((dDistMin < 0) && (dDistMax < 0)) // This is below. { return(false); } else { // find the intersection. dVerticalDistance = 0; C2DPointSet pts = new C2DPointSet(); if (this.Crosses(Other, pts)) { ptOnThis = pts[0]; ptOnOther = ptOnThis; } else { Debug.Assert(false); } } return(true); } else { return(false); } }
/// <summary> /// Contructor. /// </summary> /// <param name="Line">The line defining the start and end point of the arc.</param> /// <param name="dRadius">The corresponding circles radius.</param> /// <param name="bCentreOnRight">Whether the centre is on the right.</param> /// <param name="bArcOnRight">Whether the arc is to the right of the line.</param> public C2DSegment(C2DLine Line, double dRadius, bool bCentreOnRight, bool bArcOnRight) { Arc.Set(Line, dRadius, bCentreOnRight, bArcOnRight); }
/// <summary> /// Projects the point on the line given returning a distance along the line from the start. /// </summary> /// <param name="Line">The line to project this on.</param> public double Project(C2DLine Line) { C2DVector vecthis = new C2DVector(Line.point, this); return((vecthis.Dot(Line.vector)) / Line.vector.GetLength()); }
/// <summary> /// Projects the point on the vector given returning a distance along the vector. /// </summary> /// <param name="Line">The vector to project this on.</param> /// <param name="Interval">The interval to recieve the result. /// Both the min and max of the interval will be set to the result.</param> public override void Project(C2DLine Line, CInterval Interval) { Interval.dMax = Project(Line); Interval.dMin = Interval.dMax; }
/// <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> /// Reflection in a line /// </summary> public abstract void Reflect(C2DLine Line);
/// <summary> /// Reflects the in the line given. /// </summary> /// <param name="Line">The line to reflect through.</param> public override void Reflect(C2DLine Line) { P1.Reflect(Line); P2.Reflect(Line); P3.Reflect(Line); }
/// <summary> /// Projects this onto the line provided with the interval on the line returned. /// </summary> public abstract void Project(C2DLine Line, CInterval Interval);
/// <summary> /// Static version of circumcentre function. /// </summary> public static C2DPoint GetCircumCentre(C2DPoint pt1, C2DPoint pt2, C2DPoint pt3) { C2DLine Line12 = new C2DLine (pt1, pt2); C2DLine Line23 = new C2DLine (pt2, pt3); // Move the lines to start from the midpoint on them Line12.point.Set( Line12.GetMidPoint()); Line23.point.Set( Line23.GetMidPoint()); // Turn them right (left would work as well) Line12.vector.TurnRight(); Line23.vector.TurnRight(); // Find the intersection between them taking the intersect point even if they don't // intersect directly (i.e. where they would intersect because we may have turned them // the wrong way). List<C2DPoint> IntPt = new List<C2DPoint>(); bool B1 = true , B2 = true; Line12.Crosses(Line23, IntPt,ref B1, ref B2, true); C2DPoint ptResult = new C2DPoint(0, 0); if (IntPt.Count == 1) { ptResult = IntPt[0]; } else { // co-linear so fail. Debug.Assert(false, "Colinnear triangle. Cannot calculate Circum Centre"); } return ptResult; }
/// <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> /// Static version of InCentre function. /// </summary> public static C2DPoint GetInCentre(C2DPoint pt1, C2DPoint pt2, C2DPoint pt3) { // Set up a line to bisect the lines from 1 to 2 and 1 to 3 C2DLine Line1 = new C2DLine(pt1, pt2); C2DLine Line2 = new C2DLine(pt1, pt3); Line1.SetLength( Line2.GetLength() ); C2DLine Line12Bisect = new C2DLine( pt1, pt3.GetMidPoint( Line1.GetPointTo())); // Set up a line to bisect the lines from 2 to 1 and 2 to 3 C2DLine Line3 = new C2DLine(pt2, pt1); C2DLine Line4 = new C2DLine(pt2, pt3); Line3.SetLength( Line4.GetLength() ); C2DLine Line34Bisect = new C2DLine(pt2, pt3.GetMidPoint(Line3.GetPointTo())); // Now intersect the 2 lines and find the point. List<C2DPoint> Int = new List<C2DPoint>(); // Add the intersection even if there isn't one (i.e. infinite lines) bool B1 = true, B2 = true; Line12Bisect.Crosses(Line34Bisect, Int, ref B1, ref B2, true); Debug.Assert (Int.Count == 1); return Int[0]; }
/// <summary> /// Constructor. /// </summary> /// <param name="Other">The other line.</param> public C2DLine(C2DLine Other) { point.Set(Other.point); vector.Set(Other.vector); }
/// <summary> /// Own cross creation. Line-line intersection Wikipedia /// </summary> /// <param name="Other"></param> /// <returns></returns> public bool Crosses(C2DLine Other) { C2DPoint p1 = point; C2DPoint p2 = GetPointTo(); C2DPoint p3 = Other.point; C2DPoint p4 = Other.GetPointTo(); double Ua = (p1.x * p2.y - p1.y * p2.x) * (p3.x - p4.x) - (p1.x - p2.x) * (p3.x * p4.y - p3.y * p4.x); double Ub = (p1.x * p2.y - p1.y * p2.x) * (p3.y - p4.y) - (p1.y - p2.y) * (p3.x * p4.y - p3.y * p4.x); double dDenominator = (p1.x - p2.x) * (p3.y - p4.y) - (p1.y - p2.y) * (p3.x - p4.x); if (dDenominator == 0) return false; Ua = Ua / dDenominator; Ub = Ub / dDenominator; bool result = (Ua >= 0 && Ua < 1) && (Ub >= 0 && Ub < 1); return result; }
/// <summary> /// Reflects the in the line given. /// </summary> /// <param name="Line">The line to reflect through.</param> public override void Reflect(C2DLine Line) { Arc.Reflect( Line); }
/// <summary> /// True if this line crosses the other line, returns the intersection pt. /// </summary> /// <param name="Other">The other line to test.</param> /// <param name="IntersectionPts">Output. The intersection points.</param> public bool Crosses(C2DLine Other, List<C2DPoint> IntersectionPts) { bool bOnThis = true; bool bOnOther = true; return Crosses(Other, IntersectionPts, ref bOnThis, ref bOnOther, false); }
/// <summary> /// Contructor. /// </summary> /// <param name="Line">The line defining the start and end point of the arc.</param> /// <param name="dRadius">The corresponding circles radius.</param> /// <param name="bCentreOnRight">Whether the centre is on the right.</param> /// <param name="bArcOnRight">Whether the arc is to the right of the line.</param> public C2DSegment(C2DLine Line, double dRadius, bool bCentreOnRight, bool bArcOnRight) { Arc.Set( Line, dRadius, bCentreOnRight, bArcOnRight); }
/// <summary> /// Function to join the 2 lines at the point where they do / would intersect. If they do then /// the lines are clipped to remove the smallest part of the line. Returns false if they /// cannot be joined. /// </summary> /// <param name="Other">The other line</param> public bool Join(C2DLine Other) { C2DPoint p1 = point; C2DPoint p2 = GetPointTo(); C2DPoint p3 = Other.point; C2DPoint p4 = Other.GetPointTo(); double Ua = (p4.x - p3.x) * (p1.y - p3.y) - (p4.y - p3.y) * (p1.x - p3.x); double Ub = (p2.x - p1.x) * (p1.y - p3.y) - (p2.y - p1.y) * (p1.x - p3.x); double dDenominator = (p4.y - p3.y) * (p2.x - p1.x) - (p4.x - p3.x) * (p2.y - p1.y); if (dDenominator == 0) return false; Ua = Ua / dDenominator; Ub = Ub / dDenominator; C2DPoint IntPt = new C2DPoint(p1.x + Ua * (p2.x - p1.x), p1.y + Ua * (p2.y - p1.y)); if ( Ua >=0.5) this.SetPointTo( IntPt ); else this.SetPointFrom( IntPt ); if ( Ub >=0.5) Other.SetPointTo( IntPt ); else Other.SetPointFrom( IntPt ); return true; }
/// <summary> /// Reflects throught the line provided. /// </summary> /// <param name="Line">Line through which to reflect this.</param> public void Reflect(C2DLine Line) { _Rim.Reflect(Line); for (int i = 0 ; i < _Holes.Count; i++) { _Holes[i].Reflect(Line); } }
/// <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> /// Projection onto a line. /// </summary> /// <param name="TestLine">The line to project this on.</param> /// <param name="Interval">Output. The interval.</param> public override void Project(C2DLine TestLine, CInterval Interval) { double dP1 = point.Project(TestLine); Interval.dMax = dP1; Interval.dMin = dP1; Interval.ExpandToInclude(GetPointTo().Project(TestLine)); }
/// <summary> /// True if this crosses the ray, returns the intersection points. /// </summary> /// <param name="Ray">Ray to test for.</param> /// <param name="IntersectionPts">Intersection points.</param> public bool CrossesRay(C2DLine Ray, C2DPointSet IntersectionPts) { C2DPointSet IntPts = new C2DPointSet(); _Rim.CrossesRay(Ray, IntPts); IntersectionPts.ExtractAllOf(IntPts); for (int i = 0 ; i < _Holes.Count; i++) { if (_Holes[i].CrossesRay(Ray, IntPts)) { double dDist = Ray.point.Distance(IntPts[0]); int nInsert = 0; while (nInsert < IntersectionPts.Count && Ray.point.Distance( IntersectionPts[nInsert]) < dDist ) { nInsert++; } IntersectionPts.InsertRange(nInsert, IntPts); } } return (IntersectionPts.Count > 0); }
/// <summary> /// True if part of this line is above the other. Returns the point /// on this and on the other. /// </summary> /// <param name="Other"></param> /// <param name="dVerticalDistance"></param> /// <param name="ptOnThis"></param> /// <param name="ptOnOther"></param> /// <returns></returns> public bool OverlapsAbove(C2DLine Other, ref double dVerticalDistance, C2DPoint ptOnThis, C2DPoint ptOnOther) { // Get the 2 points for both lines C2DPoint OtherTo = new C2DPoint(Other.point.x + Other.vector.i, Other.point.y + Other.vector.j); C2DPoint ThisTo = new C2DPoint(point.x + vector.i, point.y + vector.j); // Make an interval for both in the x plane CInterval iThis = new CInterval( point.x, point.x); iThis.ExpandToInclude( ThisTo.x ); CInterval iOther = new CInterval( Other.point.x, Other.point.x); iOther.ExpandToInclude( OtherTo.x ); // This is an interval for the overlap between the 2 CInterval iOverlap = new CInterval(); // If there is an overlap... if (iThis.Overlaps(iOther, iOverlap)) { double dThisYMin; double dThisYMax; double dOtherYMin; double dOtherYMax; // If the line is vertical then y at the x min / max can be set to the ends of the line. if (vector.i == 0) { dThisYMin = point.y; dThisYMax = ThisTo.y; } else // otherwise, caluclate the y values at the interval ends { dThisYMin = GetY(iOverlap.dMin); dThisYMax = GetY(iOverlap.dMax); } // Now do the same for the other line if (Other.vector.i == 0) { dOtherYMin = Other.point.y; dOtherYMax = OtherTo.y; } else { dOtherYMin = Other.GetY(iOverlap.dMin); dOtherYMax = Other.GetY(iOverlap.dMax); } // Now find the distance between the 2 at the ends double dDistMin = dThisYMin - dOtherYMin; double dDistMax = dThisYMax - dOtherYMax; // If they are both > 0 then no intersection if ( (dDistMin > 0) && (dDistMax > 0)) { dDistMin = Math.Abs( dDistMin); dDistMax = Math.Abs(dDistMax); // find which one is smallest if ( dDistMin > dDistMax) { dVerticalDistance = dDistMax; // distance at the max is smallest ptOnThis.x = iOverlap.dMax; ptOnThis.y = dThisYMax; ptOnOther.x = iOverlap.dMax; ptOnOther.y = dOtherYMax; } else { dVerticalDistance = dDistMin; // distance at the min is smallest ptOnThis.x = iOverlap.dMin; ptOnThis.y = dThisYMin; ptOnOther.x = iOverlap.dMin; ptOnOther.y = dOtherYMin; } return true; } else if ( (dDistMin < 0) && (dDistMax < 0)) // This is below. { return false; } else { // find the intersection. dVerticalDistance = 0; C2DPointSet pts = new C2DPointSet(); if(this.Crosses(Other, pts)) { ptOnThis = pts[0]; ptOnOther = ptOnThis; } else { Debug.Assert(false); } } return true; } else { return false; } }
/// <summary> /// Reflects the in the line given. /// </summary> /// <param name="Line">The line to reflect through.</param> public override void Reflect(C2DLine Line) { Arc.Reflect(Line); }