mirror of
https://gitgud.io/AbstractConcept/rimworld-animation-studio.git
synced 2024-08-15 00:43:27 +00:00
Initial commit
This commit is contained in:
commit
3c7cc0c973
8391 changed files with 704313 additions and 0 deletions
|
@ -0,0 +1,489 @@
|
|||
// -----------------------------------------------------------------------
|
||||
// <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
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue