Beispiel #1
0
 protected void ComputeInterior()
 {
     RemoveDegenerateEdges();
     InitPriorityQ();
     RemoveDegenerateFaces();
     InitEdgeDict();
     MeshUtils.Vertex vertex;
     while ((vertex = _pq.ExtractMin()) != null)
     {
         while (true)
         {
             MeshUtils.Vertex vertex2 = _pq.Minimum();
             if (vertex2 == null || !Geom.VertEq(vertex2, vertex))
             {
                 break;
             }
             vertex2 = _pq.ExtractMin();
             SpliceMergeVertices(vertex._anEdge, vertex2._anEdge);
         }
         SweepEvent(vertex);
     }
     DoneEdgeDict();
     DonePriorityQ();
     RemoveDegenerateFaces();
 }
Beispiel #2
0
        private void SweepEvent(MeshUtils.Vertex vEvent)
        {
            _event = vEvent;
            MeshUtils.Edge edge = vEvent._anEdge;
            while (edge._activeRegion == null)
            {
                edge = edge._Onext;
                if (edge == vEvent._anEdge)
                {
                    ConnectLeftVertex(vEvent);
                    return;
                }
            }
            ActiveRegion activeRegion  = TopLeftRegion(edge._activeRegion);
            ActiveRegion activeRegion2 = RegionBelow(activeRegion);

            MeshUtils.Edge eUp   = activeRegion2._eUp;
            MeshUtils.Edge edge2 = FinishLeftRegions(activeRegion2, null);
            if (edge2._Onext == eUp)
            {
                ConnectRightVertex(activeRegion, edge2);
            }
            else
            {
                ActiveRegion   regUp = activeRegion;
                MeshUtils.Edge onext = edge2._Onext;
                MeshUtils.Edge edge3 = eUp;
                AddRightEdges(regUp, onext, edge3, edge3, true);
            }
        }
Beispiel #3
0
 public void Check()
 {
     MeshUtils.Face fHead = _fHead;
     fHead = _fHead;
     MeshUtils.Face next;
     MeshUtils.Edge edge;
     while ((next = fHead._next) != _fHead)
     {
         edge = next._anEdge;
         do
         {
             edge = edge._Lnext;
         }while (edge != next._anEdge);
         fHead = next;
     }
     MeshUtils.Vertex vHead = _vHead;
     vHead = _vHead;
     MeshUtils.Vertex next2;
     while ((next2 = vHead._next) != _vHead)
     {
         edge = next2._anEdge;
         do
         {
             edge = edge._Onext;
         }while (edge != next2._anEdge);
         vHead = next2;
     }
     MeshUtils.Edge eHead = _eHead;
     eHead = _eHead;
     while ((edge = eHead._next) != _eHead)
     {
         eHead = edge;
     }
 }
Beispiel #4
0
        static void Swap(ref MeshUtils.Vertex a, ref MeshUtils.Vertex b)
        {
            var tmp = a;

            a = b;
            b = tmp;
        }
Beispiel #5
0
 public override void OnFree()
 {
     MeshUtils.Face face  = _fHead._next;
     MeshUtils.Face fHead = _fHead;
     while (face != _fHead)
     {
         fHead = face._next;
         face.Free();
         face = fHead;
     }
     MeshUtils.Vertex vertex = _vHead._next;
     MeshUtils.Vertex vHead  = _vHead;
     while (vertex != _vHead)
     {
         vHead = vertex._next;
         vertex.Free();
         vertex = vHead;
     }
     MeshUtils.Edge edge  = _eHead._next;
     MeshUtils.Edge eHead = _eHead;
     while (edge != _eHead)
     {
         eHead = edge._next;
         edge.Free();
         edge = eHead;
     }
 }
Beispiel #6
0
        internal MeshUtils.Vertex ExtractMin()
        {
            Debug.Assert(_initialized);

            int hMin = _nodes[1];

            MeshUtils.Vertex min = _handles[hMin]._key;

            if (_size > 0)
            {
                _nodes[1] = _nodes[_size];
                _handles[_nodes[1]]._node = 1;

                _handles[hMin]._key  = null;
                _handles[hMin]._node = _freeList;
                _freeList            = hMin;

                if (--_size > 0)
                {
                    FloatDown(1);
                }
            }

            return(min);
        }
Beispiel #7
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;
             }
         }
     }
 }
Beispiel #8
0
        private void ProjectPolygon()
        {
            Vec3 v    = _normal;
            bool flag = false;

            if (v.X == 0f && v.Y == 0f && v.Z == 0f)
            {
                ComputeNormal(ref v);
                _normal = v;
                flag    = true;
            }
            int num = Vec3.LongAxis(ref v);

            _sUnit[num]           = 0f;
            _sUnit[(num + 1) % 3] = SUnitX;
            _sUnit[(num + 2) % 3] = SUnitY;
            _tUnit[num]           = 0f;
            _tUnit[(num + 1) % 3] = ((v[num] > 0f) ? (0f - SUnitY) : SUnitY);
            _tUnit[(num + 2) % 3] = ((v[num] > 0f) ? SUnitX : (0f - SUnitX));
            for (MeshUtils.Vertex next = _mesh._vHead._next; next != _mesh._vHead; next = next._next)
            {
                Vec3.Dot(ref next._coords, ref _sUnit, out next._s);
                Vec3.Dot(ref next._coords, ref _tUnit, out next._t);
            }
            if (flag)
            {
                CheckOrientation();
            }
            bool flag2 = true;

            for (MeshUtils.Vertex next2 = _mesh._vHead._next; next2 != _mesh._vHead; next2 = next2._next)
            {
                if (flag2)
                {
                    _bminX = (_bmaxX = next2._s);
                    _bminY = (_bmaxY = next2._t);
                    flag2  = false;
                }
                else
                {
                    if (next2._s < _bminX)
                    {
                        _bminX = next2._s;
                    }
                    if (next2._s > _bmaxX)
                    {
                        _bmaxX = next2._s;
                    }
                    if (next2._t < _bminY)
                    {
                        _bminY = next2._t;
                    }
                    if (next2._t > _bmaxY)
                    {
                        _bmaxY = next2._t;
                    }
                }
            }
        }
Beispiel #9
0
 public static bool VertEq(MeshUtils.Vertex lhs, MeshUtils.Vertex rhs)
 {
     if (lhs._s == rhs._s)
     {
         return(lhs._t == rhs._t);
     }
     return(false);
 }
Beispiel #10
0
 private ActiveRegion TopRightRegion(ActiveRegion reg)
 {
     MeshUtils.Vertex dst = reg._eUp._Dst;
     do
     {
         reg = RegionAbove(reg);
     }while (reg._eUp._Dst == dst);
     return(reg);
 }
Beispiel #11
0
        public static float TransSign(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
        {
            float num  = v._t - u._t;
            float num2 = w._t - v._t;

            if (num + num2 > 0f)
            {
                return((v._s - w._s) * num + (v._s - u._s) * num2);
            }
            return(0f);
        }
Beispiel #12
0
        public static float EdgeSign(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
        {
            float num  = v._s - u._s;
            float num2 = w._s - v._s;

            if (num + num2 > 0f)
            {
                return((v._t - w._t) * num + (v._t - u._t) * num2);
            }
            return(0f);
        }
Beispiel #13
0
        public void Check()
        {
            MeshUtils.Edge e;

            MeshUtils.Face fPrev = _fHead, f;
            for (fPrev = _fHead; (f = fPrev._next) != _fHead; fPrev = f)
            {
                e = f._anEdge;
                do
                {
                    Debug.Assert(e._Sym != e);
                    Debug.Assert(e._Sym._Sym == e);
                    Debug.Assert(e._Lnext._Onext._Sym == e);
                    Debug.Assert(e._Onext._Sym._Lnext == e);
                    Debug.Assert(e._Lface == f);
                    e = e._Lnext;
                } while (e != f._anEdge);
            }
            Debug.Assert(f._prev == fPrev && f._anEdge == null);

            MeshUtils.Vertex vPrev = _vHead, v;
            for (vPrev = _vHead; (v = vPrev._next) != _vHead; vPrev = v)
            {
                Debug.Assert(v._prev == vPrev);
                e = v._anEdge;
                do
                {
                    Debug.Assert(e._Sym != e);
                    Debug.Assert(e._Sym._Sym == e);
                    Debug.Assert(e._Lnext._Onext._Sym == e);
                    Debug.Assert(e._Onext._Sym._Lnext == e);
                    Debug.Assert(e._Org == v);
                    e = e._Onext;
                } while (e != v._anEdge);
            }
            Debug.Assert(v._prev == vPrev && v._anEdge == null);

            MeshUtils.Edge ePrev = _eHead;
            for (ePrev = _eHead; (e = ePrev._next) != _eHead; ePrev = e)
            {
                Debug.Assert(e._Sym._next == ePrev._Sym);
                Debug.Assert(e._Sym != e);
                Debug.Assert(e._Sym._Sym == e);
                Debug.Assert(e._Org != null);
                Debug.Assert(e._Sym._Org != null);
                Debug.Assert(e._Lnext._Onext._Sym == e);
                Debug.Assert(e._Onext._Sym._Lnext == e);
            }
            Debug.Assert(e._Sym._next == ePrev._Sym &&
                         e._Sym == _eHeadSym &&
                         e._Sym._Sym == e &&
                         e._Org == null && e._Sym._Org == null &&
                         e._Lface == null && e._Rface == null);
        }
Beispiel #14
0
 public static bool VertLeq(MeshUtils.Vertex lhs, MeshUtils.Vertex rhs)
 {
     if (!(lhs._s < rhs._s))
     {
         if (lhs._s == rhs._s)
         {
             return(lhs._t <= rhs._t);
         }
         return(false);
     }
     return(true);
 }
Beispiel #15
0
 public static bool TransLeq(MeshUtils.Vertex lhs, MeshUtils.Vertex rhs)
 {
     if (!(lhs._t < rhs._t))
     {
         if (lhs._t == rhs._t)
         {
             return(lhs._s <= rhs._s);
         }
         return(false);
     }
     return(true);
 }
Beispiel #16
0
        private void VertexWeights(MeshUtils.Vertex isect, MeshUtils.Vertex org, MeshUtils.Vertex dst, out float w0, out float w1)
        {
            float num  = Geom.VertL1dist(org, isect);
            float num2 = Geom.VertL1dist(dst, isect);

            w0 = num2 / (num + num2) / 2f;
            float num3 = num;

            w1 = num3 / (num3 + num2) / 2f;
            isect._coords.X += w0 * org._coords.X + w1 * dst._coords.X;
            isect._coords.Y += w0 * org._coords.Y + w1 * dst._coords.Y;
            isect._coords.Z += w0 * org._coords.Z + w1 * dst._coords.Z;
        }
Beispiel #17
0
        /// <summary>
        /// Returns a number whose sign matches EdgeEval(u,v,w) but which
        /// is cheaper to evaluate. Returns > 0, == 0 , or < 0
        /// as v is above, on, or below the edge uw.
        /// </summary>
        public static float EdgeSign(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
        {
            Debug.Assert(VertLeq(u, v) && VertLeq(v, w));

            float gapL = v._s - u._s;
            float gapR = w._s - v._s;

            if (gapL + gapR > 0.0f)
            {
                return((v._t - w._t) * gapL + (v._t - u._t) * gapR);
            }
            /* vertical line */
            return(0.0f);
        }
Beispiel #18
0
        public static float TransSign(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
        {
            Debug.Assert(TransLeq(u, v) && TransLeq(v, w));

            float gapL = v._t - u._t;
            float gapR = w._t - v._t;

            if (gapL + gapR > 0.0f)
            {
                return((v._s - w._s) * gapL + (v._s - u._s) * gapR);
            }
            /* vertical line */
            return(0.0f);
        }
Beispiel #19
0
        public static DeterministicFloat TransSign(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
        {
            Debug.Assert(TransLeq(u, v) && TransLeq(v, w));

            var gapL = v._t - u._t;
            var gapR = w._t - v._t;

            if (gapL + gapR > new DeterministicFloat(0))
            {
                return((v._s - w._s) * gapL + (v._s - u._s) * gapR);
            }
            /* vertical line */
            return(new DeterministicFloat(0));
        }
Beispiel #20
0
 private ActiveRegion TopLeftRegion(ActiveRegion reg)
 {
     MeshUtils.Vertex org = reg._eUp._Org;
     do
     {
         reg = RegionAbove(reg);
     }while (reg._eUp._Org == org);
     if (reg._fixUpperEdge)
     {
         MeshUtils.Edge newEdge = _mesh.Connect(RegionBelow(reg)._eUp._Sym, reg._eUp._Lnext);
         FixUpperEdge(reg, newEdge);
         reg = RegionAbove(reg);
     }
     return(reg);
 }
Beispiel #21
0
        internal int Insert(MeshUtils.Vertex value)
        {
            int curr = ++_size;

            if ((curr * 2) > _max)
            {
                _max <<= 1;
                ArrayPool <int> .Resize(ref _nodes, _max + 1, true);

                ArrayPool <HandleElem> .Resize(ref _handles, _max + 1, true);
            }

            int free;

            if (_freeList == 0)
            {
                free = curr;
            }
            else
            {
                free      = _freeList;
                _freeList = _handles[free]._node;
            }

            _nodes[curr] = free;
            if (_handles[free] == null)
            {
                _handles[free] = new HandleElem {
                    _key = value, _node = curr
                };
            }
            else
            {
                _handles[free]._node = curr;
                _handles[free]._key  = value;
            }

            if (_initialized)
            {
                FloatUp(curr);
            }

            Debug.Assert(free != PQHandle.Invalid);
            return(free);
        }
Beispiel #22
0
        internal int Insert(MeshUtils.Vertex value)
        {
            if (_initialized)
            {
                return(_heap.Insert(value));
            }

            int curr = _size;

            if (++_size >= _max)
            {
                _max <<= 1;
                ArrayPool <MeshUtils.Vertex> .Resize(ref _keys, _max, true);
            }

            _keys[curr] = value;
            return(-(curr + 1));
        }
Beispiel #23
0
        public static float EdgeEval(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
        {
            float num  = v._s - u._s;
            float num2 = w._s - v._s;

            if (num + num2 > 0f)
            {
                if (num < num2)
                {
                    float num3 = v._t - u._t;
                    float num4 = u._t - w._t;
                    float num5 = num;
                    return(num3 + num4 * (num5 / (num5 + num2)));
                }
                return(v._t - w._t + (w._t - u._t) * (num2 / (num + num2)));
            }
            return(0f);
        }
Beispiel #24
0
        public Mesh()
        {
            var v = _vHead = new MeshUtils.Vertex();
            var f = _fHead = new MeshUtils.Face();

            var pair = MeshUtils.EdgePair.Create();
            var e = _eHead = pair._e;
            var eSym = _eHeadSym = pair._eSym;

            v._next = v._prev = v;
            f._next = f._prev = f;

            e._next = e;
            e._Sym = eSym;

            eSym._next = eSym;
            eSym._Sym = e;
        }
Beispiel #25
0
        private void AddSentinel(float smin, float smax, float t)
        {
            MeshUtils.Edge edge = _mesh.MakeEdge();
            edge._Org._s = smax;
            edge._Org._t = t;
            edge._Dst._s = smin;
            edge._Dst._t = t;
            _event       = edge._Dst;
            ActiveRegion activeRegion = new ActiveRegion();

            activeRegion._eUp           = edge;
            activeRegion._windingNumber = 0;
            activeRegion._inside        = false;
            activeRegion._fixUpperEdge  = false;
            activeRegion._sentinel      = true;
            activeRegion._dirty         = false;
            activeRegion._nodeUp        = _dict.Insert(activeRegion);
        }
Beispiel #26
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);
        }
Beispiel #27
0
        /// <summary>
        /// Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w),
        /// evaluates the t-coord of the edge uw at the s-coord of the vertex v.
        /// Returns v->t - (uw)(v->s), ie. the signed distance from uw to v.
        /// If uw is vertical (and thus passes thru v), the result is zero.
        ///
        /// The calculation is extremely accurate and stable, even when v
        /// is very close to u or w.  In particular if we set v->t = 0 and
        /// let r be the negated result (this evaluates (uw)(v->s)), then
        /// r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t).
        /// </summary>
        public static float EdgeEval(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
        {
            Debug.Assert(VertLeq(u, v) && VertLeq(v, w));

            float gapL = v._s - u._s;
            float gapR = w._s - v._s;

            if (gapL + gapR > 0.0f)
            {
                if (gapL < gapR)
                {
                    return((v._t - u._t) + (u._t - w._t) * (gapL / (gapL + gapR)));
                }
                else
                {
                    return((v._t - w._t) + (w._t - u._t) * (gapR / (gapL + gapR)));
                }
            }
            /* vertical line */
            return(0.0f);
        }
Beispiel #28
0
        private void CheckOrientation()
        {
            float num = 0f;

            for (MeshUtils.Face next = _mesh._fHead._next; next != _mesh._fHead; next = next._next)
            {
                if (next._anEdge._winding > 0)
                {
                    num += MeshUtils.FaceArea(next);
                }
            }
            if (num < 0f)
            {
                for (MeshUtils.Vertex next2 = _mesh._vHead._next; next2 != _mesh._vHead; next2 = next2._next)
                {
                    MeshUtils.Vertex vertex = next2;
                    vertex._t = 0f - vertex._t;
                }
                Vec3.Neg(ref _tUnit);
            }
        }
Beispiel #29
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");
 }
Beispiel #30
0
        /// <summary>
        /// Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w),
        /// evaluates the t-coord of the edge uw at the s-coord of the vertex v.
        /// Returns v->t - (uw)(v->s), ie. the signed distance from uw to v.
        /// If uw is vertical (and thus passes through v), the result is zero.
        ///
        /// The calculation is extremely accurate and stable, even when v
        /// is very close to u or w.  In particular if we set v->t = 0 and
        /// let r be the negated result (this evaluates (uw)(v->s)), then
        /// r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t).
        /// </summary>
        public static DeterministicFloat EdgeEval(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
        {
            Debug.Assert(VertLeq(u, v) && VertLeq(v, w));

            var gapL = v._s - u._s;
            var gapR = w._s - v._s;

            if (gapL + gapR > new DeterministicFloat(0))
            {
                if (gapL < gapR)
                {
                    return((v._t - u._t) + (u._t - w._t) * (gapL / (gapL + gapR)));
                }
                else
                {
                    return((v._t - w._t) + (w._t - u._t) * (gapR / (gapL + gapR)));
                }
            }
            /* vertical line */
            return(new DeterministicFloat(0));
        }
Beispiel #31
0
        private void InitPriorityQ()
        {
            MeshUtils.Vertex vHead = _mesh._vHead;
            int num = 0;

            for (MeshUtils.Vertex next = vHead._next; next != vHead; next = next._next)
            {
                num++;
            }
            num  += 8;
            _pq   = new PriorityQueue <MeshUtils.Vertex>(num, Geom.VertLeq);
            vHead = _mesh._vHead;
            for (MeshUtils.Vertex next = vHead._next; next != vHead; next = next._next)
            {
                next._pqHandle = _pq.Insert(next);
                if (next._pqHandle._handle == PQHandle.Invalid)
                {
                    throw new InvalidOperationException("PQHandle should not be invalid");
                }
            }
            _pq.Init();
        }
Beispiel #32
0
Datei: Mesh.cs Projekt: D021/ink
        public Mesh()
        {
            var v = _vHead = new MeshUtils.Vertex();
            var f = _fHead = new MeshUtils.Face();

            var pair = MeshUtils.EdgePair.Create();
            var e = _eHead = pair._e;
            var eSym = _eHeadSym = pair._eSym;

            v._next = v._prev = v;
            v._anEdge = null;

            f._next = f._prev = f;
            f._anEdge = null;
            f._trail = null;
            f._marked = false;
            f._inside = false;

            e._next = e;
            e._Sym = eSym;
            e._Onext = null;
            e._Lnext = null;
            e._Org = null;
            e._Lface = null;
            e._winding = 0;
            e._activeRegion = null;

            eSym._next = eSym;
            eSym._Sym = e;
            eSym._Onext = null;
            eSym._Lnext = null;
            eSym._Org = null;
            eSym._Lface = null;
            eSym._winding = 0;
            eSym._activeRegion = null;
        }
Beispiel #33
0
        /// <summary>
        /// Check the upper and lower edges of the given region to see if
        /// they intersect.  If so, create the intersection and add it
        /// to the data structures.
        /// 
        /// Returns TRUE if adding the new intersection resulted in a recursive
        /// call to AddRightEdges(); in this case all "dirty" regions have been
        /// checked for intersections, and possibly regUp has been deleted.
        /// </summary>
        private bool CheckForIntersect(ActiveRegion regUp)
        {
            var regLo = RegionBelow(regUp);
            var eUp = regUp._eUp;
            var eLo = regLo._eUp;
            var orgUp = eUp._Org;
            var orgLo = eLo._Org;
            var dstUp = eUp._Dst;
            var dstLo = eLo._Dst;

            Debug.Assert(!Geom.VertEq(dstLo, dstUp));
            Debug.Assert(Geom.EdgeSign(dstUp, _event, orgUp) <= 0.0f);
            Debug.Assert(Geom.EdgeSign(dstLo, _event, orgLo) >= 0.0f);
            Debug.Assert(orgUp != _event && orgLo != _event);
            Debug.Assert(!regUp._fixUpperEdge && !regLo._fixUpperEdge);

            if( orgUp == orgLo )
            {
                // right endpoints are the same
                return false;
            }

            var tMinUp = Math.Min(orgUp._t, dstUp._t);
            var tMaxLo = Math.Max(orgLo._t, dstLo._t);
            if( tMinUp > tMaxLo )
            {
                // t ranges do not overlap
                return false;
            }

            if (Geom.VertLeq(orgUp, orgLo))
            {
                if (Geom.EdgeSign( dstLo, orgUp, orgLo ) > 0.0f)
                {
                    return false;
                }
            }
            else
            {
                if (Geom.EdgeSign( dstUp, orgLo, orgUp ) < 0.0f)
                {
                    return false;
                }
            }

            // At this point the edges intersect, at least marginally

            var isect = new MeshUtils.Vertex();
            Geom.EdgeIntersect(dstUp, orgUp, dstLo, orgLo, isect);
            // The following properties are guaranteed:
            Debug.Assert(Math.Min(orgUp._t, dstUp._t) <= isect._t);
            Debug.Assert(isect._t <= Math.Max(orgLo._t, dstLo._t));
            Debug.Assert(Math.Min(dstLo._s, dstUp._s) <= isect._s);
            Debug.Assert(isect._s <= Math.Max(orgLo._s, orgUp._s));

            if (Geom.VertLeq(isect, _event))
            {
                // The intersection point lies slightly to the left of the sweep line,
                // so move it until it''s slightly to the right of the sweep line.
                // (If we had perfect numerical precision, this would never happen
                // in the first place). The easiest and safest thing to do is
                // replace the intersection by tess._event.
                isect._s = _event._s;
                isect._t = _event._t;
            }
            // Similarly, if the computed intersection lies to the right of the
            // rightmost origin (which should rarely happen), it can cause
            // unbelievable inefficiency on sufficiently degenerate inputs.
            // (If you have the test program, try running test54.d with the
            // "X zoom" option turned on).
            var orgMin = Geom.VertLeq(orgUp, orgLo) ? orgUp : orgLo;
            if (Geom.VertLeq(orgMin, isect))
            {
                isect._s = orgMin._s;
                isect._t = orgMin._t;
            }

            if (Geom.VertEq(isect, orgUp) || Geom.VertEq(isect, orgLo))
            {
                // Easy case -- intersection at one of the right endpoints
                CheckForRightSplice(regUp);
                return false;
            }

            if (   (! Geom.VertEq(dstUp, _event)
                && Geom.EdgeSign(dstUp, _event, isect) >= 0.0f)
                || (! Geom.VertEq(dstLo, _event)
                && Geom.EdgeSign(dstLo, _event, isect) <= 0.0f ))
            {
                // Very unusual -- the new upper or lower edge would pass on the
                // wrong side of the sweep event, or through it. This can happen
                // due to very small numerical errors in the intersection calculation.
                if (dstLo == _event)
                {
                    // Splice dstLo into eUp, and process the new region(s)
                    _mesh.SplitEdge(eUp._Sym);
                    _mesh.Splice(eLo._Sym, eUp);
                    regUp = TopLeftRegion(regUp);
                    eUp = RegionBelow(regUp)._eUp;
                    FinishLeftRegions(RegionBelow(regUp), regLo);
                    AddRightEdges(regUp, eUp._Oprev, eUp, eUp, true);
                    return true;
                }
                if( dstUp == _event ) {
                    /* Splice dstUp into eLo, and process the new region(s) */
                    _mesh.SplitEdge(eLo._Sym);
                    _mesh.Splice(eUp._Lnext, eLo._Oprev);
                    regLo = regUp;
                    regUp = TopRightRegion(regUp);
                    var e = RegionBelow(regUp)._eUp._Rprev;
                    regLo._eUp = eLo._Oprev;
                    eLo = FinishLeftRegions(regLo, null);
                    AddRightEdges(regUp, eLo._Onext, eUp._Rprev, e, true);
                    return true;
                }
                // Special case: called from ConnectRightVertex. If either
                // edge passes on the wrong side of tess._event, split it
                // (and wait for ConnectRightVertex to splice it appropriately).
                if (Geom.EdgeSign( dstUp, _event, isect ) >= 0.0f)
                {
                    RegionAbove(regUp)._dirty = regUp._dirty = true;
                    _mesh.SplitEdge(eUp._Sym);
                    eUp._Org._s = _event._s;
                    eUp._Org._t = _event._t;
                }
                if (Geom.EdgeSign(dstLo, _event, isect) <= 0.0f)
                {
                    regUp._dirty = regLo._dirty = true;
                    _mesh.SplitEdge(eLo._Sym);
                    eLo._Org._s = _event._s;
                    eLo._Org._t = _event._t;
                }
                // leave the rest for ConnectRightVertex
                return false;
            }

            // General case -- split both edges, splice into new vertex.
            // When we do the splice operation, the order of the arguments is
            // arbitrary as far as correctness goes. However, when the operation
            // creates a new face, the work done is proportional to the size of
            // the new face.  We expect the faces in the processed part of
            // the mesh (ie. eUp._Lface) to be smaller than the faces in the
            // unprocessed original contours (which will be eLo._Oprev._Lface).
            _mesh.SplitEdge(eUp._Sym);
            _mesh.SplitEdge(eLo._Sym);
            _mesh.Splice(eLo._Oprev, eUp);
            eUp._Org._s = isect._s;
            eUp._Org._t = isect._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, orgUp, dstUp, orgLo, dstLo);
            RegionAbove(regUp)._dirty = regUp._dirty = regLo._dirty = true;
            return false;
        }
Beispiel #34
0
        private void ComputeNormal(ref Vec3 norm)
        {
            var v = _mesh._vHead._next;

            var minVal = new float[3] { v._coords.X, v._coords.Y, v._coords.Z };
            var minVert = new MeshUtils.Vertex[3] { v, v, v };
            var maxVal = new float[3] { v._coords.X, v._coords.Y, v._coords.Z };
            var maxVert = new MeshUtils.Vertex[3] { v, v, v };

            for (; v != _mesh._vHead; v = v._next)
            {
                if (v._coords.X < minVal[0]) { minVal[0] = v._coords.X; minVert[0] = v; }
                if (v._coords.Y < minVal[1]) { minVal[1] = v._coords.Y; minVert[1] = v; }
                if (v._coords.Z < minVal[2]) { minVal[2] = v._coords.Z; minVert[2] = v; }
                if (v._coords.X > maxVal[0]) { maxVal[0] = v._coords.X; maxVert[0] = v; }
                if (v._coords.Y > maxVal[1]) { maxVal[1] = v._coords.Y; maxVert[1] = v; }
                if (v._coords.Z > maxVal[2]) { maxVal[2] = v._coords.Z; maxVert[2] = v; }
            }

            // Find two vertices separated by at least 1/sqrt(3) of the maximum
            // distance between any two vertices
            int i = 0;
            if (maxVal[1] - minVal[1] > maxVal[0] - minVal[0]) { i = 1; }
            if (maxVal[2] - minVal[2] > maxVal[i] - minVal[i]) { i = 2; }
            if (minVal[i] >= maxVal[i])
            {
                // All vertices are the same -- normal doesn't matter
                norm = new Vec3 { X = 0.0f, Y = 0.0f, Z = 1.0f };
                return;
            }

            // Look for a third vertex which forms the triangle with maximum area
            // (Length of normal == twice the triangle area)
            float maxLen2 = 0.0f, tLen2;
            var v1 = minVert[i];
            var v2 = maxVert[i];
            Vec3 d1, d2, tNorm;
            Vec3.Sub(ref v1._coords, ref v2._coords, out d1);
            for (v = _mesh._vHead._next; v != _mesh._vHead; v = v._next)
            {
                Vec3.Sub(ref v._coords, ref v2._coords, out d2);
                tNorm.X = d1.Y * d2.Z - d1.Z * d2.Y;
                tNorm.Y = d1.Z * d2.X - d1.X * d2.Z;
                tNorm.Z = d1.X * d2.Y - d1.Y * d2.X;
                tLen2 = tNorm.X*tNorm.X + tNorm.Y*tNorm.Y + tNorm.Z*tNorm.Z;
                if (tLen2 > maxLen2)
                {
                    maxLen2 = tLen2;
                    norm = tNorm;
                }
            }

            if (maxLen2 <= 0.0f)
            {
                // All points lie on a single line -- any decent normal will do
                norm = Vec3.Zero;
                i = Vec3.LongAxis(ref d1);
                norm[i] = 1.0f;
            }
        }