Ejemplo n.º 1
0
        private void AddRightEdges(ActiveRegion regUp, MeshUtils.Edge eFirst, MeshUtils.Edge eLast, MeshUtils.Edge eTopLeft, bool cleanUp)
        {
            bool flag = true;

            MeshUtils.Edge edge = eFirst;
            do
            {
                AddRegionBelow(regUp, edge._Sym);
                edge = edge._Onext;
            }while (edge != eLast);
            if (eTopLeft == null)
            {
                eTopLeft = RegionBelow(regUp)._eUp._Rprev;
            }
            ActiveRegion activeRegion = regUp;

            MeshUtils.Edge edge2 = eTopLeft;
            while (true)
            {
                ActiveRegion activeRegion2 = RegionBelow(activeRegion);
                edge = activeRegion2._eUp._Sym;
                if (edge._Org != edge2._Org)
                {
                    break;
                }
                if (edge._Onext != edge2)
                {
                    _mesh.Splice(edge._Oprev, edge);
                    _mesh.Splice(edge2._Oprev, edge);
                }
                activeRegion2._windingNumber = activeRegion._windingNumber - edge._winding;
                activeRegion2._inside        = Geom.IsWindingInside(_windingRule, activeRegion2._windingNumber);
                activeRegion._dirty          = true;
                if (!flag && CheckForRightSplice(activeRegion))
                {
                    Geom.AddWinding(edge, edge2);
                    DeleteRegion(activeRegion);
                    _mesh.Delete(edge2);
                }
                flag         = false;
                activeRegion = activeRegion2;
                edge2        = edge;
            }
            activeRegion._dirty = true;
            if (cleanUp)
            {
                WalkDirtyRegions(activeRegion);
            }
        }
Ejemplo n.º 2
0
        public void MergeConvexFaces(int maxVertsPerFace)
        {
            for (var f = _fHead._next; f != _fHead; f = f._next)
            {
                // Skip faces which are outside the result
                if (!f._inside)
                {
                    continue;
                }

                var eCur   = f._anEdge;
                var vStart = eCur._Org;

                while (true)
                {
                    var eNext = eCur._Lnext;
                    var eSym  = eCur._Sym;

                    if (eSym != null && eSym._Lface != null && eSym._Lface._inside)
                    {
                        // Try to merge the neighbour faces if the resulting polygons
                        // does not exceed maximum number of vertices.
                        int curNv = f.VertsCount;
                        int symNv = eSym._Lface.VertsCount;
                        if ((curNv + symNv - 2) <= maxVertsPerFace)
                        {
                            // Merge if the resulting poly is convex.
                            if (Geom.VertCCW(eCur._Lprev._Org, eCur._Org, eSym._Lnext._Lnext._Org) &&
                                Geom.VertCCW(eSym._Lprev._Org, eSym._Org, eCur._Lnext._Lnext._Org))
                            {
                                eNext = eSym._Lnext;
                                Delete(eSym);
                                eCur = null;
                            }
                        }
                    }

                    if (eCur != null && eCur._Lnext._Org == vStart)
                    {
                        break;
                    }

                    // Continue to next edge.
                    eCur = eNext;
                }
            }
        }
Ejemplo n.º 3
0
        private void ConnectRightVertex(ActiveRegion regUp, MeshUtils.Edge eBottomLeft)
        {
            MeshUtils.Edge edge         = eBottomLeft._Onext;
            ActiveRegion   activeRegion = RegionBelow(regUp);

            MeshUtils.Edge eUp  = regUp._eUp;
            MeshUtils.Edge eUp2 = activeRegion._eUp;
            bool           flag = false;

            if (eUp._Dst != eUp2._Dst)
            {
                CheckForIntersect(regUp);
            }
            if (Geom.VertEq(eUp._Org, _event))
            {
                _mesh.Splice(edge._Oprev, eUp);
                regUp = TopLeftRegion(regUp);
                edge  = RegionBelow(regUp)._eUp;
                FinishLeftRegions(RegionBelow(regUp), activeRegion);
                flag = true;
            }
            if (Geom.VertEq(eUp2._Org, _event))
            {
                _mesh.Splice(eBottomLeft, eUp2._Oprev);
                eBottomLeft = FinishLeftRegions(activeRegion, null);
                flag        = true;
            }
            if (flag)
            {
                ActiveRegion   regUp2 = regUp;
                MeshUtils.Edge onext  = eBottomLeft._Onext;
                MeshUtils.Edge edge2  = edge;
                AddRightEdges(regUp2, onext, edge2, edge2, true);
            }
            else
            {
                MeshUtils.Edge eDst = (!Geom.VertLeq(eUp2._Org, eUp._Org)) ? eUp : eUp2._Oprev;
                eDst = _mesh.Connect(eBottomLeft._Lprev, eDst);
                ActiveRegion   regUp3 = regUp;
                MeshUtils.Edge edge3  = eDst;
                AddRightEdges(regUp3, edge3, edge3._Onext, eDst._Onext, false);
                eDst._Sym._activeRegion._fixUpperEdge = true;
                WalkDirtyRegions(regUp);
            }
        }
Ejemplo n.º 4
0
        internal MeshUtils.Vertex Minimum()
        {
            Debug.Assert(_initialized);

            if (_size == 0)
            {
                return(_heap.Minimum());
            }
            MeshUtils.Vertex sortMin = _keys[_order[_size - 1]];
            if (!_heap.Empty)
            {
                MeshUtils.Vertex heapMin = _heap.Minimum();
                if (Geom.VertLeq(heapMin, sortMin))
                {
                    return(heapMin);
                }
            }
            return(sortMin);
        }
Ejemplo n.º 5
0
        private void FloatUp(int curr)
        {
            int parent;
            int hCurr, hParent;

            hCurr = _nodes[curr];
            while (true)
            {
                parent  = curr >> 1;
                hParent = _nodes[parent];
                if (parent == 0 || Geom.VertLeq(_handles[hParent]._key, _handles[hCurr]._key))
                {
                    _nodes[curr]          = hCurr;
                    _handles[hCurr]._node = curr;
                    break;
                }
                _nodes[curr]            = hParent;
                _handles[hParent]._node = curr;
                curr = parent;
            }
        }
Ejemplo n.º 6
0
 private void ConnectLeftDegenerate(ActiveRegion regUp, MeshUtils.Vertex vEvent)
 {
     MeshUtils.Edge eUp = regUp._eUp;
     if (Geom.VertEq(eUp._Org, vEvent))
     {
         throw new InvalidOperationException("Vertices should have been merged before");
     }
     if (!Geom.VertEq(eUp._Dst, vEvent))
     {
         _mesh.SplitEdge(eUp._Sym);
         if (regUp._fixUpperEdge)
         {
             _mesh.Delete(eUp._Onext);
             regUp._fixUpperEdge = false;
         }
         _mesh.Splice(vEvent._anEdge, eUp);
         SweepEvent(vEvent);
         return;
     }
     throw new InvalidOperationException("Vertices should have been merged before");
 }
Ejemplo n.º 7
0
        private void ConnectLeftVertex(MeshUtils.Vertex vEvent)
        {
            ActiveRegion activeRegion = new ActiveRegion();

            activeRegion._eUp = vEvent._anEdge._Sym;
            ActiveRegion key           = _dict.Find(activeRegion).Key;
            ActiveRegion activeRegion2 = RegionBelow(key);

            if (activeRegion2 != null)
            {
                MeshUtils.Edge eUp  = key._eUp;
                MeshUtils.Edge eUp2 = activeRegion2._eUp;
                if (Geom.EdgeSign(eUp._Dst, vEvent, eUp._Org) == 0f)
                {
                    ConnectLeftDegenerate(key, vEvent);
                }
                else
                {
                    ActiveRegion activeRegion3 = Geom.VertLeq(eUp2._Dst, eUp._Dst) ? key : activeRegion2;
                    if (key._inside || activeRegion3._fixUpperEdge)
                    {
                        MeshUtils.Edge edge = (activeRegion3 != key) ? _mesh.Connect(eUp2._Dnext, vEvent._anEdge)._Sym : _mesh.Connect(vEvent._anEdge._Sym, eUp._Lnext);
                        if (activeRegion3._fixUpperEdge)
                        {
                            FixUpperEdge(activeRegion3, edge);
                        }
                        else
                        {
                            ComputeWinding(AddRegionBelow(key, edge));
                        }
                        SweepEvent(vEvent);
                    }
                    else
                    {
                        AddRightEdges(key, vEvent._anEdge, vEvent._anEdge, null, true);
                    }
                }
            }
        }
Ejemplo n.º 8
0
 private void TessellateMonoRegion(MeshUtils.Face face)
 {
     MeshUtils.Edge edge = face._anEdge;
     while (Geom.VertLeq(edge._Dst, edge._Org))
     {
         edge = edge._Lprev;
     }
     while (Geom.VertLeq(edge._Org, edge._Dst))
     {
         edge = edge._Lnext;
     }
     MeshUtils.Edge edge2 = edge._Lprev;
     while (edge._Lnext != edge2)
     {
         if (Geom.VertLeq(edge._Dst, edge2._Org))
         {
             while (edge2._Lnext != edge && (Geom.EdgeGoesLeft(edge2._Lnext) || Geom.EdgeSign(edge2._Org, edge2._Dst, edge2._Lnext._Dst) <= 0f))
             {
                 edge2 = _mesh.Connect(edge2._Lnext, edge2)._Sym;
             }
             edge2 = edge2._Lprev;
         }
         else
         {
             while (edge2._Lnext != edge && (Geom.EdgeGoesRight(edge._Lprev) || Geom.EdgeSign(edge._Dst, edge._Org, edge._Lprev._Org) >= 0f))
             {
                 Mesh           mesh  = _mesh;
                 MeshUtils.Edge edge3 = edge;
                 edge = mesh.Connect(edge3, edge3._Lprev)._Sym;
             }
             edge = edge._Lnext;
         }
     }
     while (edge2._Lnext._Lnext != edge)
     {
         edge2 = _mesh.Connect(edge2._Lnext, edge2)._Sym;
     }
 }
Ejemplo n.º 9
0
        internal MeshUtils.Vertex ExtractMin()
        {
            Debug.Assert(_initialized);

            if (_size == 0)
            {
                return(_heap.ExtractMin());
            }
            MeshUtils.Vertex sortMin = _keys[_order[_size - 1]];
            if (!_heap.Empty)
            {
                MeshUtils.Vertex heapMin = _heap.Minimum();
                if (Geom.VertLeq(heapMin, sortMin))
                {
                    return(_heap.ExtractMin());
                }
            }
            do
            {
                --_size;
            } while (_size > 0 && _keys[_order[_size - 1]] == null);

            return(sortMin);
        }
Ejemplo n.º 10
0
        private bool CheckForRightSplice(ActiveRegion regUp)
        {
            ActiveRegion activeRegion = RegionBelow(regUp);

            MeshUtils.Edge eUp  = regUp._eUp;
            MeshUtils.Edge eUp2 = activeRegion._eUp;
            if (Geom.VertLeq(eUp._Org, eUp2._Org))
            {
                if (Geom.EdgeSign(eUp2._Dst, eUp._Org, eUp2._Org) > 0f)
                {
                    return(false);
                }
                if (!Geom.VertEq(eUp._Org, eUp2._Org))
                {
                    _mesh.SplitEdge(eUp2._Sym);
                    _mesh.Splice(eUp, eUp2._Oprev);
                    regUp._dirty = (activeRegion._dirty = true);
                }
                else if (eUp._Org != eUp2._Org)
                {
                    _pq.Remove(eUp._Org._pqHandle);
                    SpliceMergeVertices(eUp2._Oprev, eUp);
                }
            }
            else
            {
                if (Geom.EdgeSign(eUp._Dst, eUp2._Org, eUp._Org) < 0f)
                {
                    return(false);
                }
                RegionAbove(regUp)._dirty = (regUp._dirty = true);
                _mesh.SplitEdge(eUp._Sym);
                _mesh.Splice(eUp2._Oprev, eUp);
            }
            return(true);
        }
Ejemplo n.º 11
0
        public void Init()
        {
            var stack = ArrayPool <StackItem> .Create(_size + 1, true);

            int stackPos = -1;

            int  p, r, i, j, piv;
            uint seed = 2016473283;

            p      = 0;
            r      = _size - 1;
            _order = ArrayPool <int> .Create(_size + 1, true);

            for (piv = 0, i = p; i <= r; ++piv, ++i)
            {
                _order[i] = piv;
            }

            stack[++stackPos] = new StackItem {
                p = p, r = r
            };

            while (stackPos >= 0)
            {
                var top = stack[stackPos--];
                p = top.p;
                r = top.r;

                while (r > p + 10)
                {
                    seed      = seed * 1539415821 + 1;
                    i         = p + (int)(seed % (r - p + 1));
                    piv       = _order[i];
                    _order[i] = _order[p];
                    _order[p] = piv;
                    i         = p - 1;
                    j         = r + 1;
                    do
                    {
                        do
                        {
                            ++i;
                        } while (!Geom.VertLeq(_keys[_order[i]], _keys[piv]));
                        do
                        {
                            --j;
                        } while (!Geom.VertLeq(_keys[piv], _keys[_order[j]]));
                        Swap(ref _order[i], ref _order[j]);
                    } while (i < j);
                    Swap(ref _order[i], ref _order[j]);
                    if (i - p < r - j)
                    {
                        stack[++stackPos] = new StackItem {
                            p = j + 1, r = r
                        };
                        r = i - 1;
                    }
                    else
                    {
                        stack[++stackPos] = new StackItem {
                            p = p, r = i - 1
                        };
                        p = j + 1;
                    }
                }
                for (i = p + 1; i <= r; ++i)
                {
                    piv = _order[i];
                    for (j = i; j > p && !Geom.VertLeq(_keys[piv], _keys[_order[j - 1]]); --j)
                    {
                        _order[j] = _order[j - 1];
                    }
                    _order[j] = piv;
                }
            }

#if DEBUG
            p = 0;
            r = _size - 1;
            for (i = p; i < r; ++i)
            {
                Debug.Assert(Geom.VertLeq(_keys[_order[i + 1]], _keys[_order[i]]), "Wrong sort");
            }
#endif

            ArrayPool <StackItem> .Free(stack);

            _max         = _size;
            _initialized = true;
            _heap.Init();
        }
Ejemplo n.º 12
0
        private void WalkDirtyRegions(ActiveRegion regUp)
        {
            ActiveRegion activeRegion = RegionBelow(regUp);

            while (true)
            {
                if (activeRegion._dirty)
                {
                    regUp        = activeRegion;
                    activeRegion = RegionBelow(activeRegion);
                }
                else
                {
                    if (!regUp._dirty)
                    {
                        activeRegion = regUp;
                        regUp        = RegionAbove(regUp);
                        if (regUp == null || !regUp._dirty)
                        {
                            break;
                        }
                    }
                    regUp._dirty = false;
                    MeshUtils.Edge eUp  = regUp._eUp;
                    MeshUtils.Edge eUp2 = activeRegion._eUp;
                    if (eUp._Dst != eUp2._Dst && CheckForLeftSplice(regUp))
                    {
                        if (activeRegion._fixUpperEdge)
                        {
                            DeleteRegion(activeRegion);
                            _mesh.Delete(eUp2);
                            activeRegion = RegionBelow(regUp);
                            eUp2         = activeRegion._eUp;
                        }
                        else if (regUp._fixUpperEdge)
                        {
                            DeleteRegion(regUp);
                            _mesh.Delete(eUp);
                            regUp = RegionAbove(activeRegion);
                            eUp   = regUp._eUp;
                        }
                    }
                    if (eUp._Org != eUp2._Org)
                    {
                        if (eUp._Dst != eUp2._Dst && !regUp._fixUpperEdge && !activeRegion._fixUpperEdge && (eUp._Dst == _event || eUp2._Dst == _event))
                        {
                            if (CheckForIntersect(regUp))
                            {
                                break;
                            }
                        }
                        else
                        {
                            CheckForRightSplice(regUp);
                        }
                    }
                    if (eUp._Org == eUp2._Org && eUp._Dst == eUp2._Dst)
                    {
                        Geom.AddWinding(eUp2, eUp);
                        DeleteRegion(regUp);
                        _mesh.Delete(eUp);
                        regUp = RegionAbove(activeRegion);
                    }
                }
            }
        }
Ejemplo n.º 13
0
        private bool CheckForIntersect(ActiveRegion regUp)
        {
            ActiveRegion activeRegion = RegionBelow(regUp);

            MeshUtils.Edge   eUp  = regUp._eUp;
            MeshUtils.Edge   eUp2 = activeRegion._eUp;
            MeshUtils.Vertex org  = eUp._Org;
            MeshUtils.Vertex org2 = eUp2._Org;
            MeshUtils.Vertex dst  = eUp._Dst;
            MeshUtils.Vertex dst2 = eUp2._Dst;
            if (org == org2)
            {
                return(false);
            }
            float num  = Math.Min(org._t, dst._t);
            float num2 = Math.Max(org2._t, dst2._t);

            if (num > num2)
            {
                return(false);
            }
            if (Geom.VertLeq(org, org2))
            {
                if (Geom.EdgeSign(dst2, org, org2) > 0f)
                {
                    return(false);
                }
            }
            else if (Geom.EdgeSign(dst, org2, org) < 0f)
            {
                return(false);
            }
            MeshUtils.Vertex vertex = MeshUtils.Pooled <MeshUtils.Vertex> .Create();

            Geom.EdgeIntersect(dst, org, dst2, org2, vertex);
            if (Geom.VertLeq(vertex, _event))
            {
                vertex._s = _event._s;
                vertex._t = _event._t;
            }
            MeshUtils.Vertex vertex2 = Geom.VertLeq(org, org2) ? org : org2;
            if (Geom.VertLeq(vertex2, vertex))
            {
                vertex._s = vertex2._s;
                vertex._t = vertex2._t;
            }
            if (Geom.VertEq(vertex, org) || Geom.VertEq(vertex, org2))
            {
                CheckForRightSplice(regUp);
                return(false);
            }
            if ((!Geom.VertEq(dst, _event) && Geom.EdgeSign(dst, _event, vertex) >= 0f) || (!Geom.VertEq(dst2, _event) && Geom.EdgeSign(dst2, _event, vertex) <= 0f))
            {
                if (dst2 == _event)
                {
                    _mesh.SplitEdge(eUp._Sym);
                    _mesh.Splice(eUp2._Sym, eUp);
                    regUp = TopLeftRegion(regUp);
                    eUp   = RegionBelow(regUp)._eUp;
                    FinishLeftRegions(RegionBelow(regUp), activeRegion);
                    ActiveRegion   regUp2 = regUp;
                    MeshUtils.Edge oprev  = eUp._Oprev;
                    MeshUtils.Edge edge   = eUp;
                    AddRightEdges(regUp2, oprev, edge, edge, true);
                    return(true);
                }
                if (dst == _event)
                {
                    _mesh.SplitEdge(eUp2._Sym);
                    _mesh.Splice(eUp._Lnext, eUp2._Oprev);
                    activeRegion = regUp;
                    regUp        = TopRightRegion(regUp);
                    MeshUtils.Edge rprev = RegionBelow(regUp)._eUp._Rprev;
                    activeRegion._eUp = eUp2._Oprev;
                    eUp2 = FinishLeftRegions(activeRegion, null);
                    AddRightEdges(regUp, eUp2._Onext, eUp._Rprev, rprev, true);
                    return(true);
                }
                if (Geom.EdgeSign(dst, _event, vertex) >= 0f)
                {
                    RegionAbove(regUp)._dirty = (regUp._dirty = true);
                    _mesh.SplitEdge(eUp._Sym);
                    eUp._Org._s = _event._s;
                    eUp._Org._t = _event._t;
                }
                if (Geom.EdgeSign(dst2, _event, vertex) <= 0f)
                {
                    regUp._dirty = (activeRegion._dirty = true);
                    _mesh.SplitEdge(eUp2._Sym);
                    eUp2._Org._s = _event._s;
                    eUp2._Org._t = _event._t;
                }
                return(false);
            }
            _mesh.SplitEdge(eUp._Sym);
            _mesh.SplitEdge(eUp2._Sym);
            _mesh.Splice(eUp2._Oprev, eUp);
            eUp._Org._s        = vertex._s;
            eUp._Org._t        = vertex._t;
            eUp._Org._pqHandle = _pq.Insert(eUp._Org);
            if (eUp._Org._pqHandle._handle == PQHandle.Invalid)
            {
                throw new InvalidOperationException("PQHandle should not be invalid");
            }
            GetIntersectData(eUp._Org, org, dst, org2, dst2);
            RegionAbove(regUp)._dirty = (regUp._dirty = (activeRegion._dirty = true));
            return(false);
        }
Ejemplo n.º 14
0
 private void ComputeWinding(ActiveRegion reg)
 {
     reg._windingNumber = RegionAbove(reg)._windingNumber + reg._eUp._winding;
     reg._inside        = Geom.IsWindingInside(_windingRule, reg._windingNumber);
 }
Ejemplo n.º 15
0
 public void MergeConvexFaces(int maxVertsPerFace)
 {
     for (MeshUtils.Face next = _fHead._next; next != _fHead; next = next._next)
     {
         if (next._inside)
         {
             MeshUtils.Edge   edge = next._anEdge;
             MeshUtils.Vertex org  = edge._Org;
             while (true)
             {
                 MeshUtils.Edge lnext = edge._Lnext;
                 MeshUtils.Edge sym   = edge._Sym;
                 if (sym != null && sym._Lface != null && sym._Lface._inside)
                 {
                     int vertsCount  = next.VertsCount;
                     int vertsCount2 = sym._Lface.VertsCount;
                     if (vertsCount + vertsCount2 - 2 <= maxVertsPerFace && Geom.VertCCW(edge._Lprev._Org, edge._Org, sym._Lnext._Lnext._Org) && Geom.VertCCW(sym._Lprev._Org, sym._Org, edge._Lnext._Lnext._Org))
                     {
                         lnext = sym._Lnext;
                         Delete(sym);
                         edge = null;
                     }
                 }
                 if (edge != null && edge._Lnext._Org == org)
                 {
                     break;
                 }
                 edge = lnext;
             }
         }
     }
 }