Exemplo n.º 1
0
        // PROTECTED METHODS

        /// <summary>
        /// Merge left and right most edges together to construct a cycling triangulation.
        /// Needed for sphere for example after normal triangulation step.
        /// </summary>
        protected void CyclingMerge()
        {
            // @TODO Make sure CyclingMerge compute a valide triangulation
            QuadEdge <TEdge> baseEdge = _mesh.RightMostEdge.Rnext;
            QuadEdge <TEdge> lCand    = baseEdge.Sym.Onext;
            QuadEdge <TEdge> rCand    = baseEdge.Oprev;

            // Get edges CCW order from left extremum until reach right extremum
            // to complete the sphere triangulation
            // All edges must be stored first because pointer are updated
            // during construction and will eventually leads to infinite loop ...
            var toCheckEdge = rCand.LeftEdges(true).ToList();

            foreach (QuadEdge <TEdge> rightEdge in toCheckEdge)
            {
                if (rightEdge.Destination != lCand.Destination)
                {
                    // Connect rightEdge.Destination to baseEdge.Destination
                    // Construct a fan
                    baseEdge = QuadEdge <TEdge> .Connect(rightEdge, baseEdge.Sym);
                }
                else
                {
                    break;
                }
            }
        }
Exemplo n.º 2
0
        // PROTECTED METHOD

        /// <summary>
        /// Construct voronoi face based on Delaunay triangulation. Vertices at infinity
        /// are define based on radius parameter. It should be large enough to avoid
        /// some circumcenters (finite voronoi vertices) to be further on.
        /// </summary>
        /// <remarks>
        /// Each face is yield just after their construction. Then it's neighborhood
        /// is not guarantee to be constructed.
        /// </remarks>
        /// <param name="radius">Distance used to construct site that are at infinity.</param>
        protected IEnumerable <Face <TEdge, TFace> > ExportFaces(Func <Vec3, Vec3, Vec3, Vec3> centerCalculator,
                                                                 double radius)
        {
            // FIFO
            var queue = new Queue <QuadEdge <TEdge> >();

            // Start at the far left
            QuadEdge <TEdge> first = _mesh.LeftMostEdge;

            // @TODO Bounds
            List <QuadEdge <TEdge> > bounds = new List <QuadEdge <TEdge> >();


            // Visit all edge of the convex hull to compute dual vertices
            // at infinity by looping in a CW order over edges with same left face.
            foreach (QuadEdge <TEdge> hullEdge in first.LeftEdges(CCW:false))
            {
                // Construct a new face
                // First infinite voronoi vertex
                if (hullEdge.Rot.Destination == null)
                {
                    hullEdge.Rot.Destination = ConstructAtInfinity(hullEdge.Sym,
                                                                   radius,
                                                                   centerCalculator);
                }

                // Add other vertices by looping over hullEdge origin in CW order (Oprev)
                foreach (QuadEdge <TEdge> current in hullEdge.EdgesFrom(CCW:false))
                {
                    if (current.Rot.Origin == null)
                    {
                        // Delaunay edge on the boundary
                        if (Geometry.LeftOf(current.Oprev.Destination, current))
                        {
                            current.Rot.Origin = ConstructAtInfinity(current,
                                                                     radius,
                                                                     centerCalculator);
                        }
                        else
                        {
                            current.Rot.Origin = centerCalculator(current.Origin,
                                                                  current.Destination,
                                                                  current.Oprev.Destination);

                            // Speed up computation of point coordinates
                            // All edges sharing the same origin should have same
                            // geometrical origin
                            foreach (QuadEdge <TEdge> otherDual in current.Rot.EdgesFrom())
                            {
                                otherDual.Origin = current.Rot.Origin;
                            }
                        }
                    }

                    if (current.Sym.Tag == _mesh.VisitedTagState)
                    {
                        queue.Enqueue(current.Sym);
                        bounds.Add(current.Sym);
                    }
                    current.Tag = !_mesh.VisitedTagState;
                }

                // After face construction over
                yield return(new Face <TEdge, TFace>(hullEdge, true, true));
            }

            // Convex hull now closed --> Construct bounded voronoi faces
            while (queue.Count > 0)
            {
                QuadEdge <TEdge> edge = queue.Dequeue();

                if (edge.Tag == _mesh.VisitedTagState)
                {
                    // Construct a new face
                    foreach (QuadEdge <TEdge> current in edge.EdgesFrom(CCW:false))
                    {
                        if (current.Rot.Origin == null)
                        {
                            current.Rot.Origin = centerCalculator(current.Origin,
                                                                  current.Destination,
                                                                  current.Oprev.Destination);
                            // Speed up computation of point coordinates
                            // All edges sharing the same origin have same
                            // geometrical origin
                            foreach (QuadEdge <TEdge> otherDual in current.Rot.EdgesFrom())
                            {
                                otherDual.Origin = current.Rot.Origin;
                            }
                        }
                        if (current.Sym.Tag == _mesh.VisitedTagState)
                        {
                            queue.Enqueue(current.Sym);
                        }
                        current.Tag = !_mesh.VisitedTagState;
                    }

                    // After face construction over
                    if (bounds.Contains(edge))
                    {
                        yield return(new Face <TEdge, TFace>(edge, true, false));
                    }
                    else
                    {
                        yield return(new Face <TEdge, TFace>(edge, false, false));
                    }
                }
            }

            // Inverse flag to be able to traverse again at next call
            _mesh.SwitchInternalFlag();
        }