Пример #1
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);
        }
Пример #2
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;
        }
Пример #3
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.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.");
                }
            }
        }