예제 #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 == Mesh.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 == Mesh.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();
        }
예제 #2
0
 /// <summary>
 /// Set the region attribute of all trianlges connected to given triangle.
 /// </summary>
 /// <param name="triangle">The triangle seed.</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, int boundary = 0)
 {
     this.Process(triangle, (tri) =>
     {
         // Set the region id and area constraint.
         tri.label = triangle.label;
         tri.area = triangle.area;
     }, boundary);
 }
예제 #3
0
        public QualityMesher(Mesh mesh, Configuration config)
        {
            logger = Log.Instance;

            badsubsegs = new Queue<BadSubseg>();
            queue = new BadTriQueue();

            this.mesh = mesh;
            this.predicates = config.Predicates();

            this.behavior = mesh.behavior;

            newLocation = new NewLocation(mesh, predicates);

            newvertex_tri = new Triangle();
        }
예제 #4
0
    /**
     * Defines if points is inside triangle
     * Based on http://wiki.unity3d.com/index.php?title=PolyContainsPoint
     */
    public static bool ContainsPoint(this TriangleNet.Topology.Triangle triangle, Vector3 p)
    {
        Vector3[] v = triangle.vertices.Select(vert => vert.ToVector3()).ToArray();

        int  j      = v.Length - 1; // Last index
        bool inside = false;

        for (int i = 0; i < v.Length; j = i++)
        {
            if (((v[i].z <= p.z && p.z < v[j].z) || (v[j].z <= p.z && p.z < v[i].z)) &&
                (p.x < (v[j].x - v[i].x) * (p.z - v[i].z) / (v[j].z - v[i].z) + v[i].x))
            {
                inside = !inside;
            }
        }
        return(inside);
    }
예제 #5
0
 /// <summary>
 /// Dissolve a bond (from one side).  
 /// </summary>
 /// <remarks>Note that the other triangle will still think it's connected to 
 /// this triangle. Usually, however, the other triangle is being deleted 
 /// entirely, or bonded to another triangle, so it doesn't matter.
 /// </remarks>
 internal void Dissolve(Triangle dummy)
 {
     tri.neighbors[orient].tri = dummy;
     tri.neighbors[orient].orient = 0;
 }
예제 #6
0
 /// <summary>
 /// Dissolve a bond (from the subsegment side).
 /// </summary>
 internal void TriDissolve(Triangle dummy)
 {
     seg.triangles[orient].tri = dummy;
 }
예제 #7
0
        private void Initialize()
        {
            dummysub = new SubSegment();
            dummysub.hash = DUMMY;

            // Initialize the two adjoining subsegments to be the omnipresent
            // subsegment. These will eventually be changed by various bonding
            // operations, but their values don't really matter, as long as they
            // can legally be dereferenced.
            dummysub.subsegs[0].seg = dummysub;
            dummysub.subsegs[1].seg = dummysub;

            // Set up 'dummytri', the 'triangle' that occupies "outer space."
            dummytri = new Triangle();
            dummytri.hash = dummytri.id = DUMMY;

            // Initialize the three adjoining triangles to be "outer space." These
            // will eventually be changed by various bonding operations, but their
            // values don't really matter, as long as they can legally be
            // dereferenced.
            dummytri.neighbors[0].tri = dummytri;
            dummytri.neighbors[1].tri = dummytri;
            dummytri.neighbors[2].tri = dummytri;

            // Initialize the three adjoining subsegments of 'dummytri' to be
            // the omnipresent subsegment.
            dummytri.subsegs[0].seg = dummysub;
            dummytri.subsegs[1].seg = dummysub;
            dummytri.subsegs[2].seg = dummysub;
        }
예제 #8
0
 /// <summary>
 /// Deallocate space for a triangle, marking it dead.
 /// </summary>
 /// <param name="dyingtriangle"></param>
 internal void TriangleDealloc(Triangle dyingtriangle)
 {
     // Mark the triangle as dead. This makes it possible to detect dead 
     // triangles when traversing the list of all triangles.
     Otri.Kill(dyingtriangle);
     triangles.Release(dyingtriangle);
 }
예제 #9
0
 public GraphNode(TriangleNet.Topology.Triangle triangle)
 {
     this.triangle = triangle;
     this.center   = new PointStruct(triangle.GetCentroid());
 }
예제 #10
0
 /// <summary>
 /// Find the abutting triangle; same edge. [sym(abc) -> ba*]
 /// </summary>
 public void Sym()
 {
     int tmp = orient;
     orient = tri.neighbors[tmp].orient;
     tri = tri.neighbors[tmp].tri;
 }
예제 #11
0
 /// <summary>
 /// Set a triangle's deallocation.
 /// </summary>
 internal static void Kill(Triangle tri)
 {
     tri.neighbors[0].tri = null;
     tri.neighbors[2].tri = null;
 }
예제 #12
0
 /// <summary>
 /// Check a triangle's deallocation.
 /// </summary>
 internal static bool IsDead(Triangle tria)
 {
     return tria.neighbors[0].tri == null;
 }
예제 #13
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>
        private void CarveHoles()
        {
            Otri searchtri = default(Otri);
            Vertex searchorg, searchdest;
            LocateResult intersect;

            Triangle[] regionTris = null;

            var dummytri = mesh.dummytri;

            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.tri = dummytri;
                        searchtri.orient = 0;
                        searchtri.Sym();
                        // 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 (predicates.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.tri);
                            }
                        }
                    }
                }
            }

            // 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] = 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.tri = dummytri;
                        searchtri.orient = 0;
                        searchtri.Sym();
                        // 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 (predicates.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.tri;
                                regionTris[i].label = region.id;
                                regionTris[i].area = region.area;
                            }
                        }
                    }

                    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].id != Mesh.DUMMY)
                    {
                        // 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();
        }
예제 #14
0
        /// <summary>
        /// Find the previous edge (clockwise) of the adjacent triangle. [rprev(abc) -> b**]
        /// </summary>
        public void Rprev()
        {
            //SymSelf();
            int tmp = orient;
            orient = tri.neighbors[tmp].orient;
            tri = tri.neighbors[tmp].tri;

            //LprevSelf();
            orient = minus1Mod3[orient];

            //SymSelf();
            tmp = orient;
            orient = tri.neighbors[tmp].orient;
            tri = tri.neighbors[tmp].tri;
        }
예제 #15
0
        /// <summary>
        /// Find the next edge (counterclockwise) of the adjacent triangle. [rnext(abc) -> *a*]
        /// </summary>
        public void Rnext()
        {
            //SymSelf();
            int tmp = orient;
            orient = tri.neighbors[tmp].orient;
            tri = tri.neighbors[tmp].tri;

            //LnextSelf();
            orient = plus1Mod3[orient];

            //SymSelf();
            tmp = orient;
            orient = tri.neighbors[tmp].orient;
            tri = tri.neighbors[tmp].tri;
        }
예제 #16
0
        /// <summary>
        /// Create a new triangle with orientation zero.
        /// </summary>
        /// <param name="newotri">Reference to the new triangle.</param>
        internal void MakeTriangle(ref Otri newotri)
        {
            Triangle tri = new Triangle();

            tri.hash = tri.id = this.hash_tri++;

            tri.subsegs[0].seg = dummysub;
            tri.subsegs[1].seg = dummysub;
            tri.subsegs[2].seg = dummysub;

            tri.neighbors[0].tri = dummytri;
            tri.neighbors[1].tri = dummytri;
            tri.neighbors[2].tri = dummytri;

            newotri.tri = tri;
            newotri.orient = 0;

            triangles.Add(tri.hash, tri);
        }
예제 #17
0
 /// <summary>
 /// Set the region attribute of all trianlges connected to given triangle.
 /// </summary>
 public void Process(Triangle triangle)
 {
     // Default action is to just set the region id for all trianlges.
     this.Process(triangle, (tri) => { tri.label = triangle.label; });
 }
예제 #18
0
        /// <summary>
        /// Process all trianlges connected to given triangle and apply given action.
        /// </summary>
        public void Process(Triangle triangle, Action<Triangle> func)
        {
            if (triangle.id != Mesh.DUMMY)
            {
                // 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();
        }