using Jobberwocky.GeometryAlgorithms.Source.Core;
using Jobberwocky.GeometryAlgorithms.Source.Parameters;
using Jobberwocky.MIConvexHull;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Jobberwocky.GeometryAlgorithms.Source.Algorithms.Triangulation3D
{
public class Triangulation3DWrapper
{
public Triangulation3DWrapper() { }
///
/// Creates a 3D triangulation of the given input points.
/// Note that this method assumes that the 3D shape is convex and without holes.
/// This means that concave shapes are triangulated to a convex shape and holes are removed.
///
///
/// Geometry
public Geometry Triangulate3D(Triangulation3DParameters parameters)
{
var geometry = Triangulate3DBase(parameters);
return geometry;
}
///
/// The base method for the 3D triangulation
///
///
/// Geometry
private Geometry Triangulate3DBase(Triangulation3DParameters parameters)
{
var geometry = new Geometry();
if (parameters == null) {
parameters = new Triangulation3DParameters();
}
var points = parameters.Points;
// We only triangulate when there are enough points available
if (points != null && points.Length > 3) {
VertexId[] pointVertices = VectorToVertex(points, parameters.CoordinateSystem);
DefaultTriangulationCell[] tetrahedrons;
if (points.Length == 4) {
var tetrahedronVertices = pointVertices.ToList();
tetrahedronVertices.Sort((a, b)
=> {
return a.Position[0].CompareTo(b.Position[0]);
});
var tetrahedron = new DefaultTriangulationCell();
tetrahedron.Vertices = tetrahedronVertices.ToArray();
tetrahedron.Adjacency = new DefaultTriangulationCell[] {null, null, null, null};
tetrahedrons = new[] {tetrahedron};
} else {
var triangulation = Triangulation.CreateDelaunay(pointVertices);
// A 3D triangulation returns tetrahedrons instead of triangles
tetrahedrons = triangulation.Cells.ToArray();
}
var vertices = new Dictionary();
var indices = new List();
int index = 0;
for (int i = 0; i < tetrahedrons.Length; i++) {
var tetrahedron = tetrahedrons[i];
var tetrahedronIndices = new int[tetrahedron.Vertices.Length];
for (int j = 0; j < tetrahedron.Vertices.Length; j++) {
Vertex vertex = new Vertex(
Utils.FromCoordinateSystemDefaultTo(
new Vector3((float) tetrahedron.Vertices[j].Position[0],
(float) tetrahedron.Vertices[j].Position[1],
(float) tetrahedron.Vertices[j].Position[2]),
parameters.CoordinateSystem),
tetrahedron.Vertices[j].Id);
if (!vertices.ContainsKey(vertex.Id)) {
vertex.Index = index++;
vertices.Add(vertex.Id, vertex);
} else {
vertex.Index = vertices[vertex.Id].Index;
}
tetrahedronIndices[j] = vertex.Index;
}
// Now are going to extract the triangles from the tetrahedrons
for (int j = 0; j < tetrahedron.Adjacency.Length; j++) {
// Create the triangles, if we only want the boundaries of the mesh,
// we only have to create a triangle when a face of a tetrahedron does not have a neighbor
if (!parameters.BoundaryOnly || tetrahedron.Adjacency[j] == null) {
switch (j) {
case 0:
indices.Add(tetrahedronIndices[2]);
indices.Add(tetrahedronIndices[1]);
indices.Add(tetrahedronIndices[3]);
break;
case 1:
indices.Add(tetrahedronIndices[0]);
indices.Add(tetrahedronIndices[2]);
indices.Add(tetrahedronIndices[3]);
break;
case 2:
indices.Add(tetrahedronIndices[3]);
indices.Add(tetrahedronIndices[1]);
indices.Add(tetrahedronIndices[0]);
break;
case 3:
indices.Add(tetrahedronIndices[1]);
indices.Add(tetrahedronIndices[2]);
indices.Add(tetrahedronIndices[0]);
break;
}
// Reverse order if we only want the back side
if (parameters.Side == Side.Back) {
var tempIndex = indices[indices.Count - 3];
indices[indices.Count - 3] = indices[indices.Count - 1];
indices[indices.Count - 1] = tempIndex;
}
// Add reverse order as well if we want both sides
if (parameters.Side == Side.Double) {
indices.Add(indices[indices.Count - 1]);
indices.Add(indices[indices.Count - 2]);
indices.Add(indices[indices.Count - 3]);
}
}
}
}
geometry.Vertices = vertices.Values.ToArray();
geometry.Indices = indices.ToArray();
}
return geometry;
}
///
/// Transforms a vector3 array to a vertex array that is usable for the miconvexhull library
///
///
///
private VertexId[] VectorToVertex(Vector3[] vectors, CoordinateSystem coordinateSystem)
{
VertexId[] vertices = new VertexId[vectors.Length];
for (int i = 0; i < vectors.Length; i++) {
var vector = Utils.ToCoordinateSystemDefault(vectors[i], coordinateSystem);
vertices[i] = new VertexId {
Position = new double[3] {vector.x, vector.y, vector.z},
Id = i
};
}
return vertices;
}
private class VertexId : DefaultVertex
{
public int Id { get; set; }
}
}
}