private ConvexPolygon2D(IReadOnlyList <CartesianPoint> vertices) { this.Vertices = vertices; var edges = new LineSegment2D[vertices.Count]; for (int i = 0; i < vertices.Count; ++i) { edges[i] = new LineSegment2D(vertices[i], vertices[(i + 1) % vertices.Count]); } this.Edges = edges; }
public PolygonPointPosition FindRelativePositionOfPoint(CartesianPoint point) { int edgesPassingThroughPoint = 0; for (int i = 0; i < Vertices.Count; ++i) { var edge = new LineSegment2D(Vertices[i], Vertices[(i + 1) % Vertices.Count]); //TODO: Perhaps I should use the DirectedSegment2D, which is faster for the use if (edge.FindRelativePositionOfPoint(point) == LineSegment2D.SegmentPointPosition.PointOnSegment) { ++edgesPassingThroughPoint; } } if (edgesPassingThroughPoint == 1) { return(PolygonPointPosition.OnEdge); } else if (edgesPassingThroughPoint == 2) { return(PolygonPointPosition.OnVertex); } else if (IsPointInsidePolygon(point)) { return(PolygonPointPosition.Inside); } else if (IsPointInsidePolygon(point)) { return(PolygonPointPosition.Inside); } else { return(PolygonPointPosition.Outside); } //TODO: IsPointInsidePolygon(point) is undefined the point is on the boundary, so the following doesn't always work. //if (IsPointInsidePolygon(point)) return PolygonPointPosition.Inside; //{ // int edgesPassingThroughPoint = 0; // for (int i = 0; i < Vertices.Count; ++i) // { // var edge = new LineSegment2D(Vertices[i], Vertices[(i + 1) % Vertices.Count]); //TODO: Perhaps I should use the DirectedSegment2D, which is faster for the use // if (edge.FindRelativePositionOfPoint(point) == LineSegment2D.SegmentPointPosition.PointOnSegment) // { // ++edgesPassingThroughPoint; // } // } // if (edgesPassingThroughPoint == 0) return PolygonPointPosition.Outside; // else if (edgesPassingThroughPoint == 1) return PolygonPointPosition.OnEdge; // else if (edgesPassingThroughPoint == 2) return PolygonPointPosition.OnVertex; // else throw new Exception("This should not have happened."); //} }
/// <summary> /// See <see cref="http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect"/> /// </summary> /// <param name="segment"></param> /// <param name="intersectionPoint"></param> /// <returns></returns> public SegmentSegmentPosition IntersectionWith(LineSegment2D segment, out CartesianPoint intersectionPoint) { //TODO: optimize this: // a) Cache the vector representation of "this".Perhaps there could be a private vector representation class //b) Perhaps some cases can be ignored/lumped together.E.g. for colinear //c) Perhaps working with the double values instead of vector structs saves a lot of accesses. //TODO: handle extreme cases: // a) One segment's end lies on the other segment // b) One segment's end coincides with one of the other segment's ends, but otherwise they do not overlap // c) These cases probably need some tolerance checks.This requires attention since intersection points // outside the element will create unwanted triangulations. //Create vectors p, r, q, s var p = Vector2.Create(this.Start.X, this.Start.Y); var r = Vector2.Create(this.End.X - this.Start.X, this.End.Y - this.Start.Y); var q = Vector2.Create(segment.Start.X, segment.Start.Y); var s = Vector2.Create(segment.End.X - segment.Start.X, segment.End.Y - segment.Start.Y); // Find the cross products r x s and (q-p)*r double rCrossS = r.CrossProduct(s); var qMinusP = q - p; double qMinusPCrossR = qMinusP.CrossProduct(r); if (rCrossS == 0) // TODO: use tolerance here { if (qMinusPCrossR == 0) // TODO: use tolerance here { double rDotR = r * r; double t0 = (qMinusP * r) / rDotR; double t1 = t0 + (s * r) / rDotR; LineSegment1D this1D = (new LineSegment1D(0.0, 1.0)); LineSegment1D.SegmentSegmentPosition intersection1D = this1D.IntesectionWith(new LineSegment1D(t0, t1)); if (intersection1D == LineSegment1D.SegmentSegmentPosition.Disjoint) { intersectionPoint = null; return(LineSegment2D.SegmentSegmentPosition.CollinearDisjoint); } else if (intersection1D == LineSegment1D.SegmentSegmentPosition.Overlapping) { intersectionPoint = null; return(LineSegment2D.SegmentSegmentPosition.Overlapping); } else // TODO: handle this case { throw new NotImplementedException("The two segments are colinear and meet only at one point"); } } else { intersectionPoint = null; return(SegmentSegmentPosition.Parallel); } } else { double t = qMinusP.CrossProduct(s) / rCrossS; double u = qMinusPCrossR / rCrossS; if ((t >= 0.0) && (t <= 1.0) && (u >= 0.0) && (u <= 1.0)) { var solution = p + t * r; intersectionPoint = new CartesianPoint(solution[0], solution[1]); return(SegmentSegmentPosition.Intersecting); } else { intersectionPoint = null; return(SegmentSegmentPosition.Disjoint); } } }
//Perhaps I can override the intersects method and project the other segment onto the local system! public LineSegment2D.SegmentSegmentPosition IntersectionWith(LineSegment2D segment, out CartesianPoint intersectionPoint) { return(segment.IntersectionWith(new LineSegment2D(Start, End), out intersectionPoint)); }