Пример #1
0
 public void EnforceQuality()
 {
     this.TallyEncs();
     this.SplitEncSegs(false);
     if (this.behavior.MinAngle > 0 || this.behavior.VarArea || this.behavior.fixedArea || this.behavior.Usertest)
     {
         this.TallyFaces();
         this.mesh.checkquality = true;
         while (this.queue.Count > 0 && this.mesh.steinerleft != 0)
         {
             BadTriangle badTriangle = this.queue.Dequeue();
             this.SplitTriangle(badTriangle);
             if (this.badsubsegs.Count <= 0)
             {
                 continue;
             }
             this.queue.Enqueue(badTriangle);
             this.SplitEncSegs(true);
         }
     }
     if (Behavior.Verbose && this.behavior.ConformingDelaunay && this.badsubsegs.Count > 0 && this.mesh.steinerleft == 0)
     {
         this.logger.Warning("I ran out of Steiner points, but the mesh has encroached subsegments, and therefore might not be truly Delaunay. If the Delaunay property is important to you, try increasing the number of Steiner points.", "Quality.EnforceQuality()");
     }
 }
Пример #2
0
        public void Enqueue(BadTriangle badtri)
        {
            double num;
            double i;
            int    num1;
            int    num2;

            this.count = this.count + 1;
            if (badtri.key < 1)
            {
                num  = 1 / badtri.key;
                num2 = 0;
            }
            else
            {
                num  = badtri.key;
                num2 = 1;
            }
            int num3 = 0;

            while (num > 2)
            {
                int num4 = 1;
                for (i = 0.5; num *i *i > 1; i = i * i)
                {
                    num4 = num4 * 2;
                }
                num3 = num3 + num4;
                num  = num * i;
            }
            num3 = 2 * num3 + (num > BadTriQueue.SQRT2 ? 1 : 0);
            num1 = (num2 <= 0 ? 2048 + num3 : 2047 - num3);
            if (this.queuefront[num1] != null)
            {
                this.queuetail[num1].nexttriang = badtri;
            }
            else
            {
                if (num1 <= this.firstnonemptyq)
                {
                    int num5 = num1 + 1;
                    while (this.queuefront[num5] == null)
                    {
                        num5++;
                    }
                    this.nextnonemptyq[num1] = this.nextnonemptyq[num5];
                    this.nextnonemptyq[num5] = num1;
                }
                else
                {
                    this.nextnonemptyq[num1] = this.firstnonemptyq;
                    this.firstnonemptyq      = num1;
                }
                this.queuefront[num1] = badtri;
            }
            this.queuetail[num1] = badtri;
            badtri.nexttriang    = null;
        }
Пример #3
0
        /// <summary>
        /// Add a bad triangle to the end of a queue.
        /// </summary>
        /// <param name="enqtri"></param>
        /// <param name="minedge"></param>
        /// <param name="enqapex"></param>
        /// <param name="enqorg"></param>
        /// <param name="enqdest"></param>
        public void Enqueue(ref Otri enqtri, double minedge, Vertex enqapex, Vertex enqorg, Vertex enqdest)
        {
            // Allocate space for the bad triangle.
            BadTriangle newbad = new BadTriangle();

            newbad.poortri    = enqtri;
            newbad.key        = minedge;
            newbad.triangapex = enqapex;
            newbad.triangorg  = enqorg;
            newbad.triangdest = enqdest;

            Enqueue(newbad);
        }
Пример #4
0
        public void Enqueue(ref Otri enqtri, double minedge, Vertex enqapex, Vertex enqorg, Vertex enqdest)
        {
            BadTriangle badTriangle = new BadTriangle()
            {
                poortri    = enqtri,
                key        = minedge,
                triangapex = enqapex,
                triangorg  = enqorg,
                triangdest = enqdest
            };

            this.Enqueue(badTriangle);
        }
Пример #5
0
        public BadTriangle Dequeue()
        {
            if (this.firstnonemptyq < 0)
            {
                return(null);
            }
            this.count = this.count - 1;
            BadTriangle badTriangle = this.queuefront[this.firstnonemptyq];

            this.queuefront[this.firstnonemptyq] = badTriangle.nexttriang;
            if (badTriangle == this.queuetail[this.firstnonemptyq])
            {
                this.firstnonemptyq = this.nextnonemptyq[this.firstnonemptyq];
            }
            return(badTriangle);
        }
Пример #6
0
        /// <summary>
        /// Remove a triangle from the front of the queue.
        /// </summary>
        /// <returns></returns>
        public BadTriangle Dequeue()
        {
            // If no queues are nonempty, return NULL.
            if (firstnonemptyq < 0)
            {
                return(null);
            }

            this.count--;

            // Find the first triangle of the highest-priority queue.
            BadTriangle result = queuefront[firstnonemptyq];

            // Remove the triangle from the queue.
            queuefront[firstnonemptyq] = result.nexttriang;
            // If this queue is now empty, note the new highest-priority
            // nonempty queue.
            if (result == queuetail[firstnonemptyq])
            {
                firstnonemptyq = nextnonemptyq[firstnonemptyq];
            }

            return(result);
        }
Пример #7
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.");
                }
            }
        }
Пример #8
0
        /// <summary>
        /// Add a bad triangle data structure to the end of a queue.
        /// </summary>
        /// <param name="badtri">The bad triangle to enqueue.</param>
        public void Enqueue(BadTriangle badtri)
        {
            double length, multiplier;
            int    exponent, expincrement;
            int    queuenumber;
            int    posexponent;
            int    i;

            this.count++;

            // Determine the appropriate queue to put the bad triangle into.
            // Recall that the key is the square of its shortest edge length.
            if (badtri.key >= 1.0)
            {
                length      = badtri.key;
                posexponent = 1;
            }
            else
            {
                // 'badtri.key' is 2.0 to a negative exponent, so we'll record that
                // fact and use the reciprocal of 'badtri.key', which is > 1.0.
                length      = 1.0 / badtri.key;
                posexponent = 0;
            }
            // 'length' is approximately 2.0 to what exponent?  The following code
            // determines the answer in time logarithmic in the exponent.
            exponent = 0;
            while (length > 2.0)
            {
                // Find an approximation by repeated squaring of two.
                expincrement = 1;
                multiplier   = 0.5;
                while (length * multiplier * multiplier > 1.0)
                {
                    expincrement *= 2;
                    multiplier   *= multiplier;
                }
                // Reduce the value of 'length', then iterate if necessary.
                exponent += expincrement;
                length   *= multiplier;
            }
            // 'length' is approximately squareroot(2.0) to what exponent?
            exponent = 2 * exponent + (length > SQRT2 ? 1 : 0);
            // 'exponent' is now in the range 0...2047 for IEEE double precision.
            // Choose a queue in the range 0...4095.  The shortest edges have the
            // highest priority (queue 4095).
            if (posexponent > 0)
            {
                queuenumber = 2047 - exponent;
            }
            else
            {
                queuenumber = 2048 + exponent;
            }

            // Are we inserting into an empty queue?
            if (queuefront[queuenumber] == null)
            {
                // Yes, we are inserting into an empty queue.
                // Will this become the highest-priority queue?
                if (queuenumber > firstnonemptyq)
                {
                    // Yes, this is the highest-priority queue.
                    nextnonemptyq[queuenumber] = firstnonemptyq;
                    firstnonemptyq             = queuenumber;
                }
                else
                {
                    // No, this is not the highest-priority queue.
                    // Find the queue with next higher priority.
                    i = queuenumber + 1;
                    while (queuefront[i] == null)
                    {
                        i++;
                    }
                    // Mark the newly nonempty queue as following a higher-priority queue.
                    nextnonemptyq[queuenumber] = nextnonemptyq[i];
                    nextnonemptyq[i]           = queuenumber;
                }
                // Put the bad triangle at the beginning of the (empty) queue.
                queuefront[queuenumber] = badtri;
            }
            else
            {
                // Add the bad triangle to the end of an already nonempty queue.
                queuetail[queuenumber].nexttriang = badtri;
            }
            // Maintain a pointer to the last triangle of the queue.
            queuetail[queuenumber] = badtri;
            // Newly enqueued bad triangle has no successor in the queue.
            badtri.nexttriang = null;
        }
Пример #9
0
 public static void FreeBadTri(BadTriangle badTri)
 {
     badTri.Reset();
     BadTriStack.Push(badTri);
 }
Пример #10
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.");
                }
            }
        }
Пример #11
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
            double             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.tri) && (borg == badtri.org) &&
                (bdest == badtri.dest) && (bapex == badtri.apex))
            {
                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?
                newloc = RobustPredicates.FindCircumcenter(borg, bdest, bapex, ref xi, ref eta, behavior.offconstant);

                // 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)))
                {
                    //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);
                    newvertex.type = VertexType.FreeVertex;

                    // 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.Lprev();
                    }

                    // 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.Id = mesh.hash_vtx++;

                        mesh.vertices.Add(newvertex.Id, 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
                    {
                        //errorflag = true;
                    }
                }
                if (errorflag)
                {
                    throw new Exception("The new vertex is at the circumcenter of triangle.");
                }
            }
        }