/* ** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) ** Copyright (C) 2011 Silicon Graphics, Inc. ** All Rights Reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a copy ** of this software and associated documentation files (the "Software"), to deal ** in the Software without restriction, including without limitation the rights ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies ** of the Software, and to permit persons to whom the Software is furnished to do so, ** subject to the following conditions: ** ** The above copyright notice including the dates of first publication and either this ** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be ** included in all copies or substantial portions of the Software. ** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, ** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. ** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE ** OR OTHER DEALINGS IN THE SOFTWARE. ** ** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not ** be used in advertising or otherwise to promote the sale, use or other dealings in ** this Software without prior written authorization from Silicon Graphics, Inc. */ /* ** Original Author: Eric Veach, July 1994. ** libtess2: Mikko Mononen, http://code.google.com/p/libtess2/. ** LibTessDotNet: Remi Gillig, https://github.com/speps/LibTessDotNet */ using System; using System.Collections.Generic; using System.Diagnostics; namespace Unity.SpriteShape.External { using Real = System.Single; namespace LibTessDotNet { internal struct Vec3 { public readonly static Vec3 Zero = new Vec3(); public Real X, Y, Z; public Real this[int index] { get { if (index == 0) return X; if (index == 1) return Y; if (index == 2) return Z; throw new IndexOutOfRangeException(); } set { if (index == 0) X = value; else if (index == 1) Y = value; else if (index == 2) Z = value; else throw new IndexOutOfRangeException(); } } public static void Sub(ref Vec3 lhs, ref Vec3 rhs, out Vec3 result) { result.X = lhs.X - rhs.X; result.Y = lhs.Y - rhs.Y; result.Z = lhs.Z - rhs.Z; } public static void Neg(ref Vec3 v) { v.X = -v.X; v.Y = -v.Y; v.Z = -v.Z; } public static void Dot(ref Vec3 u, ref Vec3 v, out Real dot) { dot = u.X * v.X + u.Y * v.Y + u.Z * v.Z; } public static void Normalize(ref Vec3 v) { var len = v.X * v.X + v.Y * v.Y + v.Z * v.Z; Debug.Assert(len >= 0.0f); len = 1.0f / (Real)Math.Sqrt(len); v.X *= len; v.Y *= len; v.Z *= len; } public static int LongAxis(ref Vec3 v) { int i = 0; if (Math.Abs(v.Y) > Math.Abs(v.X)) i = 1; if (Math.Abs(v.Z) > Math.Abs(i == 0 ? v.X : v.Y)) i = 2; return i; } public override string ToString() { return string.Format("{0}, {1}, {2}", X, Y, Z); } } internal static class MeshUtils { public const int Undef = ~0; public abstract class Pooled where T : Pooled, new() { private static Stack _stack; public abstract void Reset(); public virtual void OnFree() { } public static T Create() { if (_stack != null && _stack.Count > 0) { return _stack.Pop(); } return new T(); } public void Free() { OnFree(); Reset(); if (_stack == null) { _stack = new Stack(); } _stack.Push((T)this); } } public class Vertex : Pooled { internal Vertex _prev, _next; internal Edge _anEdge; internal Vec3 _coords; internal Real _s, _t; internal PQHandle _pqHandle; internal int _n; internal object _data; public override void Reset() { _prev = _next = null; _anEdge = null; _coords = Vec3.Zero; _s = 0; _t = 0; _pqHandle = new PQHandle(); _n = 0; _data = null; } } public class Face : Pooled { internal Face _prev, _next; internal Edge _anEdge; internal Face _trail; internal int _n; internal bool _marked, _inside; internal int VertsCount { get { int n = 0; var eCur = _anEdge; do { n++; eCur = eCur._Lnext; } while (eCur != _anEdge); return n; } } public override void Reset() { _prev = _next = null; _anEdge = null; _trail = null; _n = 0; _marked = false; _inside = false; } } public struct EdgePair { internal Edge _e, _eSym; public static EdgePair Create() { var pair = new MeshUtils.EdgePair(); pair._e = MeshUtils.Edge.Create(); pair._e._pair = pair; pair._eSym = MeshUtils.Edge.Create(); pair._eSym._pair = pair; return pair; } public void Reset() { _e = _eSym = null; } } public class Edge : Pooled { internal EdgePair _pair; internal Edge _next, _Sym, _Onext, _Lnext; internal Vertex _Org; internal Face _Lface; internal Tess.ActiveRegion _activeRegion; internal int _winding; internal Face _Rface { get { return _Sym._Lface; } set { _Sym._Lface = value; } } internal Vertex _Dst { get { return _Sym._Org; } set { _Sym._Org = value; } } internal Edge _Oprev { get { return _Sym._Lnext; } set { _Sym._Lnext = value; } } internal Edge _Lprev { get { return _Onext._Sym; } set { _Onext._Sym = value; } } internal Edge _Dprev { get { return _Lnext._Sym; } set { _Lnext._Sym = value; } } internal Edge _Rprev { get { return _Sym._Onext; } set { _Sym._Onext = value; } } internal Edge _Dnext { get { return _Rprev._Sym; } set { _Rprev._Sym = value; } } internal Edge _Rnext { get { return _Oprev._Sym; } set { _Oprev._Sym = value; } } internal static void EnsureFirst(ref Edge e) { if (e == e._pair._eSym) { e = e._Sym; } } public override void Reset() { _pair.Reset(); _next = _Sym = _Onext = _Lnext = null; _Org = null; _Lface = null; _activeRegion = null; _winding = 0; } } /// /// MakeEdge creates a new pair of half-edges which form their own loop. /// No vertex or face structures are allocated, but these must be assigned /// before the current edge operation is completed. /// public static Edge MakeEdge(Edge eNext) { Debug.Assert(eNext != null); var pair = EdgePair.Create(); var e = pair._e; var eSym = pair._eSym; // Make sure eNext points to the first edge of the edge pair Edge.EnsureFirst(ref eNext); // Insert in circular doubly-linked list before eNext. // Note that the prev pointer is stored in Sym->next. var ePrev = eNext._Sym._next; eSym._next = ePrev; ePrev._Sym._next = e; e._next = eNext; eNext._Sym._next = eSym; e._Sym = eSym; e._Onext = e; e._Lnext = eSym; e._Org = null; e._Lface = null; e._winding = 0; e._activeRegion = null; eSym._Sym = e; eSym._Onext = eSym; eSym._Lnext = e; eSym._Org = null; eSym._Lface = null; eSym._winding = 0; eSym._activeRegion = null; return e; } /// /// Splice( a, b ) is best described by the Guibas/Stolfi paper or the /// CS348a notes (see Mesh.cs). Basically it modifies the mesh so that /// a->Onext and b->Onext are exchanged. This can have various effects /// depending on whether a and b belong to different face or vertex rings. /// For more explanation see Mesh.Splice(). /// public static void Splice(Edge a, Edge b) { var aOnext = a._Onext; var bOnext = b._Onext; aOnext._Sym._Lnext = b; bOnext._Sym._Lnext = a; a._Onext = bOnext; b._Onext = aOnext; } /// /// MakeVertex( eOrig, vNext ) attaches a new vertex and makes it the /// origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives /// a place to insert the new vertex in the global vertex list. We insert /// the new vertex *before* vNext so that algorithms which walk the vertex /// list will not see the newly created vertices. /// public static void MakeVertex(Edge eOrig, Vertex vNext) { var vNew = MeshUtils.Vertex.Create(); // insert in circular doubly-linked list before vNext var vPrev = vNext._prev; vNew._prev = vPrev; vPrev._next = vNew; vNew._next = vNext; vNext._prev = vNew; vNew._anEdge = eOrig; // leave coords, s, t undefined // fix other edges on this vertex loop var e = eOrig; do { e._Org = vNew; e = e._Onext; } while (e != eOrig); } /// /// MakeFace( eOrig, fNext ) attaches a new face and makes it the left /// face of all edges in the face loop to which eOrig belongs. "fNext" gives /// a place to insert the new face in the global face list. We insert /// the new face *before* fNext so that algorithms which walk the face /// list will not see the newly created faces. /// public static void MakeFace(Edge eOrig, Face fNext) { var fNew = MeshUtils.Face.Create(); // insert in circular doubly-linked list before fNext var fPrev = fNext._prev; fNew._prev = fPrev; fPrev._next = fNew; fNew._next = fNext; fNext._prev = fNew; fNew._anEdge = eOrig; fNew._trail = null; fNew._marked = false; // The new face is marked "inside" if the old one was. This is a // convenience for the common case where a face has been split in two. fNew._inside = fNext._inside; // fix other edges on this face loop var e = eOrig; do { e._Lface = fNew; e = e._Lnext; } while (e != eOrig); } /// /// KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym), /// and removes from the global edge list. /// public static void KillEdge(Edge eDel) { // Half-edges are allocated in pairs, see EdgePair above Edge.EnsureFirst(ref eDel); // delete from circular doubly-linked list var eNext = eDel._next; var ePrev = eDel._Sym._next; eNext._Sym._next = ePrev; ePrev._Sym._next = eNext; eDel.Free(); } /// /// KillVertex( vDel ) destroys a vertex and removes it from the global /// vertex list. It updates the vertex loop to point to a given new vertex. /// public static void KillVertex(Vertex vDel, Vertex newOrg) { var eStart = vDel._anEdge; // change the origin of all affected edges var e = eStart; do { e._Org = newOrg; e = e._Onext; } while (e != eStart); // delete from circular doubly-linked list var vPrev = vDel._prev; var vNext = vDel._next; vNext._prev = vPrev; vPrev._next = vNext; vDel.Free(); } /// /// KillFace( fDel ) destroys a face and removes it from the global face /// list. It updates the face loop to point to a given new face. /// public static void KillFace(Face fDel, Face newLFace) { var eStart = fDel._anEdge; // change the left face of all affected edges var e = eStart; do { e._Lface = newLFace; e = e._Lnext; } while (e != eStart); // delete from circular doubly-linked list var fPrev = fDel._prev; var fNext = fDel._next; fNext._prev = fPrev; fPrev._next = fNext; fDel.Free(); } /// /// Return signed area of face. /// public static Real FaceArea(Face f) { Real area = 0; var e = f._anEdge; do { area += (e._Org._s - e._Dst._s) * (e._Org._t + e._Dst._t); e = e._Lnext; } while (e != f._anEdge); return area; } } } } // namespace Unity.VectorGraphics.External