/// <summary> /// Creates the events for a segment. /// </summary> /// <param name="segment">A list consisting of two points defining an edge</param> /// <param name="polygonType"></param> /// <param name="list">The list to add the events to</param> private void CreateEvents(IList <Vector2D> segment, PolygonType polygonType, ICollection <SweepEvent> list) { var point1 = segment[0]; var point2 = segment[1]; var event1 = new SweepEvent(point1, false, null, polygonType); var event2 = new SweepEvent(point2, false, event1, polygonType); event1.OtherEvent = event2; if (point1.Equals(point2)) { // 0-length segments are irrelevant for us since they will never result in intersections return; } // The segment could be ordered the wrong way around, so we need to set the IsStart field properly if (SweepEvent.CompareTo(event1, event2) > 0) { event2.IsStart = true; } else { event1.IsStart = true; } list.Add(event1); list.Add(event2); }
private void DivideSegment(SweepEvent ev, Vector2D pos, IBST <SweepEvent> events) { // "Right event" of the "left line segment" resulting from dividing ev.Segment var r = new SweepEvent(pos, false, ev, ev.PolygonType); // "Left event" of the "right line segment" resulting from dividing ev.Segment var l = new SweepEvent(pos, true, ev.OtherEvent, ev.PolygonType); if (SweepEvent.CompareTo(l, ev.OtherEvent) > 0 ) // Avoid a rounding error. The left event would be processed after the right event { ev.OtherEvent.IsStart = true; l.IsStart = false; } ev.OtherEvent.OtherEvent = l; ev.OtherEvent = r; events.Insert(l); events.Insert(r); }
private ContourPolygon ConnectEdges() { var result = new ContourPolygon(); var resultEvents = ResultEvents .Where(it => (it.IsStart && it.InResult) || (!it.IsStart && it.OtherEvent.InResult)).ToList(); // Due to overlapping edges the resultEvents list can be not wholly sorted var sorted = false; while (!sorted) { sorted = true; for (int i = 0; i < resultEvents.Count; i++) { if (i + 1 < resultEvents.Count && SweepEvent.CompareTo(resultEvents[i], resultEvents[i + 1]) == 1) { var tmp = resultEvents[i]; resultEvents[i] = resultEvents[i + 1]; resultEvents[i + 1] = tmp; sorted = false; } } } // We cannot do a foreach because we need to set PositionInResult for (int i = 0; i < resultEvents.Count; i++) { var resultEvent = resultEvents[i]; resultEvent.PositionInResult = i; } foreach (var resultEvent in resultEvents) { if (!resultEvent.IsStart) { var tmp = resultEvent.PositionInResult; resultEvent.PositionInResult = resultEvent.OtherEvent.PositionInResult; resultEvent.OtherEvent.PositionInResult = tmp; } } var processed = new BitArray(resultEvents.Count); var depth = new List <int>(); var holeOf = new List <int>(); for (int i = 0; i < resultEvents.Count; i++) { if (processed[i]) { continue; } var contour = new Contour(); result.Add(contour); var contourId = result.NumberOfContours - 1; depth.Add(0); holeOf.Add(-1); if (resultEvents[i].PreviousInResult != null) { var lowerContourId = resultEvents[i].PreviousInResult.ContourId; if (!resultEvents[i].PreviousInResult.ResultInOut) { result[lowerContourId].AddHole(contourId); holeOf[contourId] = lowerContourId; depth[contourId] = depth[lowerContourId] + 1; contour.External = false; } else if (!result[lowerContourId].External) { result[holeOf[lowerContourId]].AddHole(contourId); holeOf[contourId] = holeOf[lowerContourId]; depth[contourId] = depth[lowerContourId]; contour.External = false; } } var pos = i; var initial = resultEvents[i].Point; contour.AddVertex(initial); while (pos >= i) { processed[pos] = true; if (resultEvents[pos].IsStart) { resultEvents[pos].ResultInOut = false; resultEvents[pos].ContourId = contourId; } else { resultEvents[pos].OtherEvent.ResultInOut = true; resultEvents[pos].OtherEvent.ContourId = contourId; } pos = resultEvents[pos].PositionInResult; processed[pos] = true; contour.AddVertex(resultEvents[pos].Point); pos = NextPos(pos, resultEvents, processed, i); } pos = pos == -1 ? i : pos; processed[pos] = processed[resultEvents[pos].PositionInResult] = true; resultEvents[pos].OtherEvent.ResultInOut = true; resultEvents[pos].OtherEvent.ContourId = contourId; if ((depth[contourId] & 1) != 0) { contour.ChangeOrientation(); } } return(result); }
private int PossibleIntersection(SweepEvent ev1, SweepEvent ev2, IBST <SweepEvent> events) { Vector2D intersectionPoint; var nIntersections = FindIntersections(ev1.Point, ev1.OtherEvent.Point, ev2.Point, ev2.OtherEvent.Point, out intersectionPoint); if (nIntersections == 0) { return(0); // no intersection } // If the intersection is between two endpoints if (nIntersections == 1 && (ev1.Point.Equals(ev2.Point) || ev1.OtherEvent.Point.Equals(ev2.OtherEvent.Point))) { return(0); // the line segments intersect at an endpoint of both line segments } if (nIntersections == 2 && ev1.PolygonType == ev2.PolygonType) { // The line segments overlap, but they belong to the same polygon throw new ArgumentException(string.Format("Sorry, edges of the same polygon overlap ({0} and {1})", ev1, ev2)); } // The line segments associated to ev1 and ev2 intersect if (nIntersections == 1) { if (!ev1.Point.Equals(intersectionPoint) && !ev1.OtherEvent.Point.Equals(intersectionPoint) ) // If the intersection point is not an endpoint of ev1.Segment { DivideSegment(ev1, intersectionPoint, events); } if (!ev2.Point.Equals(intersectionPoint) && !ev2.OtherEvent.Point.Equals(intersectionPoint) ) // If the intersection point is not an endpoint of ev2.Segment { DivideSegment(ev2, intersectionPoint, events); } return(1); } // The line segments associated to ev1 and ev2 overlap var sortedEvents = new List <SweepEvent>(); var leftEqual = false; var rightEqual = false; if (ev1.Point.Equals(ev2.Point)) { leftEqual = true; } else if (SweepEvent.CompareTo(ev1, ev2) == 1) { sortedEvents.Add(ev2); sortedEvents.Add(ev1); } else { sortedEvents.Add(ev1); sortedEvents.Add(ev2); } if (ev1.OtherEvent.Point.Equals(ev2.OtherEvent.Point)) { rightEqual = true; } else if (SweepEvent.CompareTo(ev1.OtherEvent, ev2.OtherEvent) == 1) { sortedEvents.Add(ev2.OtherEvent); sortedEvents.Add(ev1.OtherEvent); } else { sortedEvents.Add(ev1.OtherEvent); sortedEvents.Add(ev2.OtherEvent); } if (leftEqual) { // Both line segments are equal or share the left endpoint ev2.EdgeType = EdgeType.NonContributing; ev1.EdgeType = (ev2.InOut == ev1.InOut) ? EdgeType.SameTransition : EdgeType.DifferentTransition; if (!rightEqual) { DivideSegment(sortedEvents[1].OtherEvent, sortedEvents[0].Point, events); } return(2); } if (rightEqual) { // The line segments share the right endpoint DivideSegment(sortedEvents[0], sortedEvents[1].Point, events); return(3); } if (sortedEvents[0] != sortedEvents[3].OtherEvent) { // No line segment includes totally the other one DivideSegment(sortedEvents[0], sortedEvents[1].Point, events); DivideSegment(sortedEvents[1], sortedEvents[2].Point, events); return(3); } // One line segment includes the other one DivideSegment(sortedEvents[0], sortedEvents[1].Point, events); DivideSegment(sortedEvents[3].OtherEvent, sortedEvents[2].Point, events); return(3); }