Ejemplo n.º 1
0
        /// <summary>
        /// TessellateMonoRegion( face ) tessellates a monotone region
        /// (what else would it do??)  The region must consist of a single
        /// loop of half-edges (see mesh.h) oriented CCW.  "Monotone" in this
        /// case means that any vertical line intersects the interior of the
        /// region in a single interval.
        ///
        /// Tessellation consists of adding interior edges (actually pairs of
        /// half-edges), to split the region into non-overlapping triangles.
        ///
        /// The basic idea is explained in Preparata and Shamos (which I don't
        /// have handy right now), although their implementation is more
        /// complicated than this one.  The are two edge chains, an upper chain
        /// and a lower chain.  We process all vertices from both chains in order,
        /// from right to left.
        ///
        /// The algorithm ensures that the following invariant holds after each
        /// vertex is processed: the untessellated region consists of two
        /// chains, where one chain (say the upper) is a single edge, and
        /// the other chain is concave.  The left vertex of the single edge
        /// is always to the left of all vertices in the concave chain.
        ///
        /// Each step consists of adding the rightmost unprocessed vertex to one
        /// of the two chains, and forming a fan of triangles from the rightmost
        /// of two chain endpoints.  Determining whether we can add each triangle
        /// to the fan is a simple orientation test.  By making the fan as large
        /// as possible, we restore the invariant (check it yourself).
        /// </summary>
        private void TessellateMonoRegion(MeshUtils.Face face)
        {
            // All edges are oriented CCW around the boundary of the region.
            // First, find the half-edge whose origin vertex is rightmost.
            // Since the sweep goes from left to right, face->anEdge should
            // be close to the edge we want.
            var up = face._anEdge;

            Debug.Assert(up._Lnext != up && up._Lnext._Lnext != up);

            for (; Geom.VertLeq(up.Dst, up._Org); up = up.Lprev)
            {
            }
            for (; Geom.VertLeq(up._Org, up.Dst); up = up._Lnext)
            {
            }

            var lo = up.Lprev;

            while (up._Lnext != lo)
            {
                if (Geom.VertLeq(up.Dst, lo._Org))
                {
                    // up.Dst is on the left. It is safe to form triangles from lo.Org.
                    // The EdgeGoesLeft test guarantees progress even when some triangles
                    // are CW, given that the upper and lower chains are truly monotone.
                    while (lo._Lnext != up && (Geom.EdgeGoesLeft(lo._Lnext) ||
                                               Geom.EdgeSign(lo._Org, lo.Dst, lo._Lnext.Dst) <= 0.0f))
                    {
                        lo = _mesh.Connect(lo._Lnext, lo)._Sym;
                    }
                    lo = lo.Lprev;
                }
                else
                {
                    // lo.Org is on the left.  We can make CCW triangles from up.Dst.
                    while (lo._Lnext != up && (Geom.EdgeGoesRight(up.Lprev) ||
                                               Geom.EdgeSign(up.Dst, up._Org, up.Lprev._Org) >= 0.0f))
                    {
                        up = _mesh.Connect(up, up.Lprev)._Sym;
                    }
                    up = up._Lnext;
                }
            }

            // Now lo.Org == up.Dst == the leftmost vertex.  The remaining region
            // can be tessellated in a fan from this leftmost vertex.
            Debug.Assert(lo._Lnext != up);
            while (lo._Lnext._Lnext != up)
            {
                lo = _mesh.Connect(lo._Lnext, lo)._Sym;
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Destroys a face and removes it from the global face list. All edges of
        /// fZap will have a NULL pointer as their left face. Any edges which
        /// also have a NULL pointer as their right face are deleted entirely
        /// (along with any isolated vertices this produces).
        /// An entire mesh can be deleted by zapping its faces, one at a time,
        /// in any order. Zapped faces cannot be used in further mesh operations!
        /// </summary>
        public void ZapFace(MeshUtils.Face fZap)
        {
            var eStart = fZap._anEdge;

            // walk around face, deleting edges whose right face is also NULL
            var eNext = eStart._Lnext;

            MeshUtils.Edge e, eSym;
            do
            {
                e     = eNext;
                eNext = e._Lnext;

                e._Lface = null;
                if (e.Rface == null)
                {
                    // delete the edge -- see TESSmeshDelete above

                    if (e._Onext == e)
                    {
                        MeshUtils.KillVertex(e._Org, null);
                    }
                    else
                    {
                        // Make sure that e._Org points to a valid half-edge
                        e._Org._anEdge = e._Onext;
                        MeshUtils.Splice(e, e.Oprev);
                    }
                    eSym = e._Sym;
                    if (eSym._Onext == eSym)
                    {
                        MeshUtils.KillVertex(eSym._Org, null);
                    }
                    else
                    {
                        // Make sure that eSym._Org points to a valid half-edge
                        eSym._Org._anEdge = eSym._Onext;
                        MeshUtils.Splice(eSym, eSym.Oprev);
                    }
                    MeshUtils.KillEdge(e);
                }
            } while (e != eStart);

            /* delete from circular doubly-linked list */
            var fPrev = fZap._prev;
            var fNext = fZap._next;

            fNext._prev = fPrev;
            fPrev._next = fNext;
        }
Ejemplo n.º 3
0
// ReSharper restore InconsistentNaming
        public Mesh()
        {
            var v = _vHead = new MeshUtils.Vertex();
            var f = _fHead = new MeshUtils.Face();

            var pair = MeshUtils.EdgePair.Create();
            var e    = _eHead = pair._e;
            var eSym = _eHeadSym = pair._eSym;

            v._next   = v._prev = v;
            v._anEdge = null;

            f._next   = f._prev = f;
            f._anEdge = null;
            f._trail  = null;
            f._marked = false;
            f._inside = false;

            e._next         = e;
            e._Sym          = eSym;
            e._Onext        = null;
            e._Lnext        = null;
            e._Org          = null;
            e._Lface        = null;
            e._winding      = 0;
            e._activeRegion = null;

            eSym._next         = eSym;
            eSym._Sym          = e;
            eSym._Onext        = null;
            eSym._Lnext        = null;
            eSym._Org          = null;
            eSym._Lface        = null;
            eSym._winding      = 0;
            eSym._activeRegion = null;
        }