static void Swap(ref MeshUtils.Vertex a, ref MeshUtils.Vertex b) { var tmp = a; a = b; b = tmp; }
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._Dst != 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._Dst == null && e._Lface == null && e._Rface == null); }
public static Real 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 > 0.0f) { return((v._s - w._s) * gapL + (v._s - u._s) * gapR); } /* vertical line */ return(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 Real EdgeSign(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 > 0.0f) { return((v._t - w._t) * gapL + (v._t - u._t) * gapR); } /* vertical line */ return(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 Real 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 > 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); }
public void Reset(IPool pool) { for (MeshUtils.Face f = _fHead, fNext = _fHead; f._next != null; f = fNext) { fNext = f._next; pool.Return(f); } for (MeshUtils.Vertex v = _vHead, vNext = _vHead; v._next != null; v = vNext) { vNext = v._next; pool.Return(v); } for (MeshUtils.Edge e = _eHead, eNext = _eHead; e._next != null; e = eNext) { eNext = e._next; pool.Return(e._Sym); pool.Return(e); } _vHead = null; _fHead = null; _eHead = _eHeadSym = null; }
public void Init(IPool pool) { var v = _vHead = pool.Get <MeshUtils.Vertex>(); var f = _fHead = pool.Get <MeshUtils.Face>(); var pair = MeshUtils.EdgePair.Create(pool); 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; }
public static bool VertLeq(MeshUtils.Vertex lhs, MeshUtils.Vertex rhs) { return((lhs._s < rhs._s) || (lhs._s == rhs._s && lhs._t <= rhs._t)); }
public static bool VertEq(MeshUtils.Vertex lhs, MeshUtils.Vertex rhs) { return(lhs._s == rhs._s && lhs._t == rhs._t); }
public static bool VertCCW(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w) { return((u._s * (v._t - w._t) + v._s * (w._t - u._t) + w._s * (u._t - v._t)) >= 0.0f); }
/// <summary> /// Given edges (o1,d1) and (o2,d2), compute their point of intersection. /// The computed point is guaranteed to lie in the intersection of the /// bounding rectangles defined by each edge. /// </summary> public static void EdgeIntersect(MeshUtils.Vertex o1, MeshUtils.Vertex d1, MeshUtils.Vertex o2, MeshUtils.Vertex d2, MeshUtils.Vertex v) { // This is certainly not the most efficient way to find the intersection // of two line segments, but it is very numerically stable. // // Strategy: find the two middle vertices in the VertLeq ordering, // and interpolate the intersection s-value from these. Then repeat // using the TransLeq ordering to find the intersection t-value. if (!VertLeq(o1, d1)) { Swap(ref o1, ref d1); } if (!VertLeq(o2, d2)) { Swap(ref o2, ref d2); } if (!VertLeq(o1, o2)) { Swap(ref o1, ref o2); Swap(ref d1, ref d2); } if (!VertLeq(o2, d1)) { // Technically, no intersection -- do our best v._s = (o2._s + d1._s) / 2.0f; } else if (VertLeq(d1, d2)) { // Interpolate between o2 and d1 var z1 = EdgeEval(o1, o2, d1); var z2 = EdgeEval(o2, d1, d2); if (z1 + z2 < 0.0f) { z1 = -z1; z2 = -z2; } v._s = Interpolate(z1, o2._s, z2, d1._s); } else { // Interpolate between o2 and d2 var z1 = EdgeSign(o1, o2, d1); var z2 = -EdgeSign(o1, d2, d1); if (z1 + z2 < 0.0f) { z1 = -z1; z2 = -z2; } v._s = Interpolate(z1, o2._s, z2, d2._s); } // Now repeat the process for t if (!TransLeq(o1, d1)) { Swap(ref o1, ref d1); } if (!TransLeq(o2, d2)) { Swap(ref o2, ref d2); } if (!TransLeq(o1, o2)) { Swap(ref o1, ref o2); Swap(ref d1, ref d2); } if (!TransLeq(o2, d1)) { // Technically, no intersection -- do our best v._t = (o2._t + d1._t) / 2.0f; } else if (TransLeq(d1, d2)) { // Interpolate between o2 and d1 var z1 = TransEval(o1, o2, d1); var z2 = TransEval(o2, d1, d2); if (z1 + z2 < 0.0f) { z1 = -z1; z2 = -z2; } v._t = Interpolate(z1, o2._t, z2, d1._t); } else { // Interpolate between o2 and d2 var z1 = TransSign(o1, o2, d1); var z2 = -TransSign(o1, d2, d1); if (z1 + z2 < 0.0f) { z1 = -z1; z2 = -z2; } v._t = Interpolate(z1, o2._t, z2, d2._t); } }
public static Real VertL1dist(MeshUtils.Vertex u, MeshUtils.Vertex v) { return(Math.Abs(u._s - v._s) + Math.Abs(u._t - v._t)); }
public static bool TransLeq(MeshUtils.Vertex lhs, MeshUtils.Vertex rhs) { return((lhs._t < rhs._t) || (lhs._t == rhs._t && lhs._s <= rhs._s)); }
private void ComputeNormal(ref Vec3 norm) { var v = _mesh._vHead._next; var minVal = new Real[3] { v._coords.X, v._coords.Y, v._coords.Z }; var minVert = new MeshUtils.Vertex[3] { v, v, v }; var maxVal = new Real[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, Y = 0, Z = 1 }; return; } // Look for a third vertex which forms the triangle with maximum area // (Length of normal == twice the triangle area) Real maxLen2 = 0, 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; } }