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(); }
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); } }
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; } }
static void Swap(ref MeshUtils.Vertex a, ref MeshUtils.Vertex b) { var tmp = a; a = b; b = tmp; }
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; } }
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); }
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; } } } }
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; } } } }
public static bool VertEq(MeshUtils.Vertex lhs, MeshUtils.Vertex rhs) { if (lhs._s == rhs._s) { return(lhs._t == rhs._t); } return(false); }
private ActiveRegion TopRightRegion(ActiveRegion reg) { MeshUtils.Vertex dst = reg._eUp._Dst; do { reg = RegionAbove(reg); }while (reg._eUp._Dst == dst); return(reg); }
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); }
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); }
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); }
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); }
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); }
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; }
/// <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); }
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); }
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)); }
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); }
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); }
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)); }
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); }
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; }
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); }
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); }
/// <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); }
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); } }
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"); }
/// <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)); }
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(); }
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; }
/// <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; }
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; } }