private static CycleType GetCycleType(DCEL_HalfEdge cycle) { if (GeomAid.TurnTest(cycle.Prev.Origin.Position, cycle.Origin.Position, cycle.Destination.Position) > 0) { return(CycleType.Interior); } else { return(CycleType.Exterior); } }
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)); } } } }
/// <summary> /// halfEdge should be Upper->Lower so that the persistent half edges become: /// o halfEdge (Upper->Lower) ==> (vertex->Lower) /// o halfEdge.Twin (Lower->Upper) ==> (Lower->vertex) /// And the two newly created half edges are (vertex->Upper) and (Upper->vertex). /// </summary> private static void SplitEdge(DCEL_Subdivision subdivision, DCEL_HalfEdge halfEdge, DCEL_Vertex vertex) { Debug.Assert(VecRat2.CompareReadingOrder(halfEdge.Origin.Position, halfEdge.Destination.Position) < 0); DCEL_HalfEdge e1 = halfEdge; DCEL_HalfEdge e2 = e1.Twin; DCEL_HalfEdge e1_prev = e1.Prev; DCEL_HalfEdge e2_next = e2.Next; DCEL_Vertex e1_origin = e1.Origin; DCEL_HalfEdge e1_top = new DCEL_HalfEdge(); DCEL_HalfEdge e2_top = new DCEL_HalfEdge(); DCEL_Helper.JoinTwin(e1_top, e2_top); e1_top.IncidentFace = e1.IncidentFace; e2_top.IncidentFace = e2.IncidentFace; DCEL_Helper.JoinIncidentEdge(vertex, e2_top); DCEL_Helper.JoinIncidentEdge(vertex, e1); DCEL_Helper.JoinIncidentEdge(e1_origin, e1_top); if (e2_next == e1) { DCEL_Helper.JoinNext(e2, e2_top); DCEL_Helper.JoinNext(e2_top, e1_top); DCEL_Helper.JoinNext(e1_top, e1); } else { DCEL_Helper.JoinPrevNext(e2, e2_top, e2_next); DCEL_Helper.JoinPrevNext(e1_prev, e1_top, e1); } if (subdivision != null) { subdivision.HalfEdges.Add(new RBTreeSetNode <DCEL_HalfEdge>(e1_top)); subdivision.HalfEdges.Add(new RBTreeSetNode <DCEL_HalfEdge>(e2_top)); } }
/// <summary> /// Create a subdivision from a single segment (u, v). /// </summary> public DCEL_Subdivision(VecRat2 u, VecRat2 v) : this() { if (u == v) { throw new Exception("Tried to create a DCELSubdivision with a segment of length 0."); } DCEL_Vertex vertex_u = new DCEL_Vertex(u); DCEL_Vertex vertex_v = new DCEL_Vertex(v); DCEL_HalfEdge halfedge_uv = new DCEL_HalfEdge(); DCEL_HalfEdge halfedge_vu = new DCEL_HalfEdge(); DCEL_Face face = new DCEL_Face(); vertex_u.IncidentEdge = halfedge_uv; vertex_v.IncidentEdge = halfedge_vu; halfedge_uv.Origin = vertex_u; halfedge_uv.Twin = halfedge_vu; halfedge_uv.IncidentFace = face; halfedge_uv.Prev = halfedge_vu; halfedge_uv.Next = halfedge_vu; halfedge_vu.Origin = vertex_v; halfedge_vu.Twin = halfedge_uv; halfedge_vu.IncidentFace = face; halfedge_vu.Prev = halfedge_uv; halfedge_vu.Next = halfedge_uv; face.InnerComponents.AddLast(halfedge_uv); Vertices.Add(new RBTreeSetNode <DCEL_Vertex>(vertex_u)); Vertices.Add(new RBTreeSetNode <DCEL_Vertex>(vertex_u)); HalfEdges.Add(new RBTreeSetNode <DCEL_HalfEdge>(halfedge_uv)); HalfEdges.Add(new RBTreeSetNode <DCEL_HalfEdge>(halfedge_vu)); Faces.Add(new RBTreeSetNode <DCEL_Face>(face)); UnboundedFace = face; }
public Segment(DCEL_HalfEdge source, Sweepline sweepline) { Source = source; EventPoint origin = new EventPoint(source.Origin); EventPoint destination = new EventPoint(source.Destination); int comp = origin.CompareTo(destination); if (comp < 0) { Upper = origin; Lower = destination; } else if (comp > 0) { Upper = destination; Lower = origin; } else { throw new InvalidOperationException("Trivial line segment."); } Sweepline = sweepline; }
public DCEL_Vertex(VecRat2 position) : base() { Position = position; IncidentEdge = null; }
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)); } }
public static void JoinIncidentEdge(DCEL_Vertex e_origin, DCEL_HalfEdge e) { e_origin.IncidentEdge = e; e.Origin = e_origin; }
public static void JoinTwin(DCEL_HalfEdge e, DCEL_HalfEdge e_twin) { e.Twin = e_twin; e_twin.Twin = e; }
public static void JoinNext(DCEL_HalfEdge e, DCEL_HalfEdge e_next) { e.Next = e_next; e_next.Prev = e; }
public static void JoinPrevNext(DCEL_HalfEdge e_prev, DCEL_HalfEdge e, DCEL_HalfEdge e_next) { JoinNext(e_prev, e); JoinNext(e, e_next); }