示例#1
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();
        }
示例#2
0
        /// <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>
        protected IEnumerable <Face <TEdge, TFace> > ExportFaces(Func <Vec3, Vec3, Vec3, Vec3> centerCalculator,
                                                                 double scaleFactor)
        {
            // FIFO
            var queue = new Queue <QuadEdge <TEdge> >();

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

            // @TODO Make sure CyclingMerge compute a valide triangulation
            // Construct first face using Centroid because
            // triangulation is not necessary delaunay
            foreach (QuadEdge <TEdge> current in first.EdgesFrom(CCW:false))
            {
                if (current.Rot.Origin == null)
                {
                    current.Rot.Origin = Geometry.Centroid(Geometry.InvStereographicProjection(current.Origin),
                                                           Geometry.InvStereographicProjection(current.Destination),
                                                           Geometry.InvStereographicProjection(current.Oprev.Destination));
                    double invDistanceScaled = scaleFactor / current.Rot.Origin.Magnitude;
                    current.Rot.Origin *= invDistanceScaled;

                    // 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;
            }
            yield return(new Face <TEdge, TFace>(first, false, false));

            // 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(Geometry.InvStereographicProjection(current.Origin),
                                                                  Geometry.InvStereographicProjection(current.Destination),
                                                                  Geometry.InvStereographicProjection(current.Oprev.Destination));
                            double invDistanceScaled = scaleFactor / current.Rot.Origin.Magnitude;
                            current.Rot.Origin *= invDistanceScaled;

                            // 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;
                    }

                    yield return(new Face <TEdge, TFace>(edge, false, false));
                }
            }

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