Exemple #1
0
        /// <summary>
        /// Process all trianlges connected to given triangle and apply given action.
        /// </summary>
        /// <param name="triangle">The seeding triangle.</param>
        /// <param name="action">The action to apply to each triangle.</param>
        /// <param name="boundary">If non-zero, process all triangles of the
        /// region that is enclosed by segments with given boundary label.</param>
        public void Process(Triangle triangle, Action <Triangle> action, int boundary = 0)
        {
            // Make sure the triangle under consideration still exists.
            // It may have been eaten by the virus.
            if (triangle.id == TriangleNetMesh.DUMMY || Otri.IsDead(triangle))
            {
                return;
            }

            // Add the seeding triangle to the region.
            region.Add(triangle);

            triangle.infected = true;

            if (boundary == 0)
            {
                // Stop at any subsegment.
                ProcessRegion(action, seg => seg.hash == TriangleNetMesh.DUMMY);
            }
            else
            {
                // Stop at segments that have the given boundary label.
                ProcessRegion(action, seg => seg.boundary != boundary);
            }

            // Free up memory (virus pool should be empty anyway).
            region.Clear();
        }
Exemple #2
0
 public void Process(Triangle triangle, Action <Triangle> func)
 {
     if (triangle != Mesh.dummytri && !Otri.IsDead(triangle))
     {
         triangle.infected = true;
         this.viri.Add(triangle);
         this.ProcessRegion(func);
     }
     this.viri.Clear();
 }
Exemple #3
0
        public bool CheckDelaunay()
        {
            Otri otri    = new Otri();
            Otri otri1   = new Otri();
            Osub osub    = new Osub();
            bool noExact = Behavior.NoExact;

            Behavior.NoExact = false;
            int num = 0;

            foreach (Triangle value in this.mesh.triangles.Values)
            {
                otri.triangle = value;
                otri.orient   = 0;
                while (otri.orient < 3)
                {
                    Vertex vertex  = otri.Org();
                    Vertex vertex1 = otri.Dest();
                    Vertex vertex2 = otri.Apex();
                    otri.Sym(ref otri1);
                    Vertex vertex3 = otri1.Apex();
                    bool   flag    = (otri1.triangle == Mesh.dummytri || Otri.IsDead(otri1.triangle) || otri.triangle.id >= otri1.triangle.id || !(vertex != this.mesh.infvertex1) || !(vertex != this.mesh.infvertex2) || !(vertex != this.mesh.infvertex3) || !(vertex1 != this.mesh.infvertex1) || !(vertex1 != this.mesh.infvertex2) || !(vertex1 != this.mesh.infvertex3) || !(vertex2 != this.mesh.infvertex1) || !(vertex2 != this.mesh.infvertex2) || !(vertex2 != this.mesh.infvertex3) || !(vertex3 != this.mesh.infvertex1) || !(vertex3 != this.mesh.infvertex2) ? false : vertex3 != this.mesh.infvertex3);
                    if (this.mesh.checksegments & flag)
                    {
                        otri.SegPivot(ref osub);
                        if (osub.seg != Mesh.dummysub)
                        {
                            flag = false;
                        }
                    }
                    if (flag && Primitives.NonRegular(vertex, vertex1, vertex2, vertex3) > 0)
                    {
                        this.logger.Warning(string.Format("Non-regular pair of triangles found (IDs {0}/{1}).", otri.triangle.id, otri1.triangle.id), "Quality.CheckDelaunay()");
                        num++;
                    }
                    otri.orient = otri.orient + 1;
                }
            }
            if (num == 0)
            {
                this.logger.Info("Mesh is Delaunay.");
            }
            Behavior.NoExact = noExact;
            return(num == 0);
        }
Exemple #4
0
        /// <summary>
        /// Process all trianlges connected to given triangle and apply given action.
        /// </summary>
        public void Process(Triangle triangle, Action <Triangle> func)
        {
            if (triangle != Mesh.dummytri)
            {
                // Make sure the triangle under consideration still exists.
                // It may have been eaten by the virus.
                if (!Otri.IsDead(triangle))
                {
                    // Put one triangle in the virus pool.
                    triangle.infected = true;
                    viri.Add(triangle);
                    // Apply one region's attribute and/or area constraint.
                    ProcessRegion(func);
                    // The virus pool should be empty now.
                }
            }

            // Free up memory (virus pool should be empty anyway).
            viri.Clear();
        }
        /// <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.");
                }
            }
        }
        /// <summary>
        /// Ensure that the mesh is (constrained) Delaunay.
        /// </summary>
        public bool CheckDelaunay()
        {
            Otri   loop = default(Otri);
            Otri   oppotri = default(Otri);
            Osub   opposubseg = default(Osub);
            Vertex triorg, tridest, triapex;
            Vertex oppoapex;
            bool   shouldbedelaunay;
            int    horrors;
            bool   saveexact;

            // Temporarily turn on exact arithmetic if it's off.
            saveexact        = Behavior.NoExact;
            Behavior.NoExact = false;
            horrors          = 0;

            // Run through the list of triangles, checking each one.
            foreach (var tri in mesh.triangles.Values)
            {
                loop.triangle = tri;

                // Check all three edges of the triangle.
                for (loop.orient = 0; loop.orient < 3;
                     loop.orient++)
                {
                    triorg  = loop.Org();
                    tridest = loop.Dest();
                    triapex = loop.Apex();
                    loop.Sym(ref oppotri);
                    oppoapex = oppotri.Apex();
                    // Only test that the edge is locally Delaunay if there is an
                    // adjoining triangle whose pointer is larger (to ensure that
                    // each pair isn't tested twice).
                    shouldbedelaunay = (oppotri.triangle != Mesh.dummytri) &&
                                       !Otri.IsDead(oppotri.triangle) && loop.triangle.id < oppotri.triangle.id &&
                                       (triorg != mesh.infvertex1) && (triorg != mesh.infvertex2) &&
                                       (triorg != mesh.infvertex3) &&
                                       (tridest != mesh.infvertex1) && (tridest != mesh.infvertex2) &&
                                       (tridest != mesh.infvertex3) &&
                                       (triapex != mesh.infvertex1) && (triapex != mesh.infvertex2) &&
                                       (triapex != mesh.infvertex3) &&
                                       (oppoapex != mesh.infvertex1) && (oppoapex != mesh.infvertex2) &&
                                       (oppoapex != mesh.infvertex3);
                    if (mesh.checksegments && shouldbedelaunay)
                    {
                        // If a subsegment separates the triangles, then the edge is
                        // constrained, so no local Delaunay test should be done.
                        loop.SegPivot(ref opposubseg);
                        if (opposubseg.seg != Mesh.dummysub)
                        {
                            shouldbedelaunay = false;
                        }
                    }
                    if (shouldbedelaunay)
                    {
                        if (Primitives.NonRegular(triorg, tridest, triapex, oppoapex) > 0.0)
                        {
                            logger.Warning(String.Format("Non-regular pair of triangles found (IDs {0}/{1}).",
                                                         loop.triangle.id, oppotri.triangle.id), "Quality.CheckDelaunay()");
                            horrors++;
                        }
                    }
                }
            }

            if (horrors == 0) // && Behavior.Verbose
            {
                logger.Info("Mesh is Delaunay.");
            }

            // Restore the status of exact arithmetic.
            Behavior.NoExact = saveexact;

            return(horrors == 0);
        }
Exemple #7
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>
        /// <returns>Location information.</returns>
        /// <remarks>
        /// Searching begins from one of:  the input 'searchtri', a recently
        /// encountered triangle 'recenttri', or from a triangle chosen from a
        /// random sample. The choice is made by determining which triangle's
        /// origin is closest to the point we are searching for. Normally,
        /// 'searchtri' should be a handle on the convex hull of the triangulation.
        ///
        /// Details on the random sampling method can be found in the Mucke, Saias,
        /// and Zhu paper cited in the header of this code.
        ///
        /// On completion, 'searchtri' is a triangle that contains 'searchpoint'.
        ///
        /// 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.
        /// </remarks>
        public LocateResult Locate(Point searchpoint, ref Otri searchtri)
        {
            Otri   sampletri = default(Otri);
            Vertex torg, tdest;
            double searchdist, dist;
            double ahead;

            // Record the distance from the suggested starting triangle to the
            // point we seek.
            torg       = searchtri.Org();
            searchdist = (searchpoint.X - torg.x) * (searchpoint.X - torg.x) +
                         (searchpoint.Y - torg.y) * (searchpoint.Y - torg.y);

            // If a recently encountered triangle has been recorded and has not been
            // deallocated, test it as a good starting point.
            if (recenttri.triangle != null)
            {
                if (!Otri.IsDead(recenttri.triangle))
                {
                    torg = recenttri.Org();
                    if ((torg.x == searchpoint.X) && (torg.y == searchpoint.Y))
                    {
                        recenttri.Copy(ref searchtri);
                        return(LocateResult.OnVertex);
                    }
                    dist = (searchpoint.X - torg.x) * (searchpoint.X - torg.x) +
                           (searchpoint.Y - torg.y) * (searchpoint.Y - torg.y);
                    if (dist < searchdist)
                    {
                        recenttri.Copy(ref searchtri);
                        searchdist = dist;
                    }
                }
            }

            // TODO: Improve sampling.
            sampler.Update(mesh);
            int[] samples = sampler.GetSamples(mesh);

            foreach (var key in samples)
            {
                sampletri.triangle = mesh.triangles[key];
                if (!Otri.IsDead(sampletri.triangle))
                {
                    torg = sampletri.Org();
                    dist = (searchpoint.X - torg.x) * (searchpoint.X - torg.x) +
                           (searchpoint.Y - torg.y) * (searchpoint.Y - torg.y);
                    if (dist < searchdist)
                    {
                        sampletri.Copy(ref searchtri);
                        searchdist = dist;
                    }
                }
            }

            // Where are we?
            torg  = searchtri.Org();
            tdest = searchtri.Dest();
            // Check the starting triangle's vertices.
            if ((torg.x == searchpoint.X) && (torg.y == searchpoint.Y))
            {
                return(LocateResult.OnVertex);
            }
            if ((tdest.x == searchpoint.X) && (tdest.y == searchpoint.Y))
            {
                searchtri.LnextSelf();
                return(LocateResult.OnVertex);
            }
            // Orient 'searchtri' to fit the preconditions of calling preciselocate().
            ahead = Primitives.CounterClockwise(torg, tdest, searchpoint);
            if (ahead < 0.0)
            {
                // Turn around so that 'searchpoint' is to the left of the
                // edge specified by 'searchtri'.
                searchtri.SymSelf();
            }
            else if (ahead == 0.0)
            {
                // Check if 'searchpoint' is between 'torg' and 'tdest'.
                if (((torg.x < searchpoint.X) == (searchpoint.X < tdest.x)) &&
                    ((torg.y < searchpoint.Y) == (searchpoint.Y < tdest.y)))
                {
                    return(LocateResult.OnEdge);
                }
            }
            return(PreciseLocate(searchpoint, ref searchtri, false));
        }
Exemple #8
0
        /// <summary>
        /// Ensure that the mesh is (constrained) Delaunay.
        /// </summary>
        private static bool IsDelaunay(Mesh mesh, bool constrained)
        {
            Otri   loop = default(Otri);
            Otri   oppotri = default(Otri);
            Osub   opposubseg = default(Osub);
            Vertex org, dest, apex;
            Vertex oppoapex;

            bool shouldbedelaunay;

            var logger = Log.Instance;

            // Temporarily turn on exact arithmetic if it's off.
            bool saveexact = Behavior.NoExact;

            Behavior.NoExact = false;

            int horrors = 0;

            var inf1 = mesh.infvertex1;
            var inf2 = mesh.infvertex2;
            var inf3 = mesh.infvertex3;

            // Run through the list of triangles, checking each one.
            foreach (var tri in mesh.triangles)
            {
                loop.tri = tri;

                // Check all three edges of the triangle.
                for (loop.orient = 0; loop.orient < 3; loop.orient++)
                {
                    org  = loop.Org();
                    dest = loop.Dest();
                    apex = loop.Apex();

                    loop.Sym(ref oppotri);
                    oppoapex = oppotri.Apex();

                    // Only test that the edge is locally Delaunay if there is an
                    // adjoining triangle whose pointer is larger (to ensure that
                    // each pair isn't tested twice).
                    shouldbedelaunay = (loop.tri.id < oppotri.tri.id) &&
                                       !Otri.IsDead(oppotri.tri) && (oppotri.tri.id != Mesh.DUMMY) &&
                                       (org != inf1) && (org != inf2) && (org != inf3) &&
                                       (dest != inf1) && (dest != inf2) && (dest != inf3) &&
                                       (apex != inf1) && (apex != inf2) && (apex != inf3) &&
                                       (oppoapex != inf1) && (oppoapex != inf2) && (oppoapex != inf3);

                    if (constrained && mesh.checksegments && shouldbedelaunay)
                    {
                        // If a subsegment separates the triangles, then the edge is
                        // constrained, so no local Delaunay test should be done.
                        loop.Pivot(ref opposubseg);

                        if (opposubseg.seg.hash != Mesh.DUMMY)
                        {
                            shouldbedelaunay = false;
                        }
                    }

                    if (shouldbedelaunay)
                    {
                        if (predicates.NonRegular(org, dest, apex, oppoapex) > 0.0)
                        {
                            if (Log.Verbose)
                            {
                                logger.Warning(String.Format("Non-regular pair of triangles found (IDs {0}/{1}).",
                                                             loop.tri.id, oppotri.tri.id), "MeshValidator.IsDelaunay()");
                            }

                            horrors++;
                        }
                    }
                }
            }

            // Restore the status of exact arithmetic.
            Behavior.NoExact = saveexact;

            return(horrors == 0);
        }
Exemple #9
0
        /// <summary>
        /// Find the holes and infect them. Find the area constraints and infect
        /// them. Infect the convex hull. Spread the infection and kill triangles.
        /// Spread the area constraints.
        /// </summary>
        public void CarveHoles()
        {
            Otri         searchtri = default(Otri);
            Vertex       searchorg, searchdest;
            LocateResult intersect;

            Triangle[] regionTris = null;

            if (!mesh.behavior.Convex)
            {
                // Mark as infected any unprotected triangles on the boundary.
                // This is one way by which concavities are created.
                InfectHull();
            }

            if (!mesh.behavior.NoHoles)
            {
                // Infect each triangle in which a hole lies.
                foreach (var hole in mesh.holes)
                {
                    // Ignore holes that aren't within the bounds of the mesh.
                    if (mesh.bounds.Contains(hole))
                    {
                        // Start searching from some triangle on the outer boundary.
                        searchtri.triangle = Mesh.dummytri;
                        searchtri.orient   = 0;
                        searchtri.SymSelf();
                        // Ensure that the hole is to the left of this boundary edge;
                        // otherwise, locate() will falsely report that the hole
                        // falls within the starting triangle.
                        searchorg  = searchtri.Org();
                        searchdest = searchtri.Dest();
                        if (Primitives.CounterClockwise(searchorg, searchdest, hole) > 0.0)
                        {
                            // Find a triangle that contains the hole.
                            intersect = mesh.locator.Locate(hole, ref searchtri);
                            if ((intersect != LocateResult.Outside) && (!searchtri.IsInfected()))
                            {
                                // Infect the triangle. This is done by marking the triangle
                                // as infected and including the triangle in the virus pool.
                                searchtri.Infect();
                                viri.Add(searchtri.triangle);
                            }
                        }
                    }
                }
            }

            // Now, we have to find all the regions BEFORE we carve the holes, because locate() won't
            // work when the triangulation is no longer convex. (Incidentally, this is the reason why
            // regional attributes and area constraints can't be used when refining a preexisting mesh,
            // which might not be convex; they can only be used with a freshly triangulated PSLG.)
            if (mesh.regions.Count > 0)
            {
                int i = 0;

                regionTris = new Triangle[mesh.regions.Count];

                // Find the starting triangle for each region.
                foreach (var region in mesh.regions)
                {
                    regionTris[i] = Mesh.dummytri;
                    // Ignore region points that aren't within the bounds of the mesh.
                    if (mesh.bounds.Contains(region.point))
                    {
                        // Start searching from some triangle on the outer boundary.
                        searchtri.triangle = Mesh.dummytri;
                        searchtri.orient   = 0;
                        searchtri.SymSelf();
                        // Ensure that the region point is to the left of this boundary
                        // edge; otherwise, locate() will falsely report that the
                        // region point falls within the starting triangle.
                        searchorg  = searchtri.Org();
                        searchdest = searchtri.Dest();
                        if (Primitives.CounterClockwise(searchorg, searchdest, region.point) > 0.0)
                        {
                            // Find a triangle that contains the region point.
                            intersect = mesh.locator.Locate(region.point, ref searchtri);
                            if ((intersect != LocateResult.Outside) && (!searchtri.IsInfected()))
                            {
                                // Record the triangle for processing after the
                                // holes have been carved.
                                regionTris[i]        = searchtri.triangle;
                                regionTris[i].region = region.id;
                            }
                        }
                    }

                    i++;
                }
            }

            if (viri.Count > 0)
            {
                // Carve the holes and concavities.
                Plague();
            }

            if (regionTris != null)
            {
                var iterator = new RegionIterator(mesh);

                for (int i = 0; i < regionTris.Length; i++)
                {
                    if (regionTris[i] != Mesh.dummytri)
                    {
                        // Make sure the triangle under consideration still exists.
                        // It may have been eaten by the virus.
                        if (!Otri.IsDead(regionTris[i]))
                        {
                            // Apply one region's attribute and/or area constraint.
                            iterator.Process(regionTris[i]);
                        }
                    }
                }
            }

            // Free up memory (virus pool should be empty anyway).
            viri.Clear();
        }
Exemple #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.");
                }
            }
        }
        /// <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.");
                }
            }
        }
        public LocateResult Locate(Point searchpoint, ref Otri searchtri)
        {
            double x;
            Otri   item   = new Otri();
            Vertex vertex = searchtri.Org();
            double num    = (searchpoint.X - vertex.x) * (searchpoint.X - vertex.x) + (searchpoint.Y - vertex.y) * (searchpoint.Y - vertex.y);

            if (this.recenttri.triangle != null && !Otri.IsDead(this.recenttri.triangle))
            {
                vertex = this.recenttri.Org();
                if (vertex.x == searchpoint.X && vertex.y == searchpoint.Y)
                {
                    this.recenttri.Copy(ref searchtri);
                    return(LocateResult.OnVertex);
                }
                x = (searchpoint.X - vertex.x) * (searchpoint.X - vertex.x) + (searchpoint.Y - vertex.y) * (searchpoint.Y - vertex.y);
                if (x < num)
                {
                    this.recenttri.Copy(ref searchtri);
                    num = x;
                }
            }
            this.sampler.Update(this.mesh);
            int[] samples = this.sampler.GetSamples(this.mesh);
            for (int i = 0; i < (int)samples.Length; i++)
            {
                int num1 = samples[i];
                item.triangle = this.mesh.triangles[num1];
                if (!Otri.IsDead(item.triangle))
                {
                    vertex = item.Org();
                    x      = (searchpoint.X - vertex.x) * (searchpoint.X - vertex.x) + (searchpoint.Y - vertex.y) * (searchpoint.Y - vertex.y);
                    if (x < num)
                    {
                        item.Copy(ref searchtri);
                        num = x;
                    }
                }
            }
            vertex = searchtri.Org();
            Vertex vertex1 = searchtri.Dest();

            if (vertex.x == searchpoint.X && vertex.y == searchpoint.Y)
            {
                return(LocateResult.OnVertex);
            }
            if (vertex1.x == searchpoint.X && vertex1.y == searchpoint.Y)
            {
                searchtri.LnextSelf();
                return(LocateResult.OnVertex);
            }
            double num2 = Primitives.CounterClockwise(vertex, vertex1, searchpoint);

            if (num2 < 0)
            {
                searchtri.SymSelf();
            }
            else if (num2 == 0 && vertex.x < searchpoint.X == searchpoint.X < vertex1.x && vertex.y < searchpoint.Y == searchpoint.Y < vertex1.y)
            {
                return(LocateResult.OnEdge);
            }
            return(this.PreciseLocate(searchpoint, ref searchtri, false));
        }
Exemple #13
0
        public void CarveHoles()
        {
            Otri otri = new Otri();

            Triangle[] triangleArray = null;
            if (!this.mesh.behavior.Convex)
            {
                this.InfectHull();
            }
            if (!this.mesh.behavior.NoHoles)
            {
                foreach (Point hole in this.mesh.holes)
                {
                    if (!this.mesh.bounds.Contains(hole))
                    {
                        continue;
                    }
                    otri.triangle = Mesh.dummytri;
                    otri.orient   = 0;
                    otri.SymSelf();
                    if (Primitives.CounterClockwise(otri.Org(), otri.Dest(), hole) <= 0 || this.mesh.locator.Locate(hole, ref otri) == LocateResult.Outside || otri.IsInfected())
                    {
                        continue;
                    }
                    otri.Infect();
                    this.viri.Add(otri.triangle);
                }
            }
            if (this.mesh.regions.Count > 0)
            {
                int num = 0;
                triangleArray = new Triangle[this.mesh.regions.Count];
                foreach (RegionPointer region in this.mesh.regions)
                {
                    triangleArray[num] = Mesh.dummytri;
                    if (this.mesh.bounds.Contains(region.point))
                    {
                        otri.triangle = Mesh.dummytri;
                        otri.orient   = 0;
                        otri.SymSelf();
                        if (Primitives.CounterClockwise(otri.Org(), otri.Dest(), region.point) > 0 && this.mesh.locator.Locate(region.point, ref otri) != LocateResult.Outside && !otri.IsInfected())
                        {
                            triangleArray[num]        = otri.triangle;
                            triangleArray[num].region = region.id;
                        }
                    }
                    num++;
                }
            }
            if (this.viri.Count > 0)
            {
                this.Plague();
            }
            if (triangleArray != null)
            {
                RegionIterator regionIterator = new RegionIterator(this.mesh);
                for (int i = 0; i < (int)triangleArray.Length; i++)
                {
                    if (triangleArray[i] != Mesh.dummytri && !Otri.IsDead(triangleArray[i]))
                    {
                        regionIterator.Process(triangleArray[i]);
                    }
                }
            }
            this.viri.Clear();
        }