CounterClockwise() public static method

Check, if the three points appear in counterclockwise order. The result is also a rough approximation of twice the signed area of the triangle defined by the three points.
Uses exact arithmetic if necessary to ensure a correct answer. The result returned is the determinant of a matrix. This determinant is computed adaptively, in the sense that exact arithmetic is used only to the degree it is needed to ensure that the returned value has the correct sign. Hence, this function is usually quite fast, but will run more slowly when the input points are collinear or nearly so. See Robust Predicates paper for details.
public static CounterClockwise ( System.Point pa, System.Point pb, System.Point pc ) : double
pa System.Point Point a.
pb System.Point Point b.
pc System.Point Point c.
return double
Example #1
0
        public static Point FindCircumcenter(Point torg, Point tdest, Point tapex, ref double xi, ref double eta)
        {
            double num;

            Statistic.CircumcenterCount = Statistic.CircumcenterCount + (long)1;
            double num1 = tdest.x - torg.x;
            double num2 = tdest.y - torg.y;
            double num3 = tapex.x - torg.x;
            double num4 = tapex.y - torg.y;
            double num5 = num1 * num1 + num2 * num2;
            double num6 = num3 * num3 + num4 * num4;

            if (!Behavior.NoExact)
            {
                num = 0.5 / Primitives.CounterClockwise(tdest, tapex, torg);
                Statistic.CounterClockwiseCount = Statistic.CounterClockwiseCount - (long)1;
            }
            else
            {
                num = 0.5 / (num1 * num4 - num3 * num2);
            }
            double num7 = (num4 * num5 - num2 * num6) * num;
            double num8 = (num1 * num6 - num3 * num5) * num;

            xi  = (num4 * num7 - num3 * num8) * (2 * num);
            eta = (num1 * num8 - num2 * num7) * (2 * num);
            return(new Point(torg.x + num7, torg.y + num8));
        }
        /// <summary>
        /// Split all the encroached subsegments.
        /// </summary>
        /// <param name="triflaws">A flag that specifies whether one should take
        /// note of new bad triangles that result from inserting vertices to repair
        /// encroached subsegments.</param>
        /// <remarks>
        /// Each encroached subsegment is repaired by splitting it - inserting a
        /// vertex at or near its midpoint.  Newly inserted vertices may encroach
        /// upon other subsegments; these are also repaired.
        /// </remarks>
        private void SplitEncSegs(bool triflaws)
        {
            Otri               enctri     = default(Otri);
            Otri               testtri    = default(Otri);
            Osub               testsh     = default(Osub);
            Osub               currentenc = default(Osub);
            BadSubseg          seg;
            Vertex             eorg, edest, eapex;
            Vertex             newvertex;
            InsertVertexResult success;
            float              segmentlength, nearestpoweroftwo;
            float              split;
            float              multiplier, divisor;
            bool               acuteorg, acuteorg2, acutedest, acutedest2;

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

                seg = badsubsegs.Dequeue();

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

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

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

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

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

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

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

                    newvertex.type = VertexType.SegmentVertex;

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

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

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

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

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

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

                // Set subsegment's origin to NULL. This makes it possible to detect dead
                // badsubsegs when traversing the list of all badsubsegs.
                seg.subsegorg = null;
            }
        }
        /// <summary>
        /// Test the mesh for topological consistency.
        /// </summary>
        public bool CheckMesh()
        {
            Otri   tri = default(Otri);
            Otri   oppotri = default(Otri), oppooppotri = default(Otri);
            Vertex triorg, tridest, triapex;
            Vertex oppoorg, oppodest;
            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 t in mesh.triangles.Values)
            {
                tri.triangle = t;

                // Check all three edges of the triangle.
                for (tri.orient = 0; tri.orient < 3; tri.orient++)
                {
                    triorg  = tri.Org();
                    tridest = tri.Dest();
                    if (tri.orient == 0)
                    {   // Only test for inversion once.
                        // Test if the triangle is flat or inverted.
                        triapex = tri.Apex();
                        if (Primitives.CounterClockwise(triorg, tridest, triapex) <= 0.0)
                        {
                            logger.Warning("Triangle is flat or inverted.",
                                           "Quality.CheckMesh()");
                            horrors++;
                        }
                    }
                    // Find the neighboring triangle on this edge.
                    tri.Sym(ref oppotri);
                    if (oppotri.triangle != Mesh.dummytri)
                    {
                        // Check that the triangle's neighbor knows it's a neighbor.
                        oppotri.Sym(ref oppooppotri);
                        if ((tri.triangle != oppooppotri.triangle) || (tri.orient != oppooppotri.orient))
                        {
                            if (tri.triangle == oppooppotri.triangle)
                            {
                                logger.Warning("Asymmetric triangle-triangle bond: (Right triangle, wrong orientation)",
                                               "Quality.CheckMesh()");
                            }

                            horrors++;
                        }
                        // Check that both triangles agree on the identities
                        // of their shared vertices.
                        oppoorg  = oppotri.Org();
                        oppodest = oppotri.Dest();
                        if ((triorg != oppodest) || (tridest != oppoorg))
                        {
                            logger.Warning("Mismatched edge coordinates between two triangles.",
                                           "Quality.CheckMesh()");

                            horrors++;
                        }
                    }
                }
            }

            // Check for unconnected vertices
            mesh.MakeVertexMap();
            foreach (var v in mesh.vertices.Values)
            {
                if (v.tri.triangle == null)
                {
                    logger.Warning("Vertex (ID " + v.id + ") not connected to mesh (duplicate input vertex?)",
                                   "Quality.CheckMesh()");
                }
            }

            if (horrors == 0) // && Behavior.Verbose
            {
                logger.Info("Mesh topology appears to be consistent.");
            }

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

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

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

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

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

                fapex = searchtri.Apex();
            }
        }
Example #6
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();
        }
Example #7
0
        public static Point FindCircumcenter(Point torg, Point tdest, Point tapex, ref double xi, ref double eta, double offconstant)
        {
            double num;
            double num1;
            double num2;

            Statistic.CircumcenterCount = Statistic.CircumcenterCount + (long)1;
            double num3 = tdest.x - torg.x;
            double num4 = tdest.y - torg.y;
            double num5 = tapex.x - torg.x;
            double num6 = tapex.y - torg.y;
            double num7 = num3 * num3 + num4 * num4;
            double num8 = num5 * num5 + num6 * num6;
            double num9 = (tdest.x - tapex.x) * (tdest.x - tapex.x) + (tdest.y - tapex.y) * (tdest.y - tapex.y);

            if (!Behavior.NoExact)
            {
                num = 0.5 / Primitives.CounterClockwise(tdest, tapex, torg);
                Statistic.CounterClockwiseCount = Statistic.CounterClockwiseCount - (long)1;
            }
            else
            {
                num = 0.5 / (num3 * num6 - num5 * num4);
            }
            double num10 = (num6 * num7 - num4 * num8) * num;
            double num11 = (num3 * num8 - num5 * num7) * num;

            if (num7 < num8 && num7 < num9)
            {
                if (offconstant > 0)
                {
                    num1 = 0.5 * num3 - offconstant * num4;
                    num2 = 0.5 * num4 + offconstant * num3;
                    if (num1 * num1 + num2 * num2 < num10 * num10 + num11 * num11)
                    {
                        num10 = num1;
                        num11 = num2;
                    }
                }
            }
            else if (num8 < num9)
            {
                if (offconstant > 0)
                {
                    num1 = 0.5 * num5 + offconstant * num6;
                    num2 = 0.5 * num6 - offconstant * num5;
                    if (num1 * num1 + num2 * num2 < num10 * num10 + num11 * num11)
                    {
                        num10 = num1;
                        num11 = num2;
                    }
                }
            }
            else if (offconstant > 0)
            {
                num1 = 0.5 * (tapex.x - tdest.x) - offconstant * (tapex.y - tdest.y);
                num2 = 0.5 * (tapex.y - tdest.y) + offconstant * (tapex.x - tdest.x);
                if (num1 * num1 + num2 * num2 < (num10 - num3) * (num10 - num3) + (num11 - num4) * (num11 - num4))
                {
                    num10 = num3 + num1;
                    num11 = num4 + num2;
                }
            }
            xi  = (num6 * num10 - num5 * num11) * (2 * num);
            eta = (num3 * num11 - num4 * num10) * (2 * num);
            return(new Point(torg.x + num10, torg.y + num11));
        }
Example #8
0
        public bool CheckMesh()
        {
            Otri otri    = new Otri();
            Otri otri1   = new Otri();
            Otri otri2   = new Otri();
            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();
                    if (otri.orient == 0 && Primitives.CounterClockwise(vertex, vertex1, otri.Apex()) <= 0)
                    {
                        this.logger.Warning("Triangle is flat or inverted.", "Quality.CheckMesh()");
                        num++;
                    }
                    otri.Sym(ref otri1);
                    if (otri1.triangle != Mesh.dummytri)
                    {
                        otri1.Sym(ref otri2);
                        if (otri.triangle != otri2.triangle || otri.orient != otri2.orient)
                        {
                            if (otri.triangle == otri2.triangle)
                            {
                                this.logger.Warning("Asymmetric triangle-triangle bond: (Right triangle, wrong orientation)", "Quality.CheckMesh()");
                            }
                            num++;
                        }
                        Vertex vertex2 = otri1.Org();
                        if (vertex != otri1.Dest() || vertex1 != vertex2)
                        {
                            this.logger.Warning("Mismatched edge coordinates between two triangles.", "Quality.CheckMesh()");
                            num++;
                        }
                    }
                    otri.orient = otri.orient + 1;
                }
            }
            this.mesh.MakeVertexMap();
            foreach (Vertex value1 in this.mesh.vertices.Values)
            {
                if (value1.tri.triangle != null)
                {
                    continue;
                }
                this.logger.Warning(string.Concat("Vertex (ID ", value1.id, ") not connected to mesh (duplicate input vertex?)"), "Quality.CheckMesh()");
            }
            if (num == 0)
            {
                this.logger.Info("Mesh topology appears to be consistent.");
            }
            Behavior.NoExact = noExact;
            return(num == 0);
        }
Example #9
0
        private void SplitEncSegs(bool triflaws)
        {
            Vertex vertex;
            double num;
            Otri   otri  = new Otri();
            Otri   otri1 = new Otri();
            Osub   osub  = new Osub();
            Osub   osub1 = new Osub();

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

            for (Vertex i = searchtri.Apex(); i.x != searchpoint.X || i.y != searchpoint.Y; i = searchtri.Apex())
            {
                double num  = Primitives.CounterClockwise(vertex, i, searchpoint);
                double num1 = Primitives.CounterClockwise(i, vertex1, searchpoint);
                if (num <= 0)
                {
                    if (num1 <= 0)
                    {
                        if (num == 0)
                        {
                            searchtri.LprevSelf();
                            return(LocateResult.OnEdge);
                        }
                        if (num1 != 0)
                        {
                            return(LocateResult.InTriangle);
                        }
                        searchtri.LnextSelf();
                        return(LocateResult.OnEdge);
                    }
                    flag = false;
                }
                else
                {
                    flag = (num1 <= 0 ? true : (i.x - searchpoint.X) * (vertex1.x - vertex.x) + (i.y - searchpoint.Y) * (vertex1.y - vertex.y) > 0);
                }
                if (!flag)
                {
                    searchtri.Lnext(ref otri);
                    vertex = i;
                }
                else
                {
                    searchtri.Lprev(ref otri);
                    vertex1 = i;
                }
                otri.Sym(ref searchtri);
                if (this.mesh.checksegments & stopatsubsegment)
                {
                    otri.SegPivot(ref osub);
                    if (osub.seg != Mesh.dummysub)
                    {
                        otri.Copy(ref searchtri);
                        return(LocateResult.Outside);
                    }
                }
                if (searchtri.triangle == Mesh.dummytri)
                {
                    otri.Copy(ref searchtri);
                    return(LocateResult.Outside);
                }
            }
            searchtri.LprevSelf();
            return(LocateResult.OnVertex);
        }
        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));
        }
Example #12
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();
        }