private void Initialize() { sweepline = new OA_Sweepline(); eventQueue = new RBTreeSet <OA_EventPoint>(OA_EventPoint.Compare); outputSubdivision = new DCEL_Subdivision(); foreach (DCEL_Subdivision inputSubdivision in inputSubdivisions) { foreach (DCEL_HalfEdge inputHalfEdge in inputSubdivision.HalfEdges.Keys) { OA_EventPoint upper = new OA_EventPoint(inputHalfEdge.Origin.Position); OA_EventPoint lower = new OA_EventPoint(inputHalfEdge.Destination.Position); //We want to take only one of the twins from every pair of half edges. if (upper.CompareTo(lower) > 0) { continue; } RBTreeSetNode <OA_EventPoint> upper_node = new RBTreeSetNode <OA_EventPoint>(upper); RBTreeSetNode <OA_EventPoint> lower_node = new RBTreeSetNode <OA_EventPoint>(lower); //If we didn't add the newly created event point, it already existed. if (!eventQueue.Add(ref upper_node)) { upper = upper_node.Key; } if (!eventQueue.Add(ref lower_node)) { lower = lower_node.Key; } OA_Segment segment = new OA_Segment(sweepline); segment.Source.Add(new OA_Source <DCEL_HalfEdge>(inputSubdivision, inputHalfEdge)); segment.Upper = upper; segment.Lower = lower; //***May be adding a duplicate if segment is in both subdivisions! upper.UpperList.Add(segment); if (!upper.Source.Any(OA_Source <DCEL_Vertex> .IsFrom(inputSubdivision))) { upper.Source.Add(new OA_Source <DCEL_Vertex>(inputSubdivision, inputHalfEdge.Origin)); } if (!lower.Source.Any(OA_Source <DCEL_Vertex> .IsFrom(inputSubdivision))) { lower.Source.Add(new OA_Source <DCEL_Vertex>(inputSubdivision, inputHalfEdge.Destination)); } } } foreach (OA_EventPoint eventPoint in eventQueue.Keys) { //***Remove those duplicates here, joining their source lists. eventPoint.UpperList.RemoveDuplicates(OA_Segment.CompareEndpoints, OA_Segment.JoinSource); } }
private void SetLeftPick(OA_EventPoint eventPoint) { RBTreeSetNode <OA_Segment> leftPick_node = sweepline.Status.FindMax(OA_Segment.IntersectsSweeplineLeftOfEventPointExclusive); if (leftPick_node != null) { eventPoint.LeftPick = leftPick_node.Key; } else { eventPoint.LeftPick = null; } }
private Dictionary <DCEL_Subdivision, DCEL_Vertex> CreateSourceLookup(OA_EventPoint eventPoint) { Dictionary <DCEL_Subdivision, DCEL_Vertex> sourceLookup = new Dictionary <DCEL_Subdivision, DCEL_Vertex>(2); foreach (OA_Source <DCEL_Vertex> source in eventPoint.Source) { sourceLookup.Add(source.Subdivision, source.Element); } foreach (DCEL_Subdivision inputSubdivision in inputSubdivisions) { if (!sourceLookup.ContainsKey(inputSubdivision)) { sourceLookup.Add(inputSubdivision, null); } } return(sourceLookup); }
private void HandleIntersection_SplittingPhase(OA_EventPoint eventPoint, List <OA_Segment> upperList, List <OA_Segment> middleList, List <OA_Segment> lowerList) { //if (upperList.Count() + middleList.Count() + lowerList.Count() <= 1) if (middleList.Count == 0) { return; } //If there are any subdivisions which don't have a vertex at this location, //then we will create one momentarily. For the moment, set the //(key, value) = (subdivision, null). Dictionary <DCEL_Subdivision, DCEL_Vertex> vertexLookup = CreateSourceLookup(eventPoint); //Make all segments meet at a vertex here, within each subdivision. //HalfEdges associated with segments in the middleList will be transformed //into HalfEdges associated with segments in the upperList. (With the associated //segments transforming as well.) foreach (OA_Segment middle in middleList) { foreach (OA_Source <DCEL_HalfEdge> source in middle.Source) { DCEL_Subdivision subdivision = source.Subdivision; DCEL_HalfEdge halfEdge = source.Element; DCEL_Vertex vertex = vertexLookup[subdivision]; //Create the vertex on-demand if it doesn't exist if (vertex == null) { vertex = new DCEL_Vertex(eventPoint.Position); vertexLookup[subdivision] = vertex; subdivision.Vertices.Add(new RBTreeSetNode <DCEL_Vertex>(vertex)); } SplitEdge(subdivision, halfEdge, vertex); if (!eventPoint.Source.Any(OA_Source <DCEL_Vertex> .IsFrom(subdivision))) { eventPoint.Source.Add(new OA_Source <DCEL_Vertex>(subdivision, vertex)); } } } }
public void SetEndpoints(OA_EventPoint a, OA_EventPoint b) { int comp = a.CompareTo(b); if (comp == 0) { throw new InvalidOperationException("Trivial line segment."); } if (comp < 0) { Upper = a; Lower = b; } else { Upper = b; Lower = a; } }
private void FindNewEventPoint(OA_Segment segment1, OA_Segment segment2, OA_EventPoint eventPoint) { VecRat2 pointIntersection = new VecRat2(); SegRat2 segmentIntersection = new SegRat2(); SegmentIntersectionType result = GeomAid.SegmentIntersection(segment1.ToSegRat2(), segment2.ToSegRat2(), ref pointIntersection, ref segmentIntersection); if (result == SegmentIntersectionType.Point) { OA_EventPoint newEventPoint = new OA_EventPoint(pointIntersection); if (eventPoint.CompareTo(newEventPoint) < 0) { //Add the new event point if it isn't already in the event queue eventQueue.Add(new RBTreeSetNode <OA_EventPoint>(newEventPoint)); } } else if (result == SegmentIntersectionType.Segment) { throw new NotImplementedException("Didn't think this would ever happen?!"); } }
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)); } }
private void HandleEventPoint(OA_EventPoint eventPoint) { AssertValidSweeplineStatus(); //Sweep to before the event point sweepline.IncidentEventPoint = eventPoint; sweepline.BeforeEventPoint = true; AssertValidSweeplineStatus(); if (phase == Phase.MergingPhase) { SetLeftPick(eventPoint); } //Determine all segments that contain the event point, and partition them List <OA_Segment> upperList = eventPoint.UpperList; List <OA_Segment> middleList; List <OA_Segment> lowerList; sweepline.Status .FindRange(OA_Segment.CompareSweeplineIntersectionToCurrentEventPoint).Select(node => node.Key) .Partition(OA_Segment.LowerIsCurrentEventPoint, out lowerList, out middleList); //upperList gets added, middleList gets reversed, lowerList gets removed EventPointTransition(upperList, middleList, lowerList); AssertValidSweeplineStatus(); switch (phase) { case Phase.SplittingPhase: HandleIntersection_SplittingPhase(eventPoint, upperList, middleList, lowerList); break; case Phase.MergingPhase: HandleIntersection_MergingPhase(eventPoint, upperList, middleList, lowerList); break; default: throw new Exception(); } AssertValidSweeplineStatus(); if (upperList.IsEmpty() && middleList.IsEmpty()) { RBTreeSetNode <OA_Segment> predecessorNode = sweepline.Status.FindMax(OA_Segment.IntersectsSweeplineLeftOfEventPointInclusive); RBTreeSetNode <OA_Segment> successorNode = sweepline.Status.FindMin(OA_Segment.IntersectsSweeplineRightOfEventPointInclusive); if (predecessorNode != null && successorNode != null) { FindNewEventPoint(predecessorNode.Key, successorNode.Key, eventPoint); } } else { var leftmostIntersectingNode = sweepline.Status.FindMin(OA_Segment.IntersectsSweeplineRightOfEventPointInclusive); var leftmostPredecessorNode = leftmostIntersectingNode.Predecessor; if (leftmostPredecessorNode != null) { FindNewEventPoint(leftmostPredecessorNode.Key, leftmostIntersectingNode.Key, eventPoint); } var rightmostIntersectingNode = sweepline.Status.FindMax(OA_Segment.IntersectsSweeplineLeftOfEventPointInclusive); var rightmostSuccessorNode = rightmostIntersectingNode.Successor; if (rightmostSuccessorNode != null) { FindNewEventPoint(rightmostIntersectingNode.Key, rightmostSuccessorNode.Key, eventPoint); } } }