Пример #1
0
        static bool SplitIsRobust(float2 point, Edge *edge)
        {
            // check both sides for highly irregular tris
            // todo try to remove assert from InsertpointInEdge/FlipEdges as this should only happen with constrained edges?
            return(Math.TriArea(edge->Org->Point, edge->Dest->Point, point) == 0 ||
                   Math.TriArea(edge->LNext->Org->Point, edge->LNext->Dest->Point, point) > 0 &&
                   Math.TriArea(edge->LPrev->Org->Point, edge->LPrev->Dest->Point, point) > 0 &&
                   Math.TriArea(edge->RNext->Org->Point, edge->RNext->Dest->Point, point) < 0 &&
                   Math.TriArea(edge->RPrev->Org->Point, edge->RPrev->Dest->Point, point) < 0);

            // var o = edge->Org->Point;
            // var d = edge->Dest->Point;
            //
            // if (Math.TriArea(o, d, point) == 0)
            //     return true;
            //
            // if (Math.TriArea(o, d, point) > 0 &&
            //     Math.TriArea(edge->LNext->Org->Point, edge->LNext->Dest->Point, point) > 0 &&
            //     Math.TriArea(edge->LPrev->Org->Point, edge->LPrev->Dest->Point, point) > 0)
            //     return true;
            //
            // if (Math.TriArea(o, d, point) < 0 &&
            //     Math.TriArea(edge->RNext->Org->Point, edge->RNext->Dest->Point, point) < 0 &&
            //     Math.TriArea(edge->RPrev->Org->Point, edge->RPrev->Dest->Point, point) < 0)
            //     return true;
            //
            // return false;
        }
Пример #2
0
        /// <summary>
        /// Returns an edge for which the specified point is contained within it's left face. If the point lies
        /// on an edge this edge is returned. If the point lies on a vertex an arbitrary edge with identical origin is returned.
        /// </summary>
        /// <param name="collinear">True when the specified point lies on the returned edge</param>
        public Edge *FindTriangleContainingPoint(float2 p, out bool collinear)
        {
            var e = FindClosestVertex(p)->Edge;

            Assert.IsTrue(e != null);
            InfiniteLoopDetection.Reset();
            while (true)
            {
                InfiniteLoopDetection.Register(1000, "FindTriangleContainingPoint");

                Edge *collinearEdge = null;
                var   orient        = Math.TriArea(e->Org->Point, e->Dest->Point, p);

                if (orient == 0)
                {
                    collinearEdge = e;
                }
                else if (orient < 0)
                {
                    e = e->Sym;
                    continue;
                }

                orient = Math.TriArea(e->ONext->Org->Point, e->ONext->Dest->Point, p);

                if (orient == 0)
                {
                    collinearEdge = e->ONext;
                }
                else if (orient > 0)
                {
                    e = e->ONext;
                    continue;
                }

                orient = Math.TriArea(e->DPrev->Org->Point, e->DPrev->Dest->Point, p);

                if (orient == 0)
                {
                    collinear = true;
                    return(e->DPrev);
                }

                if (orient > 0)
                {
                    e = e->DPrev;
                    continue;
                }

                if (collinearEdge != null)
                {
                    collinear = true;
                    return(collinearEdge);
                }

                collinear = false;
                return(e);
            }
        }
Пример #3
0
        void InsertSegmentNoConstraints(Vertex *a, Vertex *b, Entity id)
        {
            var c = GetConnection(a, b);

            if (c != null)
            {
                C.TryAdd((IntPtr)c);
                if (!c->IsConstrainedBy(id))
                {
                    c->AddConstraint(id);
                }
                ResetClearance(c);
                return;
            }

            var e = GetLeftEdge(a, b->Point);

            InfiniteLoopDetection.Reset();
            while (e->Dest != b)
            {
                InfiniteLoopDetection.Register(1000, "InsertSegmentNoConstraints");

                var d    = Math.TriArea(a->Point, b->Point, e->Dest->Point);
                var next = d > 0 ? e->RPrev : e->ONext;

                if (d < 0)
                {
                    Assert.IsTrue(!e->Constrained);
                    RemoveEdge(e);
                }
                else if (d == 0 && e->Dest != a)
                {
                    var t = e->Dest;
                    Connect(a, t, id);
                    a = t;
                }

                e = next;
            }

            Connect(a, b, id);
        }
Пример #4
0
        void RemoveIfEligible(Vertex *v)
        {
            if (v->PointConstraints > 0 || v->ConstraintHandles > 0)
            {
                return;
            }

            var amount      = 0;
            var constrained = stackalloc Edge *[2];

            var e = v->GetEdgeEnumerator();

            while (e.MoveNext())
            {
                if (e.Current->Constrained)
                {
                    if (amount == 2)
                    {
                        return;
                    }
                    constrained[amount++] = e.Current;
                }
            }

            if (amount == 0)
            {
                e = v->GetEdgeEnumerator();
                while (e.MoveNext())
                {
                    V.TryAdd((IntPtr)e.Current->Dest);
                }
                var face = RemoveVertex(v);
                RetriangulateFace(face);
                return;
            }

            if (amount != 2 || !constrained[0]->ConstraintsEqual(constrained[1]))
            {
                return;
            }

            var e1 = constrained[0];
            var e2 = constrained[1];

            Assert.IsTrue(e1->Dest != v && e2->Dest != v);
            Assert.IsTrue(e1->Dest != e2->Dest);
            var d1        = e1->Dest->Point;
            var d2        = e2->Dest->Point;
            var collinear = Math.TriArea(d1, d2, v->Point);

            if (collinear == 0)
            {
                e = v->GetEdgeEnumerator();
                while (e.MoveNext())
                {
                    V.TryAdd((IntPtr)e.Current->Dest);
                }

                var v1   = e1->Dest;
                var v2   = e2->Dest;
                var crep = e1->QuadEdge->Crep;
                RemoveEdge(e1, false);
                RemoveVertex(v);
                var e3 = Connect(v1, v2);
                RetriangulateFace(e3);
                RetriangulateFace(e3->Sym);
                e3->QuadEdge->Crep = crep;
            }
            else
            {
                var t = collinear / math.length(d2 - d1);

                if (collinear > 0)
                {
                    if (t < _collinearMargin && Math.TriArea(d1, d2, e1->DPrev->Org->Point) < 0 && Math.TriArea(d1, d2, e2->DNext->Org->Point) < 0)
                    {
                        e = v->GetEdgeEnumerator();
                        while (e.MoveNext())
                        {
                            V.TryAdd((IntPtr)e.Current->Dest);
                        }
                        RemoveSemiCollinear(v, e1, e2);
                    }
                }
                else if (t > -_collinearMargin && Math.TriArea(d1, d2, e1->DNext->Org->Point) > 0 && Math.TriArea(d1, d2, e2->DPrev->Org->Point) > 0)
                {
                    e = v->GetEdgeEnumerator();
                    while (e.MoveNext())
                    {
                        V.TryAdd((IntPtr)e.Current->Dest);
                    }
                    RemoveSemiCollinear(v, e1, e2);
                }
            }
        }
Пример #5
0
        Point GetNextPoint(Vertex *a, Vertex *b, float2 start, float2 end)
        {
            InfiniteLoopDetection.Reset();
            var e = GetLeftEdge(a, b->Point);

            while (e->Dest != b)
            {
                InfiniteLoopDetection.Register(1000, "GetNextPoint");

                var d = Math.TriArea(a->Point, b->Point, e->Dest->Point);

                if (d < 0 && e->Constrained)
                {
                    var p           = (float2)Math.IntersectLineSegClamped(start, end, e->Org->Point, e->Dest->Point);
                    var pointExists = TryGetPoint(p, e, out var v);

                    if (v != null)
                    {
                        if (_insertedPoints.Length > 1)
                        {
                            var prev = _insertedPoints[_insertedPoints.Length - 1].Vertex;
                            if (prev == v || e->Org == prev || e->Dest == prev)
                            {
                                continue;
                            }
                        }

                        if (_insertedPoints.Length > 2)
                        {
                            var prev = _insertedPoints[_insertedPoints.Length - 2].Vertex;
                            if (prev == v || e->Org == prev || e->Dest == prev)
                            {
                                continue;
                            }
                        }

                        return(new Point
                        {
                            Vertex = v,
                            FoundExisting = true,
                            P = p
                        });
                    }

                    if (pointExists || !SplitIsRobust(p, e))
                    {
                        var pRef = CreatePRef(p, e);

                        if (_insertedPoints.Length > 1 && _insertedPoints[_insertedPoints.Length - 1].Vertex == pRef)
                        {
                            continue;
                        }

                        var point = new Point
                        {
                            Vertex   = pRef,
                            Modified = true,
                            P        = p
                        };

                        var proj  = (float2)Math.ProjectLine(a->Point, b->Point, point.Vertex->Point);
                        var pproj = proj - p;

                        if (math.dot(b - a, pproj) < 0)
                        {
                            point.Before = proj;
                            point.After  = p;
                        }
                        else
                        {
                            point.Before = p;
                            point.After  = proj;
                        }

                        return(point);
                    }

                    var vert = InsertPointInEdge(p, e);
                    return(new Point
                    {
                        Vertex = vert,
                        P = p
                    });
                }

                e = d > 0 ? e->RPrev : e->ONext;
            }

            return(new Point
            {
                Vertex = b,
                P = b->Point
            });
        }
Пример #6
0
        Vertex *InsertPoint(float2 p)
        {
            var closest = _qt.FindClosest(p);

            if (math.lengthsq(closest->Point - p) <= _e * _e)
            {
                return(closest);
            }

            var e = closest->Edge;

            Assert.IsTrue(e != null);
            InfiniteLoopDetection.Reset();

            while (true)
            {
                InfiniteLoopDetection.Register(1000, "InsertPoint");

                Edge *inEdge = null;

                var orient = Math.TriArea(e->Org->Point, e->Dest->Point, p);

                if (orient == 0)
                {
                    inEdge = e;
                }

                if (orient < 0)
                {
                    e = e->Sym;
                    continue;
                }

                orient = Math.TriArea(e->ONext->Org->Point, e->ONext->Dest->Point, p);

                if (orient == 0)
                {
                    inEdge = e->ONext;
                }

                if (orient > 0)
                {
                    e = e->ONext;
                    continue;
                }

                orient = Math.TriArea(e->DPrev->Org->Point, e->DPrev->Dest->Point, p);

                if (orient == 0)
                {
                    inEdge = e->DPrev;
                }

                if (orient > 0)
                {
                    e = e->DPrev;
                    continue;
                }

                if (inEdge != null)
                {
                    Assert.IsTrue(SplitIsRobust(p, inEdge));
                    return(InsertPointInEdge(p, inEdge));
                }

                return(InsertPointInFace(p, e));
            }
        }