public static LinkedList <LineSegmentIntersection> FindIntersections(IEnumerable <DCEL_HalfEdge> lineSegments) { LinkedList <LineSegmentIntersection> result = new LinkedList <LineSegmentIntersection>(); Sweepline sweepline = new Sweepline(); RBTreeMap <EventPoint, LinkedList <Segment> > eventQueue = new RBTreeMap <EventPoint, LinkedList <Segment> >((x, y) => x.CompareTo(y)); var segments = lineSegments.Where(lineSegment => lineSegment.Origin.Position != lineSegment.Destination.Position) .Select(lineSegment => new Segment(lineSegment, sweepline)); //segments = FixOverlappingSegments(segments); foreach (var segment in segments) { var node = eventQueue.Find(segment.Upper); LinkedList <Segment> upperList = (node != null ? node.Value : null); if (upperList == null) { upperList = new LinkedList <Segment>(); eventQueue.Add(new RBTreeMapNode <EventPoint, LinkedList <Segment> >(new EventPoint(segment.Upper), upperList)); } upperList.AddLast(segment); if (!eventQueue.ContainsKey(segment.Lower)) { eventQueue.Add(new RBTreeMapNode <EventPoint, LinkedList <Segment> >(new EventPoint(segment.Lower), new LinkedList <Segment>())); } } RBTreeSet <Segment> status = new RBTreeSet <Segment>((x, y) => x.CompareTo(y)); while (eventQueue.Count > 0) { var pair = eventQueue.MinNode; eventQueue.RemoveMin(); EventPoint nextEventPoint = pair.Key; LinkedList <Segment> upperList = pair.Value; LineSegmentIntersection reportedIntersection; HandleEventPoint(nextEventPoint, upperList, sweepline, eventQueue, status, out reportedIntersection); if (reportedIntersection != null) { result.AddLast(reportedIntersection); } } return(result); }
private static void FindNewEvent(Segment s1, Segment s2, EventPoint eventPoint, RBTreeMap <EventPoint, LinkedList <Segment> > eventQueue) { //If two segments intersect below the sweep line, or on it and //to the right of the current event point, and the intersection //is not yet present as an event in Q: //then insert a new event point in Q for this intersection VecRat2 pointIntersection = new VecRat2(); SegRat2 segmentIntersection = new SegRat2(); //bool intersectionExists = Segment.ComputeIntersection(s1, s2, out pointIntersection); //if (intersectionExists) SegmentIntersectionType result = GeomAid.SegmentIntersection(s1.ToSegRat2(), s2.ToSegRat2(), ref pointIntersection, ref segmentIntersection); if (result == SegmentIntersectionType.Point) { EventPoint newEventPoint = new EventPoint(null); newEventPoint.Position = pointIntersection; if (eventPoint.CompareTo(newEventPoint) < 0 && !eventQueue.ContainsKey(newEventPoint)) { LinkedList <Segment> upperList = new LinkedList <Segment>(); eventQueue.Add(new RBTreeMapNode <EventPoint, LinkedList <Segment> >(newEventPoint, upperList)); } } else if (result == SegmentIntersectionType.Segment) { throw new NotImplementedException("Didn't think this would ever happen?!"); } }
private void CreateFaces() { RBTreeMap <DCEL_HalfEdge, HalfEdgeData> halfEdgesData = new RBTreeMap <DCEL_HalfEdge, HalfEdgeData>(DCEL_Element.Compare); foreach (DCEL_HalfEdge halfEdge in outputSubdivision.HalfEdges.Keys) { halfEdgesData.Add(new RBTreeMapNode <DCEL_HalfEdge, HalfEdgeData>(halfEdge, new HalfEdgeData())); } RBTreeMap <DCEL_HalfEdge, CycleData> cyclesData = new RBTreeMap <DCEL_HalfEdge, CycleData>(DCEL_Element.Compare); List <bool> visited = outputSubdivision.HalfEdges.Keys.Select(e => false).ToList(); DCEL_Face unboundedFace = new DCEL_Face(); outputSubdivision.UnboundedFace = unboundedFace; outputSubdivision.Faces.Add(new RBTreeSetNode <DCEL_Face>(unboundedFace)); foreach (var halfEdgeNode in halfEdgesData.Nodes) { DCEL_HalfEdge halfEdge = halfEdgeNode.Key; if (halfEdgeNode.Value.Visited) { continue; } DCEL_HalfEdge cycle = halfEdge.CycleNext.Min((a, b) => a.Origin.CompareTo(b.Origin)); { cycle = cycle.CycleNext.Where(e => e.Origin == cycle.Origin).Max(AngleComparisonUpperList_HalfEdge(cycle.Origin.Position)); } CycleType cycleType = GetCycleType(cycle); if (cycleType == CycleType.Interior) { DCEL_Face interiorFace = new DCEL_Face(); outputSubdivision.Faces.Add(new RBTreeSetNode <DCEL_Face>(interiorFace)); interiorFace.OuterComponent = cycle; foreach (DCEL_HalfEdge cycleHalfEdge in cycle.CycleNext) { cycleHalfEdge.IncidentFace = interiorFace; } } cyclesData.Add(new RBTreeMapNode <DCEL_HalfEdge, CycleData>(cycle, new CycleData(cycleType))); foreach (DCEL_HalfEdge cycleHalfEdge in halfEdge.CycleNext) { HalfEdgeData data = halfEdgesData[cycleHalfEdge].Value; data.Cycle = cycle; } } foreach (var cycleNode in cyclesData.Nodes) { if (cycleNode.Value.CycleType == CycleType.Interior) { continue; } DCEL_HalfEdge cycle = cycleNode.Key; DCEL_HalfEdge leftPick = leftPicksMap[cycle.Origin].Value; if (leftPick == null) { unboundedFace.InnerComponents.AddLast(cycle); foreach (DCEL_HalfEdge cycleHalfEdge in cycle.CycleNext) { cycleHalfEdge.IncidentFace = unboundedFace; } continue; } DCEL_HalfEdge leftPickCycle = halfEdgesData[leftPick].Value.Cycle; CycleType leftPickCycleType = cyclesData[leftPickCycle].Value.CycleType; //if (leftPickCycleType == CycleType.Interior) //{ // leftPickCycle.IncidentFace.InnerComponents.AddLast(cycle); // foreach (DCEL_HalfEdge cycleHalfEdge in cycle.CycleNext) // cycleHalfEdge.IncidentFace = leftPickCycle.IncidentFace; //} cyclesData[leftPickCycle].Value.Children.Add(cycle); cycleNode.Value.IsRoot = false; } foreach (var cycleChildrenNode in cyclesData.Nodes) { if (!cycleChildrenNode.Value.IsRoot) { continue; } DCEL_HalfEdge parentCycle = cycleChildrenNode.Key; CycleType parentCycleType = cyclesData[parentCycle].Value.CycleType; DCEL_Face face = parentCycle.IncidentFace; List <DCEL_HalfEdge> childCycles = cycleChildrenNode.Value.Children; Stack <DCEL_HalfEdge> unattachedCycles = new Stack <DCEL_HalfEdge>(); foreach (DCEL_HalfEdge childCycle in childCycles) { unattachedCycles.Push(childCycle); } while (!unattachedCycles.IsEmpty()) { DCEL_HalfEdge exteriorCycle = unattachedCycles.Pop(); face.InnerComponents.AddLast(exteriorCycle); foreach (DCEL_HalfEdge exteriorCycleHalfEdge in exteriorCycle.CycleNext) { exteriorCycleHalfEdge.IncidentFace = face; } foreach (DCEL_HalfEdge child in cyclesData[exteriorCycle].Value.Children) { unattachedCycles.Push(child); } } } }
private void HandleIntersection_MergingPhase(OA_EventPoint eventPoint, List <OA_Segment> upperList, List <OA_Segment> middleList, List <OA_Segment> lowerList) { if (middleList.Count != 0) { throw new Exception("MergingPhase: Something went wrong in the SplittingPhase, because there is an intersection with nonempty middleList."); } //Dictionary<DCEL_Subdivision, DCEL_Vertex> vertexLookup = CreateSourceLookup(eventPoint); //DCEL_Vertex mergedVertex = vertexLookup.Values.First(); DCEL_Vertex mergedVertex = eventPoint.Source.First().Element; lowerList.Sort(AngleComparisonLowerList(mergedVertex.Position)); upperList.Sort(AngleComparisonUpperList(mergedVertex.Position)); //JoinNext all consecutive pairs around circle, and join origins to mergedVertex { //Outgoing half edges in CCW order List <DCEL_HalfEdge> bothList = new List <DCEL_HalfEdge>(); bothList.AddRange(lowerList.Select(segment => segment.Source.First().Element.Twin)); bothList.AddRange(upperList.Select(segment => segment.Source.First().Element)); if (bothList.Count > 1) { DCEL_HalfEdge e, e_next; for (int i = 1; i < bothList.Count; i++) { e = bothList[i].Twin; e_next = bothList[i - 1]; DCEL_Helper.JoinNext(e, e_next); } e = bothList.First().Twin; e_next = bothList.Last(); DCEL_Helper.JoinNext(e, e_next); } else { DCEL_HalfEdge e = bothList[0].Twin; DCEL_HalfEdge e_next = e.Twin; DCEL_Helper.JoinNext(e, e_next); } //Set the origins to the mergedVertex foreach (DCEL_HalfEdge e in bothList) { e.Origin = mergedVertex; } mergedVertex.IncidentEdge = bothList.First(); } outputSubdivision.Vertices.Add(new RBTreeSetNode <DCEL_Vertex>(mergedVertex)); foreach (OA_Segment upper in upperList) { DCEL_HalfEdge e = upper.Source.First().Element; outputSubdivision.HalfEdges.Add(new RBTreeSetNode <DCEL_HalfEdge>(e)); outputSubdivision.HalfEdges.Add(new RBTreeSetNode <DCEL_HalfEdge>(e.Twin)); //HACK?///////////////////////////////////////// e.IncidentFace = null; e.Twin.IncidentFace = null; //HACK?///////////////////////////////////////// } //Store the left pick for the mergedVertex if (eventPoint.LeftPick != null) { leftPicksMap.Add(new RBTreeMapNode <DCEL_Vertex, DCEL_HalfEdge>(mergedVertex, eventPoint.LeftPick.Source.First().Element)); } else { leftPicksMap.Add(new RBTreeMapNode <DCEL_Vertex, DCEL_HalfEdge>(mergedVertex, null)); } }