Пример #1
0
        public int CheckSeg4Encroach(ref Osub testsubseg)
        {
            double num;
            Vertex vertex;
            Otri   otri    = new Otri();
            Osub   osub    = new Osub();
            int    num1    = 0;
            int    num2    = 0;
            Vertex vertex1 = testsubseg.Org();
            Vertex vertex2 = testsubseg.Dest();

            testsubseg.TriPivot(ref otri);
            if (otri.triangle != Mesh.dummytri)
            {
                num2++;
                vertex = otri.Apex();
                num    = (vertex1.x - vertex.x) * (vertex2.x - vertex.x) + (vertex1.y - vertex.y) * (vertex2.y - vertex.y);
                if (num < 0 && (this.behavior.ConformingDelaunay || num * num >= (2 * this.behavior.goodAngle - 1) * (2 * this.behavior.goodAngle - 1) * ((vertex1.x - vertex.x) * (vertex1.x - vertex.x) + (vertex1.y - vertex.y) * (vertex1.y - vertex.y)) * ((vertex2.x - vertex.x) * (vertex2.x - vertex.x) + (vertex2.y - vertex.y) * (vertex2.y - vertex.y))))
                {
                    num1 = 1;
                }
            }
            testsubseg.Sym(ref osub);
            osub.TriPivot(ref otri);
            if (otri.triangle != Mesh.dummytri)
            {
                num2++;
                vertex = otri.Apex();
                num    = (vertex1.x - vertex.x) * (vertex2.x - vertex.x) + (vertex1.y - vertex.y) * (vertex2.y - vertex.y);
                if (num < 0 && (this.behavior.ConformingDelaunay || num * num >= (2 * this.behavior.goodAngle - 1) * (2 * this.behavior.goodAngle - 1) * ((vertex1.x - vertex.x) * (vertex1.x - vertex.x) + (vertex1.y - vertex.y) * (vertex1.y - vertex.y)) * ((vertex2.x - vertex.x) * (vertex2.x - vertex.x) + (vertex2.y - vertex.y) * (vertex2.y - vertex.y))))
                {
                    num1 = num1 + 2;
                }
            }
            if (num1 > 0 && (this.behavior.NoBisect == 0 || this.behavior.NoBisect == 1 && num2 == 2))
            {
                BadSubseg badSubseg = new BadSubseg();
                if (num1 != 1)
                {
                    badSubseg.encsubseg  = osub;
                    badSubseg.subsegorg  = vertex2;
                    badSubseg.subsegdest = vertex1;
                }
                else
                {
                    badSubseg.encsubseg  = testsubseg;
                    badSubseg.subsegorg  = vertex1;
                    badSubseg.subsegdest = vertex2;
                }
                this.badsubsegs.Enqueue(badSubseg);
            }
            return(num1);
        }
        /// <summary>
        /// Tag all blind triangles.
        /// </summary>
        /// <remarks>
        /// A triangle is said to be blind if the triangle and its circumcenter
        /// lie on two different sides of a constrained edge.
        /// </remarks>
        private void TagBlindTriangles()
        {
            int blinded = 0;

            Stack <Triangle> triangles;

            subsegMap = new Dictionary <int, SubSegment>();

            Otri f    = default(Otri);
            Otri f0   = default(Otri);
            Osub e    = default(Osub);
            Osub sub1 = default(Osub);

            // Tag all triangles non-blind
            foreach (var t in _TriangleNetMesh.triangles)
            {
                // Use the infected flag for 'blinded' attribute.
                t.infected = false;
            }

            // for each constrained edge e of cdt do
            foreach (var ss in _TriangleNetMesh.subsegs.Values)
            {
                // Create a stack: triangles
                triangles = new Stack <Triangle>();

                // for both adjacent triangles fe to e tagged non-blind do
                // Push fe into triangles
                e.seg    = ss;
                e.orient = 0;
                e.Pivot(ref f);

                if (f.tri.id != TriangleNetMesh.DUMMY && !f.tri.infected)
                {
                    triangles.Push(f.tri);
                }

                e.Sym();
                e.Pivot(ref f);

                if (f.tri.id != TriangleNetMesh.DUMMY && !f.tri.infected)
                {
                    triangles.Push(f.tri);
                }

                // while triangles is non-empty
                while (triangles.Count > 0)
                {
                    // Pop f from stack triangles
                    f.tri    = triangles.Pop();
                    f.orient = 0;

                    // if f is blinded by e (use P) then
                    if (TriangleIsBlinded(ref f, ref e))
                    {
                        // Tag f as blinded by e
                        f.tri.infected = true;
                        blinded++;

                        // Store association triangle -> subseg
                        subsegMap.Add(f.tri.hash, e.seg);

                        // for each adjacent triangle f0 to f do
                        for (f.orient = 0; f.orient < 3; f.orient++)
                        {
                            f.Sym(ref f0);

                            f0.Pivot(ref sub1);

                            // if f0 is finite and tagged non-blind & the common edge
                            // between f and f0 is unconstrained then
                            if (f0.tri.id != TriangleNetMesh.DUMMY && !f0.tri.infected && sub1.seg.hash == TriangleNetMesh.DUMMY)
                            {
                                // Push f0 into triangles.
                                triangles.Push(f0.tri);
                            }
                        }
                    }
                }
            }

            blinded = 0;
        }
Пример #3
0
        /// <summary>
        /// Check a subsegment to see if it is encroached; add it to the list if it is.
        /// </summary>
        /// <param name="testsubseg">The subsegment to check.</param>
        /// <returns>Returns a nonzero value if the subsegment is encroached.</returns>
        /// <remarks>
        /// A subsegment is encroached if there is a vertex in its diametral lens.
        /// For Ruppert's algorithm (-D switch), the "diametral lens" is the
        /// diametral circle. For Chew's algorithm (default), the diametral lens is
        /// just big enough to enclose two isosceles triangles whose bases are the
        /// subsegment. Each of the two isosceles triangles has two angles equal
        /// to 'b.minangle'.
        ///
        /// Chew's algorithm does not require diametral lenses at all--but they save
        /// time. Any vertex inside a subsegment's diametral lens implies that the
        /// triangle adjoining the subsegment will be too skinny, so it's only a
        /// matter of time before the encroaching vertex is deleted by Chew's
        /// algorithm. It's faster to simply not insert the doomed vertex in the
        /// first place, which is why I use diametral lenses with Chew's algorithm.
        /// </remarks>
        public int CheckSeg4Encroach(ref Osub testsubseg)
        {
            Otri      neighbortri = default(Otri);
            Osub      testsym     = default(Osub);
            BadSubseg encroachedseg;
            float     dotproduct;
            int       encroached;
            int       sides;
            Vertex    eorg, edest, eapex;

            encroached = 0;
            sides      = 0;

            eorg  = testsubseg.Org();
            edest = testsubseg.Dest();
            // Check one neighbor of the subsegment.
            testsubseg.TriPivot(ref neighbortri);
            // Does the neighbor exist, or is this a boundary edge?
            if (neighbortri.triangle != Mesh.dummytri)
            {
                sides++;
                // Find a vertex opposite this subsegment.
                eapex = neighbortri.Apex();
                // Check whether the apex is in the diametral lens of the subsegment
                // (the diametral circle if 'conformdel' is set).  A dot product
                // of two sides of the triangle is used to check whether the angle
                // at the apex is greater than (180 - 2 'minangle') degrees (for
                // lenses; 90 degrees for diametral circles).
                dotproduct = (eorg.x - eapex.x) * (edest.x - eapex.x) +
                             (eorg.y - eapex.y) * (edest.y - eapex.y);
                if (dotproduct < 0.0)
                {
                    if (behavior.ConformingDelaunay ||
                        (dotproduct * dotproduct >=
                         (2.0 * behavior.goodAngle - 1.0) * (2.0 * behavior.goodAngle - 1.0) *
                         ((eorg.x - eapex.x) * (eorg.x - eapex.x) +
                          (eorg.y - eapex.y) * (eorg.y - eapex.y)) *
                         ((edest.x - eapex.x) * (edest.x - eapex.x) +
                          (edest.y - eapex.y) * (edest.y - eapex.y))))
                    {
                        encroached = 1;
                    }
                }
            }
            // Check the other neighbor of the subsegment.
            testsubseg.Sym(ref testsym);
            testsym.TriPivot(ref neighbortri);
            // Does the neighbor exist, or is this a boundary edge?
            if (neighbortri.triangle != Mesh.dummytri)
            {
                sides++;
                // Find the other vertex opposite this subsegment.
                eapex = neighbortri.Apex();
                // Check whether the apex is in the diametral lens of the subsegment
                // (or the diametral circle, if 'conformdel' is set).
                dotproduct = (eorg.x - eapex.x) * (edest.x - eapex.x) +
                             (eorg.y - eapex.y) * (edest.y - eapex.y);
                if (dotproduct < 0.0)
                {
                    if (behavior.ConformingDelaunay ||
                        (dotproduct * dotproduct >=
                         (2.0 * behavior.goodAngle - 1.0) * (2.0 * behavior.goodAngle - 1.0) *
                         ((eorg.x - eapex.x) * (eorg.x - eapex.x) +
                          (eorg.y - eapex.y) * (eorg.y - eapex.y)) *
                         ((edest.x - eapex.x) * (edest.x - eapex.x) +
                          (edest.y - eapex.y) * (edest.y - eapex.y))))
                    {
                        encroached += 2;
                    }
                }
            }

            if (encroached > 0 && (behavior.NoBisect == 0 || ((behavior.NoBisect == 1) && (sides == 2))))
            {
                // Add the subsegment to the list of encroached subsegments.
                // Be sure to get the orientation right.
                encroachedseg = new BadSubseg();
                if (encroached == 1)
                {
                    encroachedseg.encsubseg  = testsubseg;
                    encroachedseg.subsegorg  = eorg;
                    encroachedseg.subsegdest = edest;
                }
                else
                {
                    encroachedseg.encsubseg  = testsym;
                    encroachedseg.subsegorg  = edest;
                    encroachedseg.subsegdest = eorg;
                }

                badsubsegs.Enqueue(encroachedseg);
            }

            return(encroached);
        }
Пример #4
0
        /// <summary>
        ///     Find the intersection of an existing segment and a segment that is being
        ///     inserted. Insert a vertex at the intersection, splitting an existing subsegment.
        /// </summary>
        /// <param name="splittri"></param>
        /// <param name="splitsubseg"></param>
        /// <param name="endpoint2"></param>
        /// <remarks>
        ///     The segment being inserted connects the apex of splittri to endpoint2.
        ///     splitsubseg is the subsegment being split, and MUST adjoin splittri.
        ///     Hence, endpoints of the subsegment being split are the origin and
        ///     destination of splittri.
        ///     On completion, splittri is a handle having the newly inserted
        ///     intersection point as its origin, and endpoint1 as its destination.
        /// </remarks>
        private void SegmentIntersection(ref Otri splittri, ref Osub splitsubseg, Vertex endpoint2)
        {
            Osub               opposubseg = default(Osub);
            Vertex             endpoint1;
            Vertex             torg, tdest;
            Vertex             leftvertex, rightvertex;
            Vertex             newvertex;
            InsertVertexResult success;

            var dummysub = mesh.dummysub;

            double ex, ey;
            double tx, ty;
            double etx, ety;
            double split, denom;

            // Find the other three segment endpoints.
            endpoint1 = splittri.Apex();
            torg      = splittri.Org();
            tdest     = splittri.Dest();
            // Segment intersection formulae; see the Antonio reference.
            tx    = tdest.X - torg.X;
            ty    = tdest.Y - torg.Y;
            ex    = endpoint2.X - endpoint1.X;
            ey    = endpoint2.Y - endpoint1.Y;
            etx   = torg.X - endpoint2.X;
            ety   = torg.Y - endpoint2.Y;
            denom = ty * ex - tx * ey;
            if (denom == 0.0)
            {
                throw new Exception("Attempt to find intersection of parallel segments.");
            }
            split = (ey * etx - ex * ety) / denom;

            // Create the new vertex.
            newvertex = new Vertex(
                torg.X + split * (tdest.X - torg.X),
                torg.Y + split * (tdest.Y - torg.Y),
                splitsubseg.seg.boundary);

            newvertex.Id = mesh.hash_vtx++;

            mesh.vertices.Add(newvertex.Id, newvertex);

            // Insert the intersection vertex.  This should always succeed.
            success = mesh.InsertVertex(newvertex, ref splittri, ref splitsubseg, false, false);
            if (success != InsertVertexResult.Successful)
            {
                throw new Exception("Failure to split a segment.");
            }
            // Record a triangle whose origin is the new vertex.
            newvertex.tri = splittri;
            if (mesh.steinerleft > 0)
            {
                mesh.steinerleft--;
            }

            // Divide the segment into two, and correct the segment endpoints.
            splitsubseg.Sym();
            splitsubseg.Pivot(ref opposubseg);
            splitsubseg.Dissolve(dummysub);
            opposubseg.Dissolve(dummysub);
            do
            {
                splitsubseg.SetSegOrg(newvertex);
                splitsubseg.Next();
            } while (splitsubseg.seg.hash != Mesh.DUMMY);
            do
            {
                opposubseg.SetSegOrg(newvertex);
                opposubseg.Next();
            } while (opposubseg.seg.hash != Mesh.DUMMY);

            // Inserting the vertex may have caused edge flips.  We wish to rediscover
            // the edge connecting endpoint1 to the new intersection vertex.
            FindDirection(ref splittri, endpoint1);

            rightvertex = splittri.Dest();
            leftvertex  = splittri.Apex();
            if ((leftvertex.X == endpoint1.X) && (leftvertex.Y == endpoint1.Y))
            {
                splittri.Onext();
            }
            else if ((rightvertex.X != endpoint1.X) || (rightvertex.Y != endpoint1.Y))
            {
                throw new Exception("Topological inconsistency after splitting a segment.");
            }
            // 'splittri' should have destination endpoint1.
        }