예제 #1
0
 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);
     }
 }
예제 #2
0
        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));
                    }
                }
            }
        }
예제 #3
0
        /// <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));
            }
        }
예제 #4
0
        /// <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;
        }
예제 #5
0
            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;
            }
예제 #6
0
 public DCEL_Vertex(VecRat2 position)
     : base()
 {
     Position     = position;
     IncidentEdge = null;
 }
예제 #7
0
        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);
                    }
                }
            }
        }
예제 #8
0
        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));
            }
        }
예제 #9
0
 public static void JoinIncidentEdge(DCEL_Vertex e_origin, DCEL_HalfEdge e)
 {
     e_origin.IncidentEdge = e;
     e.Origin = e_origin;
 }
예제 #10
0
 public static void JoinTwin(DCEL_HalfEdge e, DCEL_HalfEdge e_twin)
 {
     e.Twin      = e_twin;
     e_twin.Twin = e;
 }
예제 #11
0
 public static void JoinNext(DCEL_HalfEdge e, DCEL_HalfEdge e_next)
 {
     e.Next      = e_next;
     e_next.Prev = e;
 }
예제 #12
0
 public static void JoinPrevNext(DCEL_HalfEdge e_prev, DCEL_HalfEdge e, DCEL_HalfEdge e_next)
 {
     JoinNext(e_prev, e);
     JoinNext(e, e_next);
 }