123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- // -----------------------------------------------------------------------
- // <copyright file="Converter.cs" company="">
- // Original Triangle code by Jonathan Richard Shewchuk, http://www.cs.cmu.edu/~quake/triangle.html
- // Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
- // </copyright>
- // -----------------------------------------------------------------------
- namespace UnityEngine.U2D.Animation.TriangleNet
- .Meshing
- {
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using Animation.TriangleNet.Geometry;
- using Animation.TriangleNet.Topology;
- using Animation.TriangleNet.Topology.DCEL;
- using HVertex = Animation.TriangleNet.Topology.DCEL.Vertex;
- using TVertex = Animation.TriangleNet.Geometry.Vertex;
- /// <summary>
- /// The Converter class provides methods for mesh reconstruction and conversion.
- /// </summary>
- internal static class Converter
- {
- #region Triangle mesh conversion
- /// <summary>
- /// Reconstruct a triangulation from its raw data representation.
- /// </summary>
- internal static Mesh ToMesh(Polygon polygon, IList<ITriangle> triangles)
- {
- return ToMesh(polygon, triangles.ToArray());
- }
- /// <summary>
- /// Reconstruct a triangulation from its raw data representation.
- /// </summary>
- internal static Mesh ToMesh(Polygon polygon, ITriangle[] triangles)
- {
- Otri tri = default(Otri);
- Osub subseg = default(Osub);
- int i = 0;
- int elements = triangles == null ? 0 : triangles.Length;
- int segments = polygon.Segments.Count;
- // TODO: Configuration should be a function argument.
- var mesh = new Mesh(new Configuration());
- mesh.TransferNodes(polygon.Points);
- mesh.regions.AddRange(polygon.Regions);
- mesh.behavior.useRegions = polygon.Regions.Count > 0;
- if (polygon.Segments.Count > 0)
- {
- mesh.behavior.Poly = true;
- mesh.holes.AddRange(polygon.Holes);
- }
- // Create the triangles.
- for (i = 0; i < elements; i++)
- {
- mesh.MakeTriangle(ref tri);
- }
- if (mesh.behavior.Poly)
- {
- mesh.insegments = segments;
- // Create the subsegments.
- for (i = 0; i < segments; i++)
- {
- mesh.MakeSegment(ref subseg);
- }
- }
- var vertexarray = SetNeighbors(mesh, triangles);
- SetSegments(mesh, polygon, vertexarray);
- return mesh;
- }
- /// <summary>
- /// Finds the adjacencies between triangles by forming a stack of triangles for
- /// each vertex. Each triangle is on three different stacks simultaneously.
- /// </summary>
- private static List<Otri>[] SetNeighbors(Mesh mesh, ITriangle[] triangles)
- {
- Otri tri = default(Otri);
- Otri triangleleft = default(Otri);
- Otri checktri = default(Otri);
- Otri checkleft = default(Otri);
- Otri nexttri;
- TVertex tdest, tapex;
- TVertex checkdest, checkapex;
- int[] corner = new int[3];
- int aroundvertex;
- int i;
- // Allocate a temporary array that maps each vertex to some adjacent triangle.
- var vertexarray = new List<Otri>[mesh.vertices.Count];
- // Each vertex is initially unrepresented.
- for (i = 0; i < mesh.vertices.Count; i++)
- {
- Otri tmp = default(Otri);
- tmp.tri = mesh.dummytri;
- vertexarray[i] = new List<Otri>(3);
- vertexarray[i].Add(tmp);
- }
- i = 0;
- // Read the triangles from the .ele file, and link
- // together those that share an edge.
- foreach (var item in mesh.triangles)
- {
- tri.tri = item;
- // Copy the triangle's three corners.
- for (int j = 0; j < 3; j++)
- {
- corner[j] = triangles[i].GetVertexID(j);
- if ((corner[j] < 0) || (corner[j] >= mesh.invertices))
- {
- Log.Instance.Error("Triangle has an invalid vertex index.", "MeshReader.Reconstruct()");
- throw new Exception("Triangle has an invalid vertex index.");
- }
- }
- // Read the triangle's attributes.
- tri.tri.label = triangles[i].Label;
- // TODO: VarArea
- if (mesh.behavior.VarArea)
- {
- tri.tri.area = triangles[i].Area;
- }
- // Set the triangle's vertices.
- tri.orient = 0;
- tri.SetOrg(mesh.vertices[corner[0]]);
- tri.SetDest(mesh.vertices[corner[1]]);
- tri.SetApex(mesh.vertices[corner[2]]);
- // Try linking the triangle to others that share these vertices.
- for (tri.orient = 0; tri.orient < 3; tri.orient++)
- {
- // Take the number for the origin of triangleloop.
- aroundvertex = corner[tri.orient];
- int index = vertexarray[aroundvertex].Count - 1;
- // Look for other triangles having this vertex.
- nexttri = vertexarray[aroundvertex][index];
- // Push the current triangle onto the stack.
- vertexarray[aroundvertex].Add(tri);
- checktri = nexttri;
- if (checktri.tri.id != Mesh.DUMMY)
- {
- tdest = tri.Dest();
- tapex = tri.Apex();
- // Look for other triangles that share an edge.
- do
- {
- checkdest = checktri.Dest();
- checkapex = checktri.Apex();
- if (tapex == checkdest)
- {
- // The two triangles share an edge; bond them together.
- tri.Lprev(ref triangleleft);
- triangleleft.Bond(ref checktri);
- }
- if (tdest == checkapex)
- {
- // The two triangles share an edge; bond them together.
- checktri.Lprev(ref checkleft);
- tri.Bond(ref checkleft);
- }
- // Find the next triangle in the stack.
- index--;
- nexttri = vertexarray[aroundvertex][index];
- checktri = nexttri;
- }
- while (checktri.tri.id != Mesh.DUMMY);
- }
- }
- i++;
- }
- return vertexarray;
- }
- /// <summary>
- /// Finds the adjacencies between triangles and subsegments.
- /// </summary>
- private static void SetSegments(Mesh mesh, Polygon polygon, List<Otri>[] vertexarray)
- {
- Otri checktri = default(Otri);
- Otri nexttri; // Triangle
- TVertex checkdest;
- Otri checkneighbor = default(Otri);
- Osub subseg = default(Osub);
- Otri prevlink; // Triangle
- TVertex tmp;
- TVertex sorg, sdest;
- bool notfound;
- //bool segmentmarkers = false;
- int boundmarker;
- int aroundvertex;
- int i;
- int hullsize = 0;
- // Prepare to count the boundary edges.
- if (mesh.behavior.Poly)
- {
- // Link the segments to their neighboring triangles.
- boundmarker = 0;
- i = 0;
- foreach (var item in mesh.subsegs.Values)
- {
- subseg.seg = item;
- sorg = polygon.Segments[i].GetVertex(0);
- sdest = polygon.Segments[i].GetVertex(1);
- boundmarker = polygon.Segments[i].Label;
- if ((sorg.id < 0 || sorg.id >= mesh.invertices) || (sdest.id < 0 || sdest.id >= mesh.invertices))
- {
- Log.Instance.Error("Segment has an invalid vertex index.", "MeshReader.Reconstruct()");
- throw new Exception("Segment has an invalid vertex index.");
- }
- // set the subsegment's vertices.
- subseg.orient = 0;
- subseg.SetOrg(sorg);
- subseg.SetDest(sdest);
- subseg.SetSegOrg(sorg);
- subseg.SetSegDest(sdest);
- subseg.seg.boundary = boundmarker;
- // Try linking the subsegment to triangles that share these vertices.
- for (subseg.orient = 0; subseg.orient < 2; subseg.orient++)
- {
- // Take the number for the destination of subsegloop.
- aroundvertex = subseg.orient == 1 ? sorg.id : sdest.id;
- int index = vertexarray[aroundvertex].Count - 1;
- // Look for triangles having this vertex.
- prevlink = vertexarray[aroundvertex][index];
- nexttri = vertexarray[aroundvertex][index];
- checktri = nexttri;
- tmp = subseg.Org();
- notfound = true;
- // Look for triangles having this edge. Note that I'm only
- // comparing each triangle's destination with the subsegment;
- // each triangle's apex is handled through a different vertex.
- // Because each triangle appears on three vertices' lists, each
- // occurrence of a triangle on a list can (and does) represent
- // an edge. In this way, most edges are represented twice, and
- // every triangle-subsegment bond is represented once.
- while (notfound && (checktri.tri.id != Mesh.DUMMY))
- {
- checkdest = checktri.Dest();
- if (tmp == checkdest)
- {
- // We have a match. Remove this triangle from the list.
- //prevlink = vertexarray[aroundvertex][index];
- vertexarray[aroundvertex].Remove(prevlink);
- // Bond the subsegment to the triangle.
- checktri.SegBond(ref subseg);
- // Check if this is a boundary edge.
- checktri.Sym(ref checkneighbor);
- if (checkneighbor.tri.id == Mesh.DUMMY)
- {
- // The next line doesn't insert a subsegment (because there's
- // already one there), but it sets the boundary markers of
- // the existing subsegment and its vertices.
- mesh.InsertSubseg(ref checktri, 1);
- hullsize++;
- }
- notfound = false;
- }
- index--;
- // Find the next triangle in the stack.
- prevlink = vertexarray[aroundvertex][index];
- nexttri = vertexarray[aroundvertex][index];
- checktri = nexttri;
- }
- }
- i++;
- }
- }
- // Mark the remaining edges as not being attached to any subsegment.
- // Also, count the (yet uncounted) boundary edges.
- for (i = 0; i < mesh.vertices.Count; i++)
- {
- // Search the stack of triangles adjacent to a vertex.
- int index = vertexarray[i].Count - 1;
- nexttri = vertexarray[i][index];
- checktri = nexttri;
- while (checktri.tri.id != Mesh.DUMMY)
- {
- // Find the next triangle in the stack before this
- // information gets overwritten.
- index--;
- nexttri = vertexarray[i][index];
- // No adjacent subsegment. (This overwrites the stack info.)
- checktri.SegDissolve(mesh.dummysub);
- checktri.Sym(ref checkneighbor);
- if (checkneighbor.tri.id == Mesh.DUMMY)
- {
- mesh.InsertSubseg(ref checktri, 1);
- hullsize++;
- }
- checktri = nexttri;
- }
- }
- mesh.hullsize = hullsize;
- }
- #endregion
- #region DCEL conversion
- internal static DcelMesh ToDCEL(Mesh mesh)
- {
- var dcel = new DcelMesh();
- var vertices = new HVertex[mesh.vertices.Count];
- var faces = new Face[mesh.triangles.Count];
- dcel.HalfEdges.Capacity = 2 * mesh.NumberOfEdges;
- mesh.Renumber();
- HVertex vertex;
- foreach (var v in mesh.vertices.Values)
- {
- vertex = new HVertex(v.x, v.y);
- vertex.id = v.id;
- vertex.label = v.label;
- vertices[v.id] = vertex;
- }
- // Maps a triangle to its 3 edges (used to set next pointers).
- var map = new List<HalfEdge>[mesh.triangles.Count];
- Face face;
- foreach (var t in mesh.triangles)
- {
- face = new Face(null);
- face.id = t.id;
- faces[t.id] = face;
- map[t.id] = new List<HalfEdge>(3);
- }
- Otri tri = default(Otri), neighbor = default(Otri);
- Animation.TriangleNet.Geometry.Vertex org, dest;
- int id, nid, count = mesh.triangles.Count;
- HalfEdge edge, twin, next;
- var edges = dcel.HalfEdges;
- // Count half-edges (edge ids).
- int k = 0;
- // Maps a vertex to its leaving boundary edge.
- var boundary = new Dictionary<int, HalfEdge>();
- foreach (var t in mesh.triangles)
- {
- id = t.id;
- tri.tri = t;
- for (int i = 0; i < 3; i++)
- {
- tri.orient = i;
- tri.Sym(ref neighbor);
- nid = neighbor.tri.id;
- if (id < nid || nid < 0)
- {
- face = faces[id];
- // Get the endpoints of the current triangle edge.
- org = tri.Org();
- dest = tri.Dest();
- // Create half-edges.
- edge = new HalfEdge(vertices[org.id], face);
- twin = new HalfEdge(vertices[dest.id], nid < 0 ? Face.Empty : faces[nid]);
- map[id].Add(edge);
- if (nid >= 0)
- {
- map[nid].Add(twin);
- }
- else
- {
- boundary.Add(dest.id, twin);
- }
- // Set leaving edges.
- edge.origin.leaving = edge;
- twin.origin.leaving = twin;
- // Set twin edges.
- edge.twin = twin;
- twin.twin = edge;
- edge.id = k++;
- twin.id = k++;
- edges.Add(edge);
- edges.Add(twin);
- }
- }
- }
- // Set next pointers for each triangle face.
- foreach (var t in map)
- {
- edge = t[0];
- next = t[1];
- if (edge.twin.origin.id == next.origin.id)
- {
- edge.next = next;
- next.next = t[2];
- t[2].next = edge;
- }
- else
- {
- edge.next = t[2];
- next.next = edge;
- t[2].next = next;
- }
- }
- // Resolve boundary edges.
- foreach (var e in boundary.Values)
- {
- e.next = boundary[e.twin.origin.id];
- }
- dcel.Vertices.AddRange(vertices);
- dcel.Faces.AddRange(faces);
- return dcel;
- }
- #endregion
- }
- }
|