예제 #1
0
        private int RemoveGhosts(ref Otri startghost)
        {
            Otri otri  = new Otri();
            Otri otri1 = new Otri();
            Otri otri2 = new Otri();
            bool poly  = !this.mesh.behavior.Poly;

            startghost.Lprev(ref otri);
            otri.SymSelf();
            Mesh.dummytri.neighbors[0] = otri;
            startghost.Copy(ref otri1);
            int num = 0;

            do
            {
                num++;
                otri1.Lnext(ref otri2);
                otri1.LprevSelf();
                otri1.SymSelf();
                if (poly && otri1.triangle != Mesh.dummytri)
                {
                    Vertex vertex = otri1.Org();
                    if (vertex.mark == 0)
                    {
                        vertex.mark = 1;
                    }
                }
                otri1.Dissolve();
                otri2.Sym(ref otri1);
                this.mesh.TriangleDealloc(otri2.triangle);
            }while (!otri1.Equal(startghost));
            return(num);
        }
예제 #2
0
        private int RemoveBox()
        {
            Otri otri  = new Otri();
            Otri otri1 = new Otri();
            Otri otri2 = new Otri();
            Otri otri3 = new Otri();
            Otri otri4 = new Otri();
            Otri otri5 = new Otri();
            bool poly  = !this.mesh.behavior.Poly;

            otri3.triangle = Mesh.dummytri;
            otri3.orient   = 0;
            otri3.SymSelf();
            otri3.Lprev(ref otri4);
            otri3.LnextSelf();
            otri3.SymSelf();
            otri3.Lprev(ref otri1);
            otri1.SymSelf();
            otri3.Lnext(ref otri2);
            otri2.SymSelf();
            if (otri2.triangle == Mesh.dummytri)
            {
                otri1.LprevSelf();
                otri1.SymSelf();
            }
            Mesh.dummytri.neighbors[0] = otri1;
            int num = -2;

            while (!otri3.Equal(otri4))
            {
                num++;
                otri3.Lprev(ref otri5);
                otri5.SymSelf();
                if (poly && otri5.triangle != Mesh.dummytri)
                {
                    Vertex vertex = otri5.Org();
                    if (vertex.mark == 0)
                    {
                        vertex.mark = 1;
                    }
                }
                otri5.Dissolve();
                otri3.Lnext(ref otri);
                otri.Sym(ref otri3);
                this.mesh.TriangleDealloc(otri.triangle);
                if (otri3.triangle != Mesh.dummytri)
                {
                    continue;
                }
                otri5.Copy(ref otri3);
            }
            this.mesh.TriangleDealloc(otri4.triangle);
            return(num);
        }
        /// <summary>
        /// Removes ghost triangles.
        /// </summary>
        /// <param name="startghost"></param>
        /// <returns>Number of vertices on the hull.</returns>
        int RemoveGhosts(ref Otri startghost)
        {
            Otri   searchedge   = default(Otri);
            Otri   dissolveedge = default(Otri);
            Otri   deadtriangle = default(Otri);
            Vertex markorg;

            int hullsize;

            bool noPoly = !mesh.behavior.Poly;

            // Find an edge on the convex hull to start point location from.
            startghost.Lprev(ref searchedge);
            searchedge.SymSelf();
            Mesh.dummytri.neighbors[0] = searchedge;
            // Remove the bounding box and count the convex hull edges.
            startghost.Copy(ref dissolveedge);
            hullsize = 0;
            do
            {
                hullsize++;
                dissolveedge.Lnext(ref deadtriangle);
                dissolveedge.LprevSelf();
                dissolveedge.SymSelf();

                // If no PSLG is involved, set the boundary markers of all the vertices
                // on the convex hull.  If a PSLG is used, this step is done later.
                if (noPoly)
                {
                    // Watch out for the case where all the input vertices are collinear.
                    if (dissolveedge.triangle != Mesh.dummytri)
                    {
                        markorg = dissolveedge.Org();
                        if (markorg.mark == 0)
                        {
                            markorg.mark = 1;
                        }
                    }
                }

                // Remove a bounding triangle from a convex hull triangle.
                dissolveedge.Dissolve();
                // Find the next bounding triangle.
                deadtriangle.Sym(ref dissolveedge);

                // Delete the bounding triangle.
                mesh.TriangleDealloc(deadtriangle.triangle);
            } while (!dissolveedge.Equal(startghost));

            return(hullsize);
        }
예제 #4
0
        /// <summary>
        /// Recursively form a Delaunay triangulation by the divide-and-conquer method.
        /// </summary>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <param name="axis"></param>
        /// <param name="farleft"></param>
        /// <param name="farright"></param>
        /// <remarks>
        /// Recursively breaks down the problem into smaller pieces, which are
        /// knitted together by mergehulls(). The base cases (problems of two or
        /// three vertices) are handled specially here.
        ///
        /// On completion, 'farleft' and 'farright' are bounding triangles such that
        /// the origin of 'farleft' is the leftmost vertex (breaking ties by
        /// choosing the highest leftmost vertex), and the destination of
        /// 'farright' is the rightmost vertex (breaking ties by choosing the
        /// lowest rightmost vertex).
        /// </remarks>
        void DivconqRecurse(int left, int right, int axis,
                            ref Otri farleft, ref Otri farright)
        {
            Otri   midtri = default(Otri);
            Otri   tri1 = default(Otri);
            Otri   tri2 = default(Otri);
            Otri   tri3 = default(Otri);
            Otri   innerleft = default(Otri), innerright = default(Otri);
            double area;
            int    vertices = right - left + 1;
            int    divider;

            if (vertices == 2)
            {
                // The triangulation of two vertices is an edge.  An edge is
                // represented by two bounding triangles.
                mesh.MakeTriangle(ref farleft);
                farleft.SetOrg(sortarray[left]);
                farleft.SetDest(sortarray[left + 1]);
                // The apex is intentionally left NULL.
                mesh.MakeTriangle(ref farright);
                farright.SetOrg(sortarray[left + 1]);
                farright.SetDest(sortarray[left]);
                // The apex is intentionally left NULL.
                farleft.Bond(ref farright);
                farleft.LprevSelf();
                farright.LnextSelf();
                farleft.Bond(ref farright);
                farleft.LprevSelf();
                farright.LnextSelf();
                farleft.Bond(ref farright);

                // Ensure that the origin of 'farleft' is sortarray[0].
                farright.Lprev(ref farleft);
                return;
            }
            else if (vertices == 3)
            {
                // The triangulation of three vertices is either a triangle (with
                // three bounding triangles) or two edges (with four bounding
                // triangles).  In either case, four triangles are created.
                mesh.MakeTriangle(ref midtri);
                mesh.MakeTriangle(ref tri1);
                mesh.MakeTriangle(ref tri2);
                mesh.MakeTriangle(ref tri3);
                area = Primitives.CounterClockwise(sortarray[left], sortarray[left + 1], sortarray[left + 2]);
                if (area == 0.0)
                {
                    // Three collinear vertices; the triangulation is two edges.
                    midtri.SetOrg(sortarray[left]);
                    midtri.SetDest(sortarray[left + 1]);
                    tri1.SetOrg(sortarray[left + 1]);
                    tri1.SetDest(sortarray[left]);
                    tri2.SetOrg(sortarray[left + 2]);
                    tri2.SetDest(sortarray[left + 1]);
                    tri3.SetOrg(sortarray[left + 1]);
                    tri3.SetDest(sortarray[left + 2]);
                    // All apices are intentionally left NULL.
                    midtri.Bond(ref tri1);
                    tri2.Bond(ref tri3);
                    midtri.LnextSelf();
                    tri1.LprevSelf();
                    tri2.LnextSelf();
                    tri3.LprevSelf();
                    midtri.Bond(ref tri3);
                    tri1.Bond(ref tri2);
                    midtri.LnextSelf();
                    tri1.LprevSelf();
                    tri2.LnextSelf();
                    tri3.LprevSelf();
                    midtri.Bond(ref tri1);
                    tri2.Bond(ref tri3);
                    // Ensure that the origin of 'farleft' is sortarray[0].
                    tri1.Copy(ref farleft);
                    // Ensure that the destination of 'farright' is sortarray[2].
                    tri2.Copy(ref farright);
                }
                else
                {
                    // The three vertices are not collinear; the triangulation is one
                    // triangle, namely 'midtri'.
                    midtri.SetOrg(sortarray[left]);
                    tri1.SetDest(sortarray[left]);
                    tri3.SetOrg(sortarray[left]);
                    // Apices of tri1, tri2, and tri3 are left NULL.
                    if (area > 0.0)
                    {
                        // The vertices are in counterclockwise order.
                        midtri.SetDest(sortarray[left + 1]);
                        tri1.SetOrg(sortarray[left + 1]);
                        tri2.SetDest(sortarray[left + 1]);
                        midtri.SetApex(sortarray[left + 2]);
                        tri2.SetOrg(sortarray[left + 2]);
                        tri3.SetDest(sortarray[left + 2]);
                    }
                    else
                    {
                        // The vertices are in clockwise order.
                        midtri.SetDest(sortarray[left + 2]);
                        tri1.SetOrg(sortarray[left + 2]);
                        tri2.SetDest(sortarray[left + 2]);
                        midtri.SetApex(sortarray[left + 1]);
                        tri2.SetOrg(sortarray[left + 1]);
                        tri3.SetDest(sortarray[left + 1]);
                    }
                    // The topology does not depend on how the vertices are ordered.
                    midtri.Bond(ref tri1);
                    midtri.LnextSelf();
                    midtri.Bond(ref tri2);
                    midtri.LnextSelf();
                    midtri.Bond(ref tri3);
                    tri1.LprevSelf();
                    tri2.LnextSelf();
                    tri1.Bond(ref tri2);
                    tri1.LprevSelf();
                    tri3.LprevSelf();
                    tri1.Bond(ref tri3);
                    tri2.LnextSelf();
                    tri3.LprevSelf();
                    tri2.Bond(ref tri3);
                    // Ensure that the origin of 'farleft' is sortarray[0].
                    tri1.Copy(ref farleft);
                    // Ensure that the destination of 'farright' is sortarray[2].
                    if (area > 0.0)
                    {
                        tri2.Copy(ref farright);
                    }
                    else
                    {
                        farleft.Lnext(ref farright);
                    }
                }

                return;
            }
            else
            {
                // Split the vertices in half.
                divider = vertices >> 1;
                // Recursively triangulate each half.
                DivconqRecurse(left, left + divider - 1, 1 - axis, ref farleft, ref innerleft);
                //DebugWriter.Session.Write(mesh, true);
                DivconqRecurse(left + divider, right, 1 - axis, ref innerright, ref farright);
                //DebugWriter.Session.Write(mesh, true);

                // Merge the two triangulations into one.
                MergeHulls(ref farleft, ref innerleft, ref innerright, ref farright, axis);
                //DebugWriter.Session.Write(mesh, true);
            }
        }
예제 #5
0
        /// <summary>
        /// Merge two adjacent Delaunay triangulations into a single Delaunay triangulation.
        /// </summary>
        /// <param name="farleft">Bounding triangles of the left triangulation.</param>
        /// <param name="innerleft">Bounding triangles of the left triangulation.</param>
        /// <param name="innerright">Bounding triangles of the right triangulation.</param>
        /// <param name="farright">Bounding triangles of the right triangulation.</param>
        /// <param name="axis"></param>
        /// <remarks>
        /// This is similar to the algorithm given by Guibas and Stolfi, but uses
        /// a triangle-based, rather than edge-based, data structure.
        ///
        /// The algorithm walks up the gap between the two triangulations, knitting
        /// them together.  As they are merged, some of their bounding triangles
        /// are converted into real triangles of the triangulation.  The procedure
        /// pulls each hull's bounding triangles apart, then knits them together
        /// like the teeth of two gears.  The Delaunay property determines, at each
        /// step, whether the next "tooth" is a bounding triangle of the left hull
        /// or the right.  When a bounding triangle becomes real, its apex is
        /// changed from NULL to a real vertex.
        ///
        /// Only two new triangles need to be allocated.  These become new bounding
        /// triangles at the top and bottom of the seam.  They are used to connect
        /// the remaining bounding triangles (those that have not been converted
        /// into real triangles) into a single fan.
        ///
        /// On entry, 'farleft' and 'innerleft' are bounding triangles of the left
        /// triangulation.  The origin of 'farleft' is the leftmost vertex, and
        /// the destination of 'innerleft' is the rightmost vertex of the
        /// triangulation.  Similarly, 'innerright' and 'farright' are bounding
        /// triangles of the right triangulation.  The origin of 'innerright' and
        /// destination of 'farright' are the leftmost and rightmost vertices.
        ///
        /// On completion, the origin of 'farleft' is the leftmost vertex of the
        /// merged triangulation, and the destination of 'farright' is the rightmost
        /// vertex.
        /// </remarks>
        void MergeHulls(ref Otri farleft, ref Otri innerleft, ref Otri innerright,
                        ref Otri farright, int axis)
        {
            Otri   leftcand = default(Otri), rightcand = default(Otri);
            Otri   nextedge = default(Otri);
            Otri   sidecasing = default(Otri), topcasing = default(Otri), outercasing = default(Otri);
            Otri   checkedge = default(Otri);
            Otri   baseedge  = default(Otri);
            Vertex innerleftdest;
            Vertex innerrightorg;
            Vertex innerleftapex, innerrightapex;
            Vertex farleftpt, farrightpt;
            Vertex farleftapex, farrightapex;
            Vertex lowerleft, lowerright;
            Vertex upperleft, upperright;
            Vertex nextapex;
            Vertex checkvertex;
            bool   changemade;
            bool   badedge;
            bool   leftfinished, rightfinished;

            innerleftdest  = innerleft.Dest();
            innerleftapex  = innerleft.Apex();
            innerrightorg  = innerright.Org();
            innerrightapex = innerright.Apex();
            // Special treatment for horizontal cuts.
            if (useDwyer && (axis == 1))
            {
                farleftpt    = farleft.Org();
                farleftapex  = farleft.Apex();
                farrightpt   = farright.Dest();
                farrightapex = farright.Apex();
                // The pointers to the extremal vertices are shifted to point to the
                // topmost and bottommost vertex of each hull, rather than the
                // leftmost and rightmost vertices.
                while (farleftapex.y < farleftpt.y)
                {
                    farleft.LnextSelf();
                    farleft.SymSelf();
                    farleftpt   = farleftapex;
                    farleftapex = farleft.Apex();
                }
                innerleft.Sym(ref checkedge);
                checkvertex = checkedge.Apex();
                while (checkvertex.y > innerleftdest.y)
                {
                    checkedge.Lnext(ref innerleft);
                    innerleftapex = innerleftdest;
                    innerleftdest = checkvertex;
                    innerleft.Sym(ref checkedge);
                    checkvertex = checkedge.Apex();
                }
                while (innerrightapex.y < innerrightorg.y)
                {
                    innerright.LnextSelf();
                    innerright.SymSelf();
                    innerrightorg  = innerrightapex;
                    innerrightapex = innerright.Apex();
                }
                farright.Sym(ref checkedge);
                checkvertex = checkedge.Apex();
                while (checkvertex.y > farrightpt.y)
                {
                    checkedge.Lnext(ref farright);
                    farrightapex = farrightpt;
                    farrightpt   = checkvertex;
                    farright.Sym(ref checkedge);
                    checkvertex = checkedge.Apex();
                }
            }
            // Find a line tangent to and below both hulls.
            do
            {
                changemade = false;
                // Make innerleftdest the "bottommost" vertex of the left hull.
                if (Primitives.CounterClockwise(innerleftdest, innerleftapex, innerrightorg) > 0.0)
                {
                    innerleft.LprevSelf();
                    innerleft.SymSelf();
                    innerleftdest = innerleftapex;
                    innerleftapex = innerleft.Apex();
                    changemade    = true;
                }
                // Make innerrightorg the "bottommost" vertex of the right hull.
                if (Primitives.CounterClockwise(innerrightapex, innerrightorg, innerleftdest) > 0.0)
                {
                    innerright.LnextSelf();
                    innerright.SymSelf();
                    innerrightorg  = innerrightapex;
                    innerrightapex = innerright.Apex();
                    changemade     = true;
                }
            } while (changemade);

            // Find the two candidates to be the next "gear tooth."
            innerleft.Sym(ref leftcand);
            innerright.Sym(ref rightcand);
            // Create the bottom new bounding triangle.
            mesh.MakeTriangle(ref baseedge);
            // Connect it to the bounding boxes of the left and right triangulations.
            baseedge.Bond(ref innerleft);
            baseedge.LnextSelf();
            baseedge.Bond(ref innerright);
            baseedge.LnextSelf();
            baseedge.SetOrg(innerrightorg);
            baseedge.SetDest(innerleftdest);
            // Apex is intentionally left NULL.

            // Fix the extreme triangles if necessary.
            farleftpt = farleft.Org();
            if (innerleftdest == farleftpt)
            {
                baseedge.Lnext(ref farleft);
            }
            farrightpt = farright.Dest();
            if (innerrightorg == farrightpt)
            {
                baseedge.Lprev(ref farright);
            }
            // The vertices of the current knitting edge.
            lowerleft  = innerleftdest;
            lowerright = innerrightorg;
            // The candidate vertices for knitting.
            upperleft  = leftcand.Apex();
            upperright = rightcand.Apex();
            // Walk up the gap between the two triangulations, knitting them together.
            while (true)
            {
                // Have we reached the top? (This isn't quite the right question,
                // because even though the left triangulation might seem finished now,
                // moving up on the right triangulation might reveal a new vertex of
                // the left triangulation. And vice-versa.)
                leftfinished  = Primitives.CounterClockwise(upperleft, lowerleft, lowerright) <= 0.0;
                rightfinished = Primitives.CounterClockwise(upperright, lowerleft, lowerright) <= 0.0;
                if (leftfinished && rightfinished)
                {
                    // Create the top new bounding triangle.
                    mesh.MakeTriangle(ref nextedge);
                    nextedge.SetOrg(lowerleft);
                    nextedge.SetDest(lowerright);
                    // Apex is intentionally left NULL.
                    // Connect it to the bounding boxes of the two triangulations.
                    nextedge.Bond(ref baseedge);
                    nextedge.LnextSelf();
                    nextedge.Bond(ref rightcand);
                    nextedge.LnextSelf();
                    nextedge.Bond(ref leftcand);

                    // Special treatment for horizontal cuts.
                    if (useDwyer && (axis == 1))
                    {
                        farleftpt    = farleft.Org();
                        farleftapex  = farleft.Apex();
                        farrightpt   = farright.Dest();
                        farrightapex = farright.Apex();
                        farleft.Sym(ref checkedge);
                        checkvertex = checkedge.Apex();
                        // The pointers to the extremal vertices are restored to the
                        // leftmost and rightmost vertices (rather than topmost and
                        // bottommost).
                        while (checkvertex.x < farleftpt.x)
                        {
                            checkedge.Lprev(ref farleft);
                            farleftapex = farleftpt;
                            farleftpt   = checkvertex;
                            farleft.Sym(ref checkedge);
                            checkvertex = checkedge.Apex();
                        }
                        while (farrightapex.x > farrightpt.x)
                        {
                            farright.LprevSelf();
                            farright.SymSelf();
                            farrightpt   = farrightapex;
                            farrightapex = farright.Apex();
                        }
                    }
                    return;
                }
                // Consider eliminating edges from the left triangulation.
                if (!leftfinished)
                {
                    // What vertex would be exposed if an edge were deleted?
                    leftcand.Lprev(ref nextedge);
                    nextedge.SymSelf();
                    nextapex = nextedge.Apex();
                    // If nextapex is NULL, then no vertex would be exposed; the
                    // triangulation would have been eaten right through.
                    if (nextapex != null)
                    {
                        // Check whether the edge is Delaunay.
                        badedge = Primitives.InCircle(lowerleft, lowerright, upperleft, nextapex) > 0.0;
                        while (badedge)
                        {
                            // Eliminate the edge with an edge flip.  As a result, the
                            // left triangulation will have one more boundary triangle.
                            nextedge.LnextSelf();
                            nextedge.Sym(ref topcasing);
                            nextedge.LnextSelf();
                            nextedge.Sym(ref sidecasing);
                            nextedge.Bond(ref topcasing);
                            leftcand.Bond(ref sidecasing);
                            leftcand.LnextSelf();
                            leftcand.Sym(ref outercasing);
                            nextedge.LprevSelf();
                            nextedge.Bond(ref outercasing);
                            // Correct the vertices to reflect the edge flip.
                            leftcand.SetOrg(lowerleft);
                            leftcand.SetDest(null);
                            leftcand.SetApex(nextapex);
                            nextedge.SetOrg(null);
                            nextedge.SetDest(upperleft);
                            nextedge.SetApex(nextapex);
                            // Consider the newly exposed vertex.
                            upperleft = nextapex;
                            // What vertex would be exposed if another edge were deleted?
                            sidecasing.Copy(ref nextedge);
                            nextapex = nextedge.Apex();
                            if (nextapex != null)
                            {
                                // Check whether the edge is Delaunay.
                                badedge = Primitives.InCircle(lowerleft, lowerright, upperleft, nextapex) > 0.0;
                            }
                            else
                            {
                                // Avoid eating right through the triangulation.
                                badedge = false;
                            }
                        }
                    }
                }
                // Consider eliminating edges from the right triangulation.
                if (!rightfinished)
                {
                    // What vertex would be exposed if an edge were deleted?
                    rightcand.Lnext(ref nextedge);
                    nextedge.SymSelf();
                    nextapex = nextedge.Apex();
                    // If nextapex is NULL, then no vertex would be exposed; the
                    // triangulation would have been eaten right through.
                    if (nextapex != null)
                    {
                        // Check whether the edge is Delaunay.
                        badedge = Primitives.InCircle(lowerleft, lowerright, upperright, nextapex) > 0.0;
                        while (badedge)
                        {
                            // Eliminate the edge with an edge flip.  As a result, the
                            // right triangulation will have one more boundary triangle.
                            nextedge.LprevSelf();
                            nextedge.Sym(ref topcasing);
                            nextedge.LprevSelf();
                            nextedge.Sym(ref sidecasing);
                            nextedge.Bond(ref topcasing);
                            rightcand.Bond(ref sidecasing);
                            rightcand.LprevSelf();
                            rightcand.Sym(ref outercasing);
                            nextedge.LnextSelf();
                            nextedge.Bond(ref outercasing);
                            // Correct the vertices to reflect the edge flip.
                            rightcand.SetOrg(null);
                            rightcand.SetDest(lowerright);
                            rightcand.SetApex(nextapex);
                            nextedge.SetOrg(upperright);
                            nextedge.SetDest(null);
                            nextedge.SetApex(nextapex);
                            // Consider the newly exposed vertex.
                            upperright = nextapex;
                            // What vertex would be exposed if another edge were deleted?
                            sidecasing.Copy(ref nextedge);
                            nextapex = nextedge.Apex();
                            if (nextapex != null)
                            {
                                // Check whether the edge is Delaunay.
                                badedge = Primitives.InCircle(lowerleft, lowerright, upperright, nextapex) > 0.0;
                            }
                            else
                            {
                                // Avoid eating right through the triangulation.
                                badedge = false;
                            }
                        }
                    }
                }
                if (leftfinished || (!rightfinished &&
                                     (Primitives.InCircle(upperleft, lowerleft, lowerright, upperright) > 0.0)))
                {
                    // Knit the triangulations, adding an edge from 'lowerleft'
                    // to 'upperright'.
                    baseedge.Bond(ref rightcand);
                    rightcand.Lprev(ref baseedge);
                    baseedge.SetDest(lowerleft);
                    lowerright = upperright;
                    baseedge.Sym(ref rightcand);
                    upperright = rightcand.Apex();
                }
                else
                {
                    // Knit the triangulations, adding an edge from 'upperleft'
                    // to 'lowerright'.
                    baseedge.Bond(ref leftcand);
                    leftcand.Lnext(ref baseedge);
                    baseedge.SetOrg(lowerright);
                    lowerleft = upperleft;
                    baseedge.Sym(ref leftcand);
                    upperleft = leftcand.Apex();
                }
            }
        }
예제 #6
0
        /// <summary>
        /// Inserts a vertex at the circumcenter of a triangle. Deletes
        /// the newly inserted vertex if it encroaches upon a segment.
        /// </summary>
        /// <param name="badtri"></param>
        private void SplitTriangle(BadTriangle badtri)
        {
            Otri               badotri = default(Otri);
            Vertex             borg, bdest, bapex;
            Point              newloc; // Location of the new vertex
            float              xi = 0, eta = 0;
            InsertVertexResult success;
            bool               errorflag;

            badotri = badtri.poortri;
            borg    = badotri.Org();
            bdest   = badotri.Dest();
            bapex   = badotri.Apex();

            // Make sure that this triangle is still the same triangle it was
            // when it was tested and determined to be of bad quality.
            // Subsequent transformations may have made it a different triangle.
            if (!Otri.IsDead(badotri.triangle) && (borg == badtri.triangorg) &&
                (bdest == badtri.triangdest) && (bapex == badtri.triangapex))
            {
                errorflag = false;
                // Create a new vertex at the triangle's circumcenter.

                // Using the original (simpler) Steiner point location method
                // for mesh refinement.
                // TODO: NewLocation doesn't work for refinement. Why? Maybe
                // reset VertexType?
                if (behavior.fixedArea || behavior.VarArea)
                {
                    newloc = Primitives.FindCircumcenter(borg, bdest, bapex, ref xi, ref eta, behavior.offconstant);
                }
                else
                {
                    newloc = newLocation.FindLocation(borg, bdest, bapex, ref xi, ref eta, true, badotri);
                }

                // Check whether the new vertex lies on a triangle vertex.
                if (((newloc.x == borg.x) && (newloc.y == borg.y)) ||
                    ((newloc.x == bdest.x) && (newloc.y == bdest.y)) ||
                    ((newloc.x == bapex.x) && (newloc.y == bapex.y)))
                {
                    if (Behavior.Verbose)
                    {
                        logger.Warning("New vertex falls on existing vertex.", "Quality.SplitTriangle()");
                        errorflag = true;
                    }
                }
                else
                {
                    // The new vertex must be in the interior, and therefore is a
                    // free vertex with a marker of zero.
                    Vertex newvertex = new Vertex(newloc.x, newloc.y, 0, mesh.nextras);
                    newvertex.type = VertexType.FreeVertex;

                    for (int i = 0; i < mesh.nextras; i++)
                    {
                        // Interpolate the vertex attributes at the circumcenter.
                        newvertex.attributes[i] = borg.attributes[i]
                                                  + xi * (bdest.attributes[i] - borg.attributes[i])
                                                  + eta * (bapex.attributes[i] - borg.attributes[i]);
                    }

                    // Ensure that the handle 'badotri' does not represent the longest
                    // edge of the triangle.  This ensures that the circumcenter must
                    // fall to the left of this edge, so point location will work.
                    // (If the angle org-apex-dest exceeds 90 degrees, then the
                    // circumcenter lies outside the org-dest edge, and eta is
                    // negative.  Roundoff error might prevent eta from being
                    // negative when it should be, so I test eta against xi.)
                    if (eta < xi)
                    {
                        badotri.LprevSelf();
                    }

                    // Insert the circumcenter, searching from the edge of the triangle,
                    // and maintain the Delaunay property of the triangulation.
                    Osub tmp = default(Osub);
                    success = mesh.InsertVertex(newvertex, ref badotri, ref tmp, true, true);

                    if (success == InsertVertexResult.Successful)
                    {
                        newvertex.hash = mesh.hash_vtx++;
                        newvertex.id   = newvertex.hash;

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

                        if (mesh.steinerleft > 0)
                        {
                            mesh.steinerleft--;
                        }
                    }
                    else if (success == InsertVertexResult.Encroaching)
                    {
                        // If the newly inserted vertex encroaches upon a subsegment,
                        // delete the new vertex.
                        mesh.UndoVertex();
                    }
                    else if (success == InsertVertexResult.Violating)
                    {
                        // Failed to insert the new vertex, but some subsegment was
                        // marked as being encroached.
                    }
                    else
                    {   // success == DUPLICATEVERTEX
                        // Couldn't insert the new vertex because a vertex is already there.
                        if (Behavior.Verbose)
                        {
                            logger.Warning("New vertex falls on existing vertex.", "Quality.SplitTriangle()");
                            errorflag = true;
                        }
                    }
                }
                if (errorflag)
                {
                    logger.Error("The new vertex is at the circumcenter of triangle: This probably "
                                 + "means that I am trying to refine triangles to a smaller size than can be "
                                 + "accommodated by the finite precision of floating point arithmetic.",
                                 "Quality.SplitTriangle()");

                    throw new Exception("The new vertex is at the circumcenter of triangle.");
                }
            }
        }
예제 #7
0
        /// <summary>
        /// Split all the encroached subsegments.
        /// </summary>
        /// <param name="triflaws">A flag that specifies whether one should take
        /// note of new bad triangles that result from inserting vertices to repair
        /// encroached subsegments.</param>
        /// <remarks>
        /// Each encroached subsegment is repaired by splitting it - inserting a
        /// vertex at or near its midpoint.  Newly inserted vertices may encroach
        /// upon other subsegments; these are also repaired.
        /// </remarks>
        private void SplitEncSegs(bool triflaws)
        {
            Otri               enctri     = default(Otri);
            Otri               testtri    = default(Otri);
            Osub               testsh     = default(Osub);
            Osub               currentenc = default(Osub);
            BadSubseg          seg;
            Vertex             eorg, edest, eapex;
            Vertex             newvertex;
            InsertVertexResult success;
            float              segmentlength, nearestpoweroftwo;
            float              split;
            float              multiplier, divisor;
            bool               acuteorg, acuteorg2, acutedest, acutedest2;

            // Note that steinerleft == -1 if an unlimited number
            // of Steiner points is allowed.
            while (badsubsegs.Count > 0)
            {
                if (mesh.steinerleft == 0)
                {
                    break;
                }

                seg = badsubsegs.Dequeue();

                currentenc = seg.encsubseg;
                eorg       = currentenc.Org();
                edest      = currentenc.Dest();
                // Make sure that this segment is still the same segment it was
                // when it was determined to be encroached.  If the segment was
                // enqueued multiple times (because several newly inserted
                // vertices encroached it), it may have already been split.
                if (!Osub.IsDead(currentenc.seg) && (eorg == seg.subsegorg) && (edest == seg.subsegdest))
                {
                    // To decide where to split a segment, we need to know if the
                    // segment shares an endpoint with an adjacent segment.
                    // The concern is that, if we simply split every encroached
                    // segment in its center, two adjacent segments with a small
                    // angle between them might lead to an infinite loop; each
                    // vertex added to split one segment will encroach upon the
                    // other segment, which must then be split with a vertex that
                    // will encroach upon the first segment, and so on forever.
                    // To avoid this, imagine a set of concentric circles, whose
                    // radii are powers of two, about each segment endpoint.
                    // These concentric circles determine where the segment is
                    // split. (If both endpoints are shared with adjacent
                    // segments, split the segment in the middle, and apply the
                    // concentric circles for later splittings.)

                    // Is the origin shared with another segment?
                    currentenc.TriPivot(ref enctri);
                    enctri.Lnext(ref testtri);
                    testtri.SegPivot(ref testsh);
                    acuteorg = testsh.seg != Mesh.dummysub;
                    // Is the destination shared with another segment?
                    testtri.LnextSelf();
                    testtri.SegPivot(ref testsh);
                    acutedest = testsh.seg != Mesh.dummysub;

                    // If we're using Chew's algorithm (rather than Ruppert's)
                    // to define encroachment, delete free vertices from the
                    // subsegment's diametral circle.
                    if (!behavior.ConformingDelaunay && !acuteorg && !acutedest)
                    {
                        eapex = enctri.Apex();
                        while ((eapex.type == VertexType.FreeVertex) &&
                               ((eorg.x - eapex.x) * (edest.x - eapex.x) +
                                (eorg.y - eapex.y) * (edest.y - eapex.y) < 0.0))
                        {
                            mesh.DeleteVertex(ref testtri);
                            currentenc.TriPivot(ref enctri);
                            eapex = enctri.Apex();
                            enctri.Lprev(ref testtri);
                        }
                    }

                    // Now, check the other side of the segment, if there's a triangle there.
                    enctri.Sym(ref testtri);
                    if (testtri.triangle != Mesh.dummytri)
                    {
                        // Is the destination shared with another segment?
                        testtri.LnextSelf();
                        testtri.SegPivot(ref testsh);
                        acutedest2 = testsh.seg != Mesh.dummysub;
                        acutedest  = acutedest || acutedest2;
                        // Is the origin shared with another segment?
                        testtri.LnextSelf();
                        testtri.SegPivot(ref testsh);
                        acuteorg2 = testsh.seg != Mesh.dummysub;
                        acuteorg  = acuteorg || acuteorg2;

                        // Delete free vertices from the subsegment's diametral circle.
                        if (!behavior.ConformingDelaunay && !acuteorg2 && !acutedest2)
                        {
                            eapex = testtri.Org();
                            while ((eapex.type == VertexType.FreeVertex) &&
                                   ((eorg.x - eapex.x) * (edest.x - eapex.x) +
                                    (eorg.y - eapex.y) * (edest.y - eapex.y) < 0.0))
                            {
                                mesh.DeleteVertex(ref testtri);
                                enctri.Sym(ref testtri);
                                eapex = testtri.Apex();
                                testtri.LprevSelf();
                            }
                        }
                    }

                    // Use the concentric circles if exactly one endpoint is shared
                    // with another adjacent segment.
                    if (acuteorg || acutedest)
                    {
                        segmentlength = UnityEngine.Mathf.Sqrt((edest.x - eorg.x) * (edest.x - eorg.x) +
                                                               (edest.y - eorg.y) * (edest.y - eorg.y));
                        // Find the power of two that most evenly splits the segment.
                        // The worst case is a 2:1 ratio between subsegment lengths.
                        nearestpoweroftwo = 1.0f;
                        while (segmentlength > 3.0f * nearestpoweroftwo)
                        {
                            nearestpoweroftwo *= 2.0f;
                        }
                        while (segmentlength < 1.5f * nearestpoweroftwo)
                        {
                            nearestpoweroftwo *= 0.5f;
                        }
                        // Where do we split the segment?
                        split = nearestpoweroftwo / segmentlength;
                        if (acutedest)
                        {
                            split = 1.0f - split;
                        }
                    }
                    else
                    {
                        // If we're not worried about adjacent segments, split
                        // this segment in the middle.
                        split = 0.5f;
                    }

                    // Create the new vertex (interpolate coordinates).
                    newvertex = new Vertex(
                        eorg.x + split * (edest.x - eorg.x),
                        eorg.y + split * (edest.y - eorg.y),
                        currentenc.Mark(),
                        mesh.nextras);

                    newvertex.type = VertexType.SegmentVertex;

                    newvertex.hash = mesh.hash_vtx++;
                    newvertex.id   = newvertex.hash;

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

                    // Interpolate attributes.
                    for (int i = 0; i < mesh.nextras; i++)
                    {
                        newvertex.attributes[i] = eorg.attributes[i]
                                                  + split * (edest.attributes[i] - eorg.attributes[i]);
                    }

                    if (!Behavior.NoExact)
                    {
                        // Roundoff in the above calculation may yield a 'newvertex'
                        // that is not precisely collinear with 'eorg' and 'edest'.
                        // Improve collinearity by one step of iterative refinement.
                        multiplier = Primitives.CounterClockwise(eorg, edest, newvertex);
                        divisor    = ((eorg.x - edest.x) * (eorg.x - edest.x) +
                                      (eorg.y - edest.y) * (eorg.y - edest.y));
                        if ((multiplier != 0.0) && (divisor != 0.0))
                        {
                            multiplier = multiplier / divisor;
                            // Watch out for NANs.
                            if (!float.IsNaN(multiplier))
                            {
                                newvertex.x += multiplier * (edest.y - eorg.y);
                                newvertex.y += multiplier * (eorg.x - edest.x);
                            }
                        }
                    }

                    // Check whether the new vertex lies on an endpoint.
                    if (((newvertex.x == eorg.x) && (newvertex.y == eorg.y)) ||
                        ((newvertex.x == edest.x) && (newvertex.y == edest.y)))
                    {
                        logger.Error("Ran out of precision: I attempted to split a"
                                     + " segment to a smaller size than can be accommodated by"
                                     + " the finite precision of floating point arithmetic.",
                                     "Quality.SplitEncSegs()");

                        throw new Exception("Ran out of precision");
                    }
                    // Insert the splitting vertex.  This should always succeed.
                    success = mesh.InsertVertex(newvertex, ref enctri, ref currentenc, true, triflaws);
                    if ((success != InsertVertexResult.Successful) && (success != InsertVertexResult.Encroaching))
                    {
                        logger.Error("Failure to split a segment.", "Quality.SplitEncSegs()");
                        throw new Exception("Failure to split a segment.");
                    }
                    if (mesh.steinerleft > 0)
                    {
                        mesh.steinerleft--;
                    }
                    // Check the two new subsegments to see if they're encroached.
                    CheckSeg4Encroach(ref currentenc);
                    currentenc.NextSelf();
                    CheckSeg4Encroach(ref currentenc);
                }

                // Set subsegment's origin to NULL. This makes it possible to detect dead
                // badsubsegs when traversing the list of all badsubsegs.
                seg.subsegorg = null;
            }
        }
예제 #8
0
        public int Triangulate(Mesh mesh)
        {
            SweepLine.SweepEvent[] sweepEventArray;
            SweepLine.SweepEvent   sweepEvent;
            Vertex vertex;
            Vertex vertex1;
            Vertex vertex2;
            Vertex vertex3;

            this.mesh        = mesh;
            this.xminextreme = 10 * mesh.bounds.Xmin - 9 * mesh.bounds.Xmax;
            Otri otri  = new Otri();
            Otri otri1 = new Otri();
            Otri otri2 = new Otri();
            Otri otri3 = new Otri();
            Otri otri4 = new Otri();
            Otri otri5 = new Otri();
            Otri otri6 = new Otri();
            bool i     = false;

            this.splaynodes = new List <SweepLine.SplayNode>();
            SweepLine.SplayNode splayNode = null;
            this.CreateHeap(out sweepEventArray);
            int num = mesh.invertices;

            mesh.MakeTriangle(ref otri2);
            mesh.MakeTriangle(ref otri3);
            otri2.Bond(ref otri3);
            otri2.LnextSelf();
            otri3.LprevSelf();
            otri2.Bond(ref otri3);
            otri2.LnextSelf();
            otri3.LprevSelf();
            otri2.Bond(ref otri3);
            Vertex vertex4 = sweepEventArray[0].vertexEvent;

            this.HeapDelete(sweepEventArray, num, 0);
            num--;
            do
            {
                if (num == 0)
                {
                    SimpleLog.Instance.Error("Input vertices are all identical.", "SweepLine.SweepLineDelaunay()");
                    throw new Exception("Input vertices are all identical.");
                }
                vertex = sweepEventArray[0].vertexEvent;
                this.HeapDelete(sweepEventArray, num, 0);
                num--;
                if (vertex4.x != vertex.x || vertex4.y != vertex.y)
                {
                    continue;
                }
                if (Behavior.Verbose)
                {
                    SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.", "SweepLine.SweepLineDelaunay().1");
                }
                vertex.type = VertexType.UndeadVertex;
                Mesh mesh1 = mesh;
                mesh1.undeads = mesh1.undeads + 1;
            }while (vertex4.x == vertex.x && vertex4.y == vertex.y);
            otri2.SetOrg(vertex4);
            otri2.SetDest(vertex);
            otri3.SetOrg(vertex);
            otri3.SetDest(vertex4);
            otri2.Lprev(ref otri);
            Vertex vertex5 = vertex;

            while (num > 0)
            {
                SweepLine.SweepEvent sweepEvent1 = sweepEventArray[0];
                this.HeapDelete(sweepEventArray, num, 0);
                num--;
                bool flag = true;
                if (sweepEvent1.xkey >= mesh.bounds.Xmin)
                {
                    Vertex vertex6 = sweepEvent1.vertexEvent;
                    if (vertex6.x != vertex5.x || vertex6.y != vertex5.y)
                    {
                        vertex5   = vertex6;
                        splayNode = this.FrontLocate(splayNode, otri, vertex6, ref otri1, ref i);
                        otri.Copy(ref otri1);
                        for (i = false; !i && this.RightOfHyperbola(ref otri1, vertex6); i = otri1.Equal(otri))
                        {
                            otri1.OnextSelf();
                        }
                        this.Check4DeadEvent(ref otri1, sweepEventArray, ref num);
                        otri1.Copy(ref otri5);
                        otri1.Sym(ref otri4);
                        mesh.MakeTriangle(ref otri2);
                        mesh.MakeTriangle(ref otri3);
                        Vertex vertex7 = otri5.Dest();
                        otri2.SetOrg(vertex7);
                        otri2.SetDest(vertex6);
                        otri3.SetOrg(vertex6);
                        otri3.SetDest(vertex7);
                        otri2.Bond(ref otri3);
                        otri2.LnextSelf();
                        otri3.LprevSelf();
                        otri2.Bond(ref otri3);
                        otri2.LnextSelf();
                        otri3.LprevSelf();
                        otri2.Bond(ref otri4);
                        otri3.Bond(ref otri5);
                        if (!i && otri5.Equal(otri))
                        {
                            otri2.Copy(ref otri);
                        }
                        if (this.randomnation(SweepLine.SAMPLERATE) == 0)
                        {
                            splayNode = this.SplayInsert(splayNode, otri2, vertex6);
                        }
                        else if (this.randomnation(SweepLine.SAMPLERATE) == 0)
                        {
                            otri3.Lnext(ref otri6);
                            splayNode = this.SplayInsert(splayNode, otri6, vertex6);
                        }
                    }
                    else
                    {
                        if (Behavior.Verbose)
                        {
                            SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.", "SweepLine.SweepLineDelaunay().2");
                        }
                        vertex6.type = VertexType.UndeadVertex;
                        Mesh mesh2 = mesh;
                        mesh2.undeads = mesh2.undeads + 1;
                        flag          = false;
                    }
                }
                else
                {
                    Otri otri7 = sweepEvent1.otriEvent;
                    otri7.Oprev(ref otri4);
                    this.Check4DeadEvent(ref otri4, sweepEventArray, ref num);
                    otri7.Onext(ref otri5);
                    this.Check4DeadEvent(ref otri5, sweepEventArray, ref num);
                    if (otri4.Equal(otri))
                    {
                        otri7.Lprev(ref otri);
                    }
                    mesh.Flip(ref otri7);
                    otri7.SetApex(null);
                    otri7.Lprev(ref otri2);
                    otri7.Lnext(ref otri3);
                    otri2.Sym(ref otri4);
                    if (this.randomnation(SweepLine.SAMPLERATE) == 0)
                    {
                        otri7.SymSelf();
                        vertex1   = otri7.Dest();
                        vertex2   = otri7.Apex();
                        vertex3   = otri7.Org();
                        splayNode = this.CircleTopInsert(splayNode, otri2, vertex1, vertex2, vertex3, sweepEvent1.ykey);
                    }
                }
                if (!flag)
                {
                    continue;
                }
                vertex1 = otri4.Apex();
                vertex2 = otri2.Dest();
                vertex3 = otri2.Apex();
                double num1 = Primitives.CounterClockwise(vertex1, vertex2, vertex3);
                if (num1 > 0)
                {
                    sweepEvent = new SweepLine.SweepEvent()
                    {
                        xkey      = this.xminextreme,
                        ykey      = this.CircleTop(vertex1, vertex2, vertex3, num1),
                        otriEvent = otri2
                    };
                    this.HeapInsert(sweepEventArray, num, sweepEvent);
                    num++;
                    otri2.SetOrg(new SweepLine.SweepEventVertex(sweepEvent));
                }
                vertex1 = otri3.Apex();
                vertex2 = otri3.Org();
                vertex3 = otri5.Apex();
                double num2 = Primitives.CounterClockwise(vertex1, vertex2, vertex3);
                if (num2 <= 0)
                {
                    continue;
                }
                sweepEvent = new SweepLine.SweepEvent()
                {
                    xkey      = this.xminextreme,
                    ykey      = this.CircleTop(vertex1, vertex2, vertex3, num2),
                    otriEvent = otri5
                };
                this.HeapInsert(sweepEventArray, num, sweepEvent);
                num++;
                otri5.SetOrg(new SweepLine.SweepEventVertex(sweepEvent));
            }
            this.splaynodes.Clear();
            otri.LprevSelf();
            return(this.RemoveGhosts(ref otri));
        }
예제 #9
0
        public int Triangulate(Mesh mesh)
        {
            this.mesh = mesh;

            // Nonexistent x value used as a flag to mark circle events in sweepline
            // Delaunay algorithm.
            xminextreme = 10 * mesh.bounds.Xmin - 9 * mesh.bounds.Xmax;

            SweepEvent[] eventheap;

            SweepEvent nextevent;
            SweepEvent newevent;
            SplayNode  splayroot;
            Otri       bottommost = default(Otri);
            Otri       searchtri  = default(Otri);
            Otri       fliptri;
            Otri       lefttri = default(Otri);
            Otri       righttri = default(Otri);
            Otri       farlefttri = default(Otri);
            Otri       farrighttri = default(Otri);
            Otri       inserttri = default(Otri);
            Vertex     firstvertex, secondvertex;
            Vertex     nextvertex, lastvertex;
            Vertex     connectvertex;
            Vertex     leftvertex, midvertex, rightvertex;
            float      lefttest, righttest;
            int        heapsize;
            bool       check4events, farrightflag = false;

            splaynodes = new List <SplayNode>();
            splayroot  = null;

            CreateHeap(out eventheap);//, out events, out freeevents);
            heapsize = mesh.invertices;

            mesh.MakeTriangle(ref lefttri);
            mesh.MakeTriangle(ref righttri);
            lefttri.Bond(ref righttri);
            lefttri.LnextSelf();
            righttri.LprevSelf();
            lefttri.Bond(ref righttri);
            lefttri.LnextSelf();
            righttri.LprevSelf();
            lefttri.Bond(ref righttri);
            firstvertex = eventheap[0].vertexEvent;

            HeapDelete(eventheap, heapsize, 0);
            heapsize--;
            do
            {
                if (heapsize == 0)
                {
                    SimpleLog.Instance.Error("Input vertices are all identical.", "SweepLine.SweepLineDelaunay()");
                    throw new Exception("Input vertices are all identical.");
                }
                secondvertex = eventheap[0].vertexEvent;
                HeapDelete(eventheap, heapsize, 0);
                heapsize--;
                if ((firstvertex.x == secondvertex.x) &&
                    (firstvertex.y == secondvertex.y))
                {
                    if (Behavior.Verbose)
                    {
                        SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.",
                                                   "SweepLine.SweepLineDelaunay().1");
                    }
                    secondvertex.type = VertexType.UndeadVertex;
                    mesh.undeads++;
                }
            } while ((firstvertex.x == secondvertex.x) &&
                     (firstvertex.y == secondvertex.y));
            lefttri.SetOrg(firstvertex);
            lefttri.SetDest(secondvertex);
            righttri.SetOrg(secondvertex);
            righttri.SetDest(firstvertex);
            lefttri.Lprev(ref bottommost);
            lastvertex = secondvertex;

            while (heapsize > 0)
            {
                nextevent = eventheap[0];
                HeapDelete(eventheap, heapsize, 0);
                heapsize--;
                check4events = true;
                if (nextevent.xkey < mesh.bounds.Xmin)
                {
                    fliptri = nextevent.otriEvent;
                    fliptri.Oprev(ref farlefttri);
                    Check4DeadEvent(ref farlefttri, eventheap, ref heapsize);
                    fliptri.Onext(ref farrighttri);
                    Check4DeadEvent(ref farrighttri, eventheap, ref heapsize);

                    if (farlefttri.Equal(bottommost))
                    {
                        fliptri.Lprev(ref bottommost);
                    }
                    mesh.Flip(ref fliptri);
                    fliptri.SetApex(null);
                    fliptri.Lprev(ref lefttri);
                    fliptri.Lnext(ref righttri);
                    lefttri.Sym(ref farlefttri);

                    if (randomnation(SAMPLERATE) == 0)
                    {
                        fliptri.SymSelf();
                        leftvertex  = fliptri.Dest();
                        midvertex   = fliptri.Apex();
                        rightvertex = fliptri.Org();
                        splayroot   = CircleTopInsert(splayroot, lefttri, leftvertex, midvertex, rightvertex, nextevent.ykey);
                    }
                }
                else
                {
                    nextvertex = nextevent.vertexEvent;
                    if ((nextvertex.x == lastvertex.x) &&
                        (nextvertex.y == lastvertex.y))
                    {
                        if (Behavior.Verbose)
                        {
                            SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.",
                                                       "SweepLine.SweepLineDelaunay().2");
                        }
                        nextvertex.type = VertexType.UndeadVertex;
                        mesh.undeads++;
                        check4events = false;
                    }
                    else
                    {
                        lastvertex = nextvertex;

                        splayroot = FrontLocate(splayroot, bottommost, nextvertex,
                                                ref searchtri, ref farrightflag);
                        //
                        bottommost.Copy(ref searchtri);
                        farrightflag = false;
                        while (!farrightflag && RightOfHyperbola(ref searchtri, nextvertex))
                        {
                            searchtri.OnextSelf();
                            farrightflag = searchtri.Equal(bottommost);
                        }


                        Check4DeadEvent(ref searchtri, eventheap, ref heapsize);

                        searchtri.Copy(ref farrighttri);
                        searchtri.Sym(ref farlefttri);
                        mesh.MakeTriangle(ref lefttri);
                        mesh.MakeTriangle(ref righttri);
                        connectvertex = farrighttri.Dest();
                        lefttri.SetOrg(connectvertex);
                        lefttri.SetDest(nextvertex);
                        righttri.SetOrg(nextvertex);
                        righttri.SetDest(connectvertex);
                        lefttri.Bond(ref righttri);
                        lefttri.LnextSelf();
                        righttri.LprevSelf();
                        lefttri.Bond(ref righttri);
                        lefttri.LnextSelf();
                        righttri.LprevSelf();
                        lefttri.Bond(ref farlefttri);
                        righttri.Bond(ref farrighttri);
                        if (!farrightflag && farrighttri.Equal(bottommost))
                        {
                            lefttri.Copy(ref bottommost);
                        }

                        if (randomnation(SAMPLERATE) == 0)
                        {
                            splayroot = SplayInsert(splayroot, lefttri, nextvertex);
                        }
                        else if (randomnation(SAMPLERATE) == 0)
                        {
                            righttri.Lnext(ref inserttri);
                            splayroot = SplayInsert(splayroot, inserttri, nextvertex);
                        }
                    }
                }

                if (check4events)
                {
                    leftvertex  = farlefttri.Apex();
                    midvertex   = lefttri.Dest();
                    rightvertex = lefttri.Apex();
                    lefttest    = Primitives.CounterClockwise(leftvertex, midvertex, rightvertex);
                    if (lefttest > 0.0)
                    {
                        newevent = new SweepEvent();

                        newevent.xkey      = xminextreme;
                        newevent.ykey      = CircleTop(leftvertex, midvertex, rightvertex, lefttest);
                        newevent.otriEvent = lefttri;
                        HeapInsert(eventheap, heapsize, newevent);
                        heapsize++;
                        lefttri.SetOrg(new SweepEventVertex(newevent));
                    }
                    leftvertex  = righttri.Apex();
                    midvertex   = righttri.Org();
                    rightvertex = farrighttri.Apex();
                    righttest   = Primitives.CounterClockwise(leftvertex, midvertex, rightvertex);
                    if (righttest > 0.0)
                    {
                        newevent = new SweepEvent();

                        newevent.xkey      = xminextreme;
                        newevent.ykey      = CircleTop(leftvertex, midvertex, rightvertex, righttest);
                        newevent.otriEvent = farrighttri;
                        HeapInsert(eventheap, heapsize, newevent);
                        heapsize++;
                        farrighttri.SetOrg(new SweepEventVertex(newevent));
                    }
                }
            }

            splaynodes.Clear();
            bottommost.LprevSelf();
            return(RemoveGhosts(ref bottommost));
        }
예제 #10
0
        /// <summary>
        /// Find a triangle or edge containing a given point.
        /// </summary>
        /// <param name="searchpoint">The point to locate.</param>
        /// <param name="searchtri">The triangle to start the search at.</param>
        /// <param name="stopatsubsegment"> If 'stopatsubsegment' is set, the search
        /// will stop if it tries to walk through a subsegment, and will return OUTSIDE.</param>
        /// <returns>Location information.</returns>
        /// <remarks>
        /// Begins its search from 'searchtri'. It is important that 'searchtri'
        /// be a handle with the property that 'searchpoint' is strictly to the left
        /// of the edge denoted by 'searchtri', or is collinear with that edge and
        /// does not intersect that edge. (In particular, 'searchpoint' should not
        /// be the origin or destination of that edge.)
        ///
        /// These conditions are imposed because preciselocate() is normally used in
        /// one of two situations:
        ///
        /// (1)  To try to find the location to insert a new point.  Normally, we
        ///      know an edge that the point is strictly to the left of. In the
        ///      incremental Delaunay algorithm, that edge is a bounding box edge.
        ///      In Ruppert's Delaunay refinement algorithm for quality meshing,
        ///      that edge is the shortest edge of the triangle whose circumcenter
        ///      is being inserted.
        ///
        /// (2)  To try to find an existing point.  In this case, any edge on the
        ///      convex hull is a good starting edge. You must screen out the
        ///      possibility that the vertex sought is an endpoint of the starting
        ///      edge before you call preciselocate().
        ///
        /// On completion, 'searchtri' is a triangle that contains 'searchpoint'.
        ///
        /// This implementation differs from that given by Guibas and Stolfi.  It
        /// walks from triangle to triangle, crossing an edge only if 'searchpoint'
        /// is on the other side of the line containing that edge. After entering
        /// a triangle, there are two edges by which one can leave that triangle.
        /// If both edges are valid ('searchpoint' is on the other side of both
        /// edges), one of the two is chosen by drawing a line perpendicular to
        /// the entry edge (whose endpoints are 'forg' and 'fdest') passing through
        /// 'fapex'. Depending on which side of this perpendicular 'searchpoint'
        /// falls on, an exit edge is chosen.
        ///
        /// This implementation is empirically faster than the Guibas and Stolfi
        /// point location routine (which I originally used), which tends to spiral
        /// in toward its target.
        ///
        /// Returns ONVERTEX if the point lies on an existing vertex. 'searchtri'
        /// is a handle whose origin is the existing vertex.
        ///
        /// Returns ONEDGE if the point lies on a mesh edge. 'searchtri' is a
        /// handle whose primary edge is the edge on which the point lies.
        ///
        /// Returns INTRIANGLE if the point lies strictly within a triangle.
        /// 'searchtri' is a handle on the triangle that contains the point.
        ///
        /// Returns OUTSIDE if the point lies outside the mesh. 'searchtri' is a
        /// handle whose primary edge the point is to the right of.  This might
        /// occur when the circumcenter of a triangle falls just slightly outside
        /// the mesh due to floating-point roundoff error. It also occurs when
        /// seeking a hole or region point that a foolish user has placed outside
        /// the mesh.
        ///
        /// WARNING:  This routine is designed for convex triangulations, and will
        /// not generally work after the holes and concavities have been carved.
        /// However, it can still be used to find the circumcenter of a triangle, as
        /// long as the search is begun from the triangle in question.</remarks>
        public LocateResult PreciseLocate(Point searchpoint, ref Otri searchtri,
                                          bool stopatsubsegment)
        {
            Otri   backtracktri = default(Otri);
            Osub   checkedge = default(Osub);
            Vertex forg, fdest, fapex;
            double orgorient, destorient;
            bool   moveleft;

            // Where are we?
            forg  = searchtri.Org();
            fdest = searchtri.Dest();
            fapex = searchtri.Apex();
            while (true)
            {
                // Check whether the apex is the point we seek.
                if ((fapex.x == searchpoint.X) && (fapex.y == searchpoint.Y))
                {
                    searchtri.LprevSelf();
                    return(LocateResult.OnVertex);
                }
                // Does the point lie on the other side of the line defined by the
                // triangle edge opposite the triangle's destination?
                destorient = Primitives.CounterClockwise(forg, fapex, searchpoint);
                // Does the point lie on the other side of the line defined by the
                // triangle edge opposite the triangle's origin?
                orgorient = Primitives.CounterClockwise(fapex, fdest, searchpoint);
                if (destorient > 0.0)
                {
                    if (orgorient > 0.0)
                    {
                        // Move left if the inner product of (fapex - searchpoint) and
                        // (fdest - forg) is positive.  This is equivalent to drawing
                        // a line perpendicular to the line (forg, fdest) and passing
                        // through 'fapex', and determining which side of this line
                        // 'searchpoint' falls on.
                        moveleft = (fapex.x - searchpoint.X) * (fdest.x - forg.x) +
                                   (fapex.y - searchpoint.Y) * (fdest.y - forg.y) > 0.0;
                    }
                    else
                    {
                        moveleft = true;
                    }
                }
                else
                {
                    if (orgorient > 0.0)
                    {
                        moveleft = false;
                    }
                    else
                    {
                        // The point we seek must be on the boundary of or inside this
                        // triangle.
                        if (destorient == 0.0)
                        {
                            searchtri.LprevSelf();
                            return(LocateResult.OnEdge);
                        }
                        if (orgorient == 0.0)
                        {
                            searchtri.LnextSelf();
                            return(LocateResult.OnEdge);
                        }
                        return(LocateResult.InTriangle);
                    }
                }

                // Move to another triangle. Leave a trace 'backtracktri' in case
                // floating-point roundoff or some such bogey causes us to walk
                // off a boundary of the triangulation.
                if (moveleft)
                {
                    searchtri.Lprev(ref backtracktri);
                    fdest = fapex;
                }
                else
                {
                    searchtri.Lnext(ref backtracktri);
                    forg = fapex;
                }
                backtracktri.Sym(ref searchtri);

                if (mesh.checksegments && stopatsubsegment)
                {
                    // Check for walking through a subsegment.
                    backtracktri.SegPivot(ref checkedge);
                    if (checkedge.seg != Mesh.dummysub)
                    {
                        // Go back to the last triangle.
                        backtracktri.Copy(ref searchtri);
                        return(LocateResult.Outside);
                    }
                }
                // Check for walking right out of the triangulation.
                if (searchtri.triangle == Mesh.dummytri)
                {
                    // Go back to the last triangle.
                    backtracktri.Copy(ref searchtri);
                    return(LocateResult.Outside);
                }

                fapex = searchtri.Apex();
            }
        }
예제 #11
0
        /// <summary>
        /// Remove the "infinite" bounding triangle, setting boundary markers as appropriate.
        /// </summary>
        /// <returns>Returns the number of edges on the convex hull of the triangulation.</returns>
        /// <remarks>
        /// The triangular bounding box has three boundary triangles (one for each
        /// side of the bounding box), and a bunch of triangles fanning out from
        /// the three bounding box vertices (one triangle for each edge of the
        /// convex hull of the inner mesh).  This routine removes these triangles.
        /// </remarks>
        int RemoveBox()
        {
            Otri   deadtriangle = default(Otri);
            Otri   searchedge = default(Otri);
            Otri   checkedge = default(Otri);
            Otri   nextedge = default(Otri), finaledge = default(Otri), dissolveedge = default(Otri);
            Vertex markorg;
            int    hullsize;

            bool noPoly = !mesh.behavior.Poly;

            // Find a boundary triangle.
            nextedge.triangle = Mesh.dummytri;
            nextedge.orient   = 0;
            nextedge.SymSelf();
            // Mark a place to stop.
            nextedge.Lprev(ref finaledge);
            nextedge.LnextSelf();
            nextedge.SymSelf();
            // Find a triangle (on the boundary of the vertex set) that isn't
            // a bounding box triangle.
            nextedge.Lprev(ref searchedge);
            searchedge.SymSelf();
            // Check whether nextedge is another boundary triangle
            // adjacent to the first one.
            nextedge.Lnext(ref checkedge);
            checkedge.SymSelf();
            if (checkedge.triangle == Mesh.dummytri)
            {
                // Go on to the next triangle.  There are only three boundary
                // triangles, and this next triangle cannot be the third one,
                // so it's safe to stop here.
                searchedge.LprevSelf();
                searchedge.SymSelf();
            }

            // Find a new boundary edge to search from, as the current search
            // edge lies on a bounding box triangle and will be deleted.
            Mesh.dummytri.neighbors[0] = searchedge;
            hullsize = -2;
            while (!nextedge.Equal(finaledge))
            {
                hullsize++;
                nextedge.Lprev(ref dissolveedge);
                dissolveedge.SymSelf();
                // If not using a PSLG, the vertices should be marked now.
                // (If using a PSLG, markhull() will do the job.)
                if (noPoly)
                {
                    // Be careful!  One must check for the case where all the input
                    // vertices are collinear, and thus all the triangles are part of
                    // the bounding box.  Otherwise, the setvertexmark() call below
                    // will cause a bad pointer reference.
                    if (dissolveedge.triangle != Mesh.dummytri)
                    {
                        markorg = dissolveedge.Org();
                        if (markorg.mark == 0)
                        {
                            markorg.mark = 1;
                        }
                    }
                }

                // Disconnect the bounding box triangle from the mesh triangle.
                dissolveedge.Dissolve();
                nextedge.Lnext(ref deadtriangle);
                deadtriangle.Sym(ref nextedge);
                // Get rid of the bounding box triangle.
                mesh.TriangleDealloc(deadtriangle.triangle);
                // Do we need to turn the corner?
                if (nextedge.triangle == Mesh.dummytri)
                {
                    // Turn the corner.
                    dissolveedge.Copy(ref nextedge);
                }
            }

            mesh.TriangleDealloc(finaledge.triangle);

            return(hullsize);
        }
예제 #12
0
        private void SplitTriangle(BadTriangle badtri)
        {
            Point  point;
            Otri   otri = new Otri();
            double num  = 0;
            double num1 = 0;

            otri = badtri.poortri;
            Vertex vertex  = otri.Org();
            Vertex vertex1 = otri.Dest();
            Vertex vertex2 = otri.Apex();

            if (!Otri.IsDead(otri.triangle) && vertex == badtri.triangorg && vertex1 == badtri.triangdest && vertex2 == badtri.triangapex)
            {
                bool flag = false;
                point = (this.behavior.fixedArea || this.behavior.VarArea ? Primitives.FindCircumcenter(vertex, vertex1, vertex2, ref num, ref num1, this.behavior.offconstant) : this.newLocation.FindLocation(vertex, vertex1, vertex2, ref num, ref num1, true, otri));
                if ((point.x != vertex.x || point.y != vertex.y) && (point.x != vertex1.x || point.y != vertex1.y) && (point.x != vertex2.x || point.y != vertex2.y))
                {
                    Vertex vertex3 = new Vertex(point.x, point.y, 0, this.mesh.nextras)
                    {
                        type = VertexType.FreeVertex
                    };
                    for (int i = 0; i < this.mesh.nextras; i++)
                    {
                        vertex3.attributes[i] = vertex.attributes[i] + num * (vertex1.attributes[i] - vertex.attributes[i]) + num1 * (vertex2.attributes[i] - vertex.attributes[i]);
                    }
                    if (num1 < num)
                    {
                        otri.LprevSelf();
                    }
                    Osub osub = new Osub();
                    InsertVertexResult insertVertexResult = this.mesh.InsertVertex(vertex3, ref otri, ref osub, true, true);
                    if (insertVertexResult == InsertVertexResult.Successful)
                    {
                        Mesh mesh    = this.mesh;
                        int  hashVtx = mesh.hash_vtx;
                        mesh.hash_vtx = hashVtx + 1;
                        vertex3.hash  = hashVtx;
                        vertex3.id    = vertex3.hash;
                        this.mesh.vertices.Add(vertex3.hash, vertex3);
                        if (this.mesh.steinerleft > 0)
                        {
                            Mesh mesh1 = this.mesh;
                            mesh1.steinerleft = mesh1.steinerleft - 1;
                        }
                    }
                    else if (insertVertexResult == InsertVertexResult.Encroaching)
                    {
                        this.mesh.UndoVertex();
                    }
                    else if (insertVertexResult != InsertVertexResult.Violating && Behavior.Verbose)
                    {
                        this.logger.Warning("New vertex falls on existing vertex.", "Quality.SplitTriangle()");
                        flag = true;
                    }
                }
                else if (Behavior.Verbose)
                {
                    this.logger.Warning("New vertex falls on existing vertex.", "Quality.SplitTriangle()");
                    flag = true;
                }
                if (flag)
                {
                    this.logger.Error("The new vertex is at the circumcenter of triangle: This probably means that I am trying to refine triangles to a smaller size than can be accommodated by the finite precision of floating point arithmetic.", "Quality.SplitTriangle()");
                    throw new Exception("The new vertex is at the circumcenter of triangle.");
                }
            }
        }
예제 #13
0
        private void SplitEncSegs(bool triflaws)
        {
            Vertex vertex;
            double num;
            Otri   otri  = new Otri();
            Otri   otri1 = new Otri();
            Osub   osub  = new Osub();
            Osub   osub1 = new Osub();

            while (this.badsubsegs.Count > 0 && this.mesh.steinerleft != 0)
            {
                BadSubseg badSubseg = this.badsubsegs.Dequeue();
                osub1 = badSubseg.encsubseg;
                Vertex vertex1 = osub1.Org();
                Vertex vertex2 = osub1.Dest();
                if (!Osub.IsDead(osub1.seg) && vertex1 == badSubseg.subsegorg && vertex2 == badSubseg.subsegdest)
                {
                    osub1.TriPivot(ref otri);
                    otri.Lnext(ref otri1);
                    otri1.SegPivot(ref osub);
                    bool flag = osub.seg != Mesh.dummysub;
                    otri1.LnextSelf();
                    otri1.SegPivot(ref osub);
                    bool flag1 = osub.seg != Mesh.dummysub;
                    if (!this.behavior.ConformingDelaunay && !flag && !flag1)
                    {
                        vertex = otri.Apex();
                        while (vertex.type == VertexType.FreeVertex && (vertex1.x - vertex.x) * (vertex2.x - vertex.x) + (vertex1.y - vertex.y) * (vertex2.y - vertex.y) < 0)
                        {
                            this.mesh.DeleteVertex(ref otri1);
                            osub1.TriPivot(ref otri);
                            vertex = otri.Apex();
                            otri.Lprev(ref otri1);
                        }
                    }
                    otri.Sym(ref otri1);
                    if (otri1.triangle != Mesh.dummytri)
                    {
                        otri1.LnextSelf();
                        otri1.SegPivot(ref osub);
                        bool flag2 = osub.seg != Mesh.dummysub;
                        flag1 = flag1 | flag2;
                        otri1.LnextSelf();
                        otri1.SegPivot(ref osub);
                        bool flag3 = osub.seg != Mesh.dummysub;
                        flag = flag | flag3;
                        if (!this.behavior.ConformingDelaunay && !flag3 && !flag2)
                        {
                            vertex = otri1.Org();
                            while (vertex.type == VertexType.FreeVertex && (vertex1.x - vertex.x) * (vertex2.x - vertex.x) + (vertex1.y - vertex.y) * (vertex2.y - vertex.y) < 0)
                            {
                                this.mesh.DeleteVertex(ref otri1);
                                otri.Sym(ref otri1);
                                vertex = otri1.Apex();
                                otri1.LprevSelf();
                            }
                        }
                    }
                    if (!(flag | flag1))
                    {
                        num = 0.5;
                    }
                    else
                    {
                        double num1 = Math.Sqrt((vertex2.x - vertex1.x) * (vertex2.x - vertex1.x) + (vertex2.y - vertex1.y) * (vertex2.y - vertex1.y));
                        double num2 = 1;
                        while (num1 > 3 * num2)
                        {
                            num2 = num2 * 2;
                        }
                        while (num1 < 1.5 * num2)
                        {
                            num2 = num2 * 0.5;
                        }
                        num = num2 / num1;
                        if (flag1)
                        {
                            num = 1 - num;
                        }
                    }
                    Vertex vertex3 = new Vertex(vertex1.x + num * (vertex2.x - vertex1.x), vertex1.y + num * (vertex2.y - vertex1.y), osub1.Mark(), this.mesh.nextras)
                    {
                        type = VertexType.SegmentVertex
                    };
                    Mesh mesh    = this.mesh;
                    int  hashVtx = mesh.hash_vtx;
                    mesh.hash_vtx = hashVtx + 1;
                    vertex3.hash  = hashVtx;
                    vertex3.id    = vertex3.hash;
                    this.mesh.vertices.Add(vertex3.hash, vertex3);
                    for (int i = 0; i < this.mesh.nextras; i++)
                    {
                        vertex3.attributes[i] = vertex1.attributes[i] + num * (vertex2.attributes[i] - vertex1.attributes[i]);
                    }
                    if (!Behavior.NoExact)
                    {
                        double num3 = Primitives.CounterClockwise(vertex1, vertex2, vertex3);
                        double num4 = (vertex1.x - vertex2.x) * (vertex1.x - vertex2.x) + (vertex1.y - vertex2.y) * (vertex1.y - vertex2.y);
                        if (num3 != 0 && num4 != 0)
                        {
                            num3 = num3 / num4;
                            if (!double.IsNaN(num3))
                            {
                                Vertex vertex4 = vertex3;
                                vertex4.x = vertex4.x + num3 * (vertex2.y - vertex1.y);
                                Vertex vertex5 = vertex3;
                                vertex5.y = vertex5.y + num3 * (vertex1.x - vertex2.x);
                            }
                        }
                    }
                    if (vertex3.x == vertex1.x && vertex3.y == vertex1.y || vertex3.x == vertex2.x && vertex3.y == vertex2.y)
                    {
                        this.logger.Error("Ran out of precision: I attempted to split a segment to a smaller size than can be accommodated by the finite precision of floating point arithmetic.", "Quality.SplitEncSegs()");
                        throw new Exception("Ran out of precision");
                    }
                    InsertVertexResult insertVertexResult = this.mesh.InsertVertex(vertex3, ref otri, ref osub1, true, triflaws);
                    if (insertVertexResult != InsertVertexResult.Successful && insertVertexResult != InsertVertexResult.Encroaching)
                    {
                        this.logger.Error("Failure to split a segment.", "Quality.SplitEncSegs()");
                        throw new Exception("Failure to split a segment.");
                    }
                    if (this.mesh.steinerleft > 0)
                    {
                        Mesh mesh1 = this.mesh;
                        mesh1.steinerleft = mesh1.steinerleft - 1;
                    }
                    this.CheckSeg4Encroach(ref osub1);
                    osub1.NextSelf();
                    this.CheckSeg4Encroach(ref osub1);
                }
                badSubseg.subsegorg = null;
            }
        }
예제 #14
0
        public LocateResult PreciseLocate(Point searchpoint, ref Otri searchtri, bool stopatsubsegment)
        {
            bool   flag;
            Otri   otri    = new Otri();
            Osub   osub    = new Osub();
            Vertex vertex  = searchtri.Org();
            Vertex vertex1 = searchtri.Dest();

            for (Vertex i = searchtri.Apex(); i.x != searchpoint.X || i.y != searchpoint.Y; i = searchtri.Apex())
            {
                double num  = Primitives.CounterClockwise(vertex, i, searchpoint);
                double num1 = Primitives.CounterClockwise(i, vertex1, searchpoint);
                if (num <= 0)
                {
                    if (num1 <= 0)
                    {
                        if (num == 0)
                        {
                            searchtri.LprevSelf();
                            return(LocateResult.OnEdge);
                        }
                        if (num1 != 0)
                        {
                            return(LocateResult.InTriangle);
                        }
                        searchtri.LnextSelf();
                        return(LocateResult.OnEdge);
                    }
                    flag = false;
                }
                else
                {
                    flag = (num1 <= 0 ? true : (i.x - searchpoint.X) * (vertex1.x - vertex.x) + (i.y - searchpoint.Y) * (vertex1.y - vertex.y) > 0);
                }
                if (!flag)
                {
                    searchtri.Lnext(ref otri);
                    vertex = i;
                }
                else
                {
                    searchtri.Lprev(ref otri);
                    vertex1 = i;
                }
                otri.Sym(ref searchtri);
                if (this.mesh.checksegments & stopatsubsegment)
                {
                    otri.SegPivot(ref osub);
                    if (osub.seg != Mesh.dummysub)
                    {
                        otri.Copy(ref searchtri);
                        return(LocateResult.Outside);
                    }
                }
                if (searchtri.triangle == Mesh.dummytri)
                {
                    otri.Copy(ref searchtri);
                    return(LocateResult.Outside);
                }
            }
            searchtri.LprevSelf();
            return(LocateResult.OnVertex);
        }
예제 #15
0
        private void DivconqRecurse(int left, int right, int axis, ref Otri farleft, ref Otri farright)
        {
            Otri otri  = new Otri();
            Otri otri1 = new Otri();
            Otri otri2 = new Otri();
            Otri otri3 = new Otri();
            Otri otri4 = new Otri();
            Otri otri5 = new Otri();
            int  num   = right - left + 1;

            if (num == 2)
            {
                this.mesh.MakeTriangle(ref farleft);
                farleft.SetOrg(this.sortarray[left]);
                farleft.SetDest(this.sortarray[left + 1]);
                this.mesh.MakeTriangle(ref farright);
                farright.SetOrg(this.sortarray[left + 1]);
                farright.SetDest(this.sortarray[left]);
                farleft.Bond(ref farright);
                farleft.LprevSelf();
                farright.LnextSelf();
                farleft.Bond(ref farright);
                farleft.LprevSelf();
                farright.LnextSelf();
                farleft.Bond(ref farright);
                farright.Lprev(ref farleft);
                return;
            }
            if (num != 3)
            {
                int num1 = num >> 1;
                this.DivconqRecurse(left, left + num1 - 1, 1 - axis, ref farleft, ref otri4);
                this.DivconqRecurse(left + num1, right, 1 - axis, ref otri5, ref farright);
                this.MergeHulls(ref farleft, ref otri4, ref otri5, ref farright, axis);
                return;
            }
            this.mesh.MakeTriangle(ref otri);
            this.mesh.MakeTriangle(ref otri1);
            this.mesh.MakeTriangle(ref otri2);
            this.mesh.MakeTriangle(ref otri3);
            double num2 = Primitives.CounterClockwise(this.sortarray[left], this.sortarray[left + 1], this.sortarray[left + 2]);

            if (num2 == 0)
            {
                otri.SetOrg(this.sortarray[left]);
                otri.SetDest(this.sortarray[left + 1]);
                otri1.SetOrg(this.sortarray[left + 1]);
                otri1.SetDest(this.sortarray[left]);
                otri2.SetOrg(this.sortarray[left + 2]);
                otri2.SetDest(this.sortarray[left + 1]);
                otri3.SetOrg(this.sortarray[left + 1]);
                otri3.SetDest(this.sortarray[left + 2]);
                otri.Bond(ref otri1);
                otri2.Bond(ref otri3);
                otri.LnextSelf();
                otri1.LprevSelf();
                otri2.LnextSelf();
                otri3.LprevSelf();
                otri.Bond(ref otri3);
                otri1.Bond(ref otri2);
                otri.LnextSelf();
                otri1.LprevSelf();
                otri2.LnextSelf();
                otri3.LprevSelf();
                otri.Bond(ref otri1);
                otri2.Bond(ref otri3);
                otri1.Copy(ref farleft);
                otri2.Copy(ref farright);
                return;
            }
            otri.SetOrg(this.sortarray[left]);
            otri1.SetDest(this.sortarray[left]);
            otri3.SetOrg(this.sortarray[left]);
            if (num2 <= 0)
            {
                otri.SetDest(this.sortarray[left + 2]);
                otri1.SetOrg(this.sortarray[left + 2]);
                otri2.SetDest(this.sortarray[left + 2]);
                otri.SetApex(this.sortarray[left + 1]);
                otri2.SetOrg(this.sortarray[left + 1]);
                otri3.SetDest(this.sortarray[left + 1]);
            }
            else
            {
                otri.SetDest(this.sortarray[left + 1]);
                otri1.SetOrg(this.sortarray[left + 1]);
                otri2.SetDest(this.sortarray[left + 1]);
                otri.SetApex(this.sortarray[left + 2]);
                otri2.SetOrg(this.sortarray[left + 2]);
                otri3.SetDest(this.sortarray[left + 2]);
            }
            otri.Bond(ref otri1);
            otri.LnextSelf();
            otri.Bond(ref otri2);
            otri.LnextSelf();
            otri.Bond(ref otri3);
            otri1.LprevSelf();
            otri2.LnextSelf();
            otri1.Bond(ref otri2);
            otri1.LprevSelf();
            otri3.LprevSelf();
            otri1.Bond(ref otri3);
            otri2.LnextSelf();
            otri3.LprevSelf();
            otri2.Bond(ref otri3);
            otri1.Copy(ref farleft);
            if (num2 > 0)
            {
                otri2.Copy(ref farright);
                return;
            }
            farleft.Lnext(ref farright);
        }
예제 #16
0
        private void MergeHulls(ref Otri farleft, ref Otri innerleft, ref Otri innerright, ref Otri farright, int axis)
        {
            Vertex vertex;
            Vertex vertex1;
            Vertex vertex2;
            Vertex vertex3;
            Vertex vertex4;
            Vertex i;
            bool   flag;
            bool   flag1;
            Otri   otri    = new Otri();
            Otri   otri1   = new Otri();
            Otri   otri2   = new Otri();
            Otri   otri3   = new Otri();
            Otri   otri4   = new Otri();
            Otri   otri5   = new Otri();
            Otri   otri6   = new Otri();
            Otri   otri7   = new Otri();
            Vertex vertex5 = innerleft.Dest();
            Vertex vertex6 = innerleft.Apex();
            Vertex vertex7 = innerright.Org();
            Vertex vertex8 = innerright.Apex();

            if (this.useDwyer && axis == 1)
            {
                vertex  = farleft.Org();
                vertex2 = farleft.Apex();
                vertex1 = farright.Dest();
                vertex3 = farright.Apex();
                while (vertex2.y < vertex.y)
                {
                    farleft.LnextSelf();
                    farleft.SymSelf();
                    vertex  = vertex2;
                    vertex2 = farleft.Apex();
                }
                innerleft.Sym(ref otri6);
                for (i = otri6.Apex(); i.y > vertex5.y; i = otri6.Apex())
                {
                    otri6.Lnext(ref innerleft);
                    vertex6 = vertex5;
                    vertex5 = i;
                    innerleft.Sym(ref otri6);
                }
                while (vertex8.y < vertex7.y)
                {
                    innerright.LnextSelf();
                    innerright.SymSelf();
                    vertex7 = vertex8;
                    vertex8 = innerright.Apex();
                }
                farright.Sym(ref otri6);
                for (i = otri6.Apex(); i.y > vertex1.y; i = otri6.Apex())
                {
                    otri6.Lnext(ref farright);
                    vertex3 = vertex1;
                    vertex1 = i;
                    farright.Sym(ref otri6);
                }
            }
            do
            {
                flag = false;
                if (Primitives.CounterClockwise(vertex5, vertex6, vertex7) > 0)
                {
                    innerleft.LprevSelf();
                    innerleft.SymSelf();
                    vertex5 = vertex6;
                    vertex6 = innerleft.Apex();
                    flag    = true;
                }
                if (Primitives.CounterClockwise(vertex8, vertex7, vertex5) <= 0)
                {
                    continue;
                }
                innerright.LnextSelf();
                innerright.SymSelf();
                vertex7 = vertex8;
                vertex8 = innerright.Apex();
                flag    = true;
            }while (flag);
            innerleft.Sym(ref otri);
            innerright.Sym(ref otri1);
            this.mesh.MakeTriangle(ref otri7);
            otri7.Bond(ref innerleft);
            otri7.LnextSelf();
            otri7.Bond(ref innerright);
            otri7.LnextSelf();
            otri7.SetOrg(vertex7);
            otri7.SetDest(vertex5);
            vertex = farleft.Org();
            if (vertex5 == vertex)
            {
                otri7.Lnext(ref farleft);
            }
            vertex1 = farright.Dest();
            if (vertex7 == vertex1)
            {
                otri7.Lprev(ref farright);
            }
            Vertex vertex9  = vertex5;
            Vertex vertex10 = vertex7;
            Vertex vertex11 = otri.Apex();
            Vertex vertex12 = otri1.Apex();

            while (true)
            {
                bool flag2 = Primitives.CounterClockwise(vertex11, vertex9, vertex10) <= 0;
                bool flag3 = Primitives.CounterClockwise(vertex12, vertex9, vertex10) <= 0;
                if (flag2 & flag3)
                {
                    break;
                }
                if (!flag2)
                {
                    otri.Lprev(ref otri2);
                    otri2.SymSelf();
                    vertex4 = otri2.Apex();
                    if (vertex4 != null)
                    {
                        flag1 = Primitives.InCircle(vertex9, vertex10, vertex11, vertex4) > 0;
                        while (flag1)
                        {
                            otri2.LnextSelf();
                            otri2.Sym(ref otri4);
                            otri2.LnextSelf();
                            otri2.Sym(ref otri3);
                            otri2.Bond(ref otri4);
                            otri.Bond(ref otri3);
                            otri.LnextSelf();
                            otri.Sym(ref otri5);
                            otri2.LprevSelf();
                            otri2.Bond(ref otri5);
                            otri.SetOrg(vertex9);
                            otri.SetDest(null);
                            otri.SetApex(vertex4);
                            otri2.SetOrg(null);
                            otri2.SetDest(vertex11);
                            otri2.SetApex(vertex4);
                            vertex11 = vertex4;
                            otri3.Copy(ref otri2);
                            vertex4 = otri2.Apex();
                            flag1   = (vertex4 == null ? false : Primitives.InCircle(vertex9, vertex10, vertex11, vertex4) > 0);
                        }
                    }
                }
                if (!flag3)
                {
                    otri1.Lnext(ref otri2);
                    otri2.SymSelf();
                    vertex4 = otri2.Apex();
                    if (vertex4 != null)
                    {
                        flag1 = Primitives.InCircle(vertex9, vertex10, vertex12, vertex4) > 0;
                        while (flag1)
                        {
                            otri2.LprevSelf();
                            otri2.Sym(ref otri4);
                            otri2.LprevSelf();
                            otri2.Sym(ref otri3);
                            otri2.Bond(ref otri4);
                            otri1.Bond(ref otri3);
                            otri1.LprevSelf();
                            otri1.Sym(ref otri5);
                            otri2.LnextSelf();
                            otri2.Bond(ref otri5);
                            otri1.SetOrg(null);
                            otri1.SetDest(vertex10);
                            otri1.SetApex(vertex4);
                            otri2.SetOrg(vertex12);
                            otri2.SetDest(null);
                            otri2.SetApex(vertex4);
                            vertex12 = vertex4;
                            otri3.Copy(ref otri2);
                            vertex4 = otri2.Apex();
                            flag1   = (vertex4 == null ? false : Primitives.InCircle(vertex9, vertex10, vertex12, vertex4) > 0);
                        }
                    }
                }
                if (flag2 || !flag3 && Primitives.InCircle(vertex11, vertex9, vertex10, vertex12) > 0)
                {
                    otri7.Bond(ref otri1);
                    otri1.Lprev(ref otri7);
                    otri7.SetDest(vertex9);
                    vertex10 = vertex12;
                    otri7.Sym(ref otri1);
                    vertex12 = otri1.Apex();
                }
                else
                {
                    otri7.Bond(ref otri);
                    otri.Lnext(ref otri7);
                    otri7.SetOrg(vertex10);
                    vertex9 = vertex11;
                    otri7.Sym(ref otri);
                    vertex11 = otri.Apex();
                }
            }
            this.mesh.MakeTriangle(ref otri2);
            otri2.SetOrg(vertex9);
            otri2.SetDest(vertex10);
            otri2.Bond(ref otri7);
            otri2.LnextSelf();
            otri2.Bond(ref otri1);
            otri2.LnextSelf();
            otri2.Bond(ref otri);
            if (this.useDwyer && axis == 1)
            {
                vertex  = farleft.Org();
                vertex2 = farleft.Apex();
                vertex1 = farright.Dest();
                vertex3 = farright.Apex();
                farleft.Sym(ref otri6);
                for (i = otri6.Apex(); i.x < vertex.x; i = otri6.Apex())
                {
                    otri6.Lprev(ref farleft);
                    vertex2 = vertex;
                    vertex  = i;
                    farleft.Sym(ref otri6);
                }
                while (vertex3.x > vertex1.x)
                {
                    farright.LprevSelf();
                    farright.SymSelf();
                    vertex1 = vertex3;
                    vertex3 = farright.Apex();
                }
            }
        }