diff --git a/sandbox/embed_selfhost_fullscreen.html b/sandbox/embed_selfhost_fullscreen.html
index aa422b0..9523c96 100644
--- a/sandbox/embed_selfhost_fullscreen.html
+++ b/sandbox/embed_selfhost_fullscreen.html
@@ -28,6 +28,7 @@
+
diff --git a/sandbox/embed_selfhost_multiple.html b/sandbox/embed_selfhost_multiple.html
index f667d31..97aae2f 100644
--- a/sandbox/embed_selfhost_multiple.html
+++ b/sandbox/embed_selfhost_multiple.html
@@ -30,6 +30,7 @@
+
diff --git a/sandbox/embed_selfhost_single.html b/sandbox/embed_selfhost_single.html
index 062dc2f..305cc9d 100644
--- a/sandbox/embed_selfhost_single.html
+++ b/sandbox/embed_selfhost_single.html
@@ -28,6 +28,7 @@
+
diff --git a/sandbox/embed_selfhost_single_scroll.html b/sandbox/embed_selfhost_single_scroll.html
index 47b7388..915c37e 100644
--- a/sandbox/embed_selfhost_single_scroll.html
+++ b/sandbox/embed_selfhost_single_scroll.html
@@ -28,6 +28,7 @@
+
diff --git a/source/model/modelutils.js b/source/model/modelutils.js
index a19d39b..ade114f 100644
--- a/source/model/modelutils.js
+++ b/source/model/modelutils.js
@@ -212,3 +212,41 @@ OV.GetMeshBoundingBox = function (mesh)
}
return calculator.GetBox ();
};
+
+OV.GetModelBoundingBox = function (model)
+{
+ let calculator = new OV.BoundingBoxCalculator3D ();
+ for (let i = 0; i < model.MeshCount (); i++) {
+ let mesh = model.GetMesh (i);
+ for (let j = 0; j < mesh.VertexCount (); j++) {
+ let vertex = mesh.GetVertex (j);
+ calculator.AddPoint (vertex);
+ }
+ }
+ return calculator.GetBox ();
+};
+
+OV.GetModelTopology = function (model)
+{
+ function GetVertexIndex (vertex, octree, topology)
+ {
+ let index = octree.FindPoint (vertex);
+ if (index === null) {
+ index = topology.AddVertex ();
+ octree.AddPoint (vertex, index);
+ }
+ return index;
+ }
+
+ let boundingBox = OV.GetModelBoundingBox (model);
+ let octree = new OV.Octree (boundingBox);
+ let topology = new OV.Topology ();
+
+ OV.EnumerateModelTriangles (model, function (v0, v1, v2) {
+ let v0Index = GetVertexIndex (v0, octree, topology);
+ let v1Index = GetVertexIndex (v1, octree, topology);
+ let v2Index = GetVertexIndex (v2, octree, topology);
+ topology.AddTriangle (v0Index, v1Index, v2Index);
+ });
+ return topology;
+};
diff --git a/source/model/topology.js b/source/model/topology.js
new file mode 100644
index 0000000..4209841
--- /dev/null
+++ b/source/model/topology.js
@@ -0,0 +1,138 @@
+OV.TopologyVertex = class
+{
+ constructor ()
+ {
+ this.edges = [];
+ this.triangles = [];
+ }
+};
+
+OV.TopologyEdge = class
+{
+ constructor (vertex1, vertex2)
+ {
+ this.vertex1 = vertex1;
+ this.vertex2 = vertex2;
+ this.triangles = [];
+ }
+};
+
+OV.TopologyTriangleEdge = class
+{
+ constructor (edge, reversed)
+ {
+ this.edge = edge;
+ this.reversed = reversed;
+ }
+};
+
+OV.TopologyTriangle = class
+{
+ constructor ()
+ {
+ this.triEdge1 = null;
+ this.triEdge2 = null;
+ this.triEdge3 = null;
+ }
+};
+
+OV.Topology = class
+{
+ constructor ()
+ {
+ this.vertices = [];
+ this.edges = [];
+ this.triangleEdges = [];
+ this.triangles = [];
+ this.edgeStartToEndVertexMap = {};
+ }
+
+ AddVertex ()
+ {
+ this.vertices.push (new OV.TopologyVertex ());
+ return this.vertices.length - 1;
+ }
+
+ AddTriangle (vertex1, vertex2, vertex3)
+ {
+ function AddTriangleToVertex (vertices, vertexIndex, triangleIndex)
+ {
+ let vertex = vertices[vertexIndex];
+ vertex.triangles.push (triangleIndex);
+ }
+
+ function AddEdgeToVertex (vertices, triangleEdges, vertexIndex, triangleEdgeIndex)
+ {
+ let vertex = vertices[vertexIndex];
+ let triangleEdge = triangleEdges[triangleEdgeIndex];
+ vertex.edges.push (triangleEdge.edge);
+ }
+
+ function AddTriangleToEdge (edges, triangleEdges, triangleEdgeIndex, triangleIndex)
+ {
+ let triangleEdge = triangleEdges[triangleEdgeIndex];
+ let edge = edges[triangleEdge.edge];
+ edge.triangles.push (triangleIndex);
+ }
+
+ let triangleIndex = this.triangles.length;
+ let triangle = new OV.TopologyTriangle ();
+ triangle.triEdge1 = this.AddTriangleEdge (vertex1, vertex2);
+ triangle.triEdge2 = this.AddTriangleEdge (vertex2, vertex3);
+ triangle.triEdge3 = this.AddTriangleEdge (vertex3, vertex1);
+
+ AddTriangleToVertex (this.vertices, vertex1, triangleIndex);
+ AddTriangleToVertex (this.vertices, vertex2, triangleIndex);
+ AddTriangleToVertex (this.vertices, vertex3, triangleIndex);
+
+ AddEdgeToVertex (this.vertices, this.triangleEdges, vertex1, triangle.triEdge1);
+ AddEdgeToVertex (this.vertices, this.triangleEdges, vertex2, triangle.triEdge2);
+ AddEdgeToVertex (this.vertices, this.triangleEdges, vertex3, triangle.triEdge3);
+
+ AddTriangleToEdge (this.edges, this.triangleEdges, triangle.triEdge1, triangleIndex);
+ AddTriangleToEdge (this.edges, this.triangleEdges, triangle.triEdge2, triangleIndex);
+ AddTriangleToEdge (this.edges, this.triangleEdges, triangle.triEdge3, triangleIndex);
+
+ this.triangles.push (triangle);
+ }
+
+ AddTriangleEdge (vertex1, vertex2)
+ {
+ let startVertex = vertex1;
+ let endVertex = vertex2;
+ let reversed = false;
+ if (vertex2 < vertex1) {
+ startVertex = vertex2;
+ endVertex = vertex1;
+ reversed = true;
+ }
+
+ let edgeIndex = this.AddEdge (startVertex, endVertex);
+ this.triangleEdges.push (new OV.TopologyTriangleEdge (edgeIndex, reversed));
+ return this.triangleEdges.length - 1;
+ }
+
+ AddEdge (startVertex, endVertex)
+ {
+ if (this.edgeStartToEndVertexMap[startVertex] === undefined) {
+ this.edgeStartToEndVertexMap[startVertex] = [];
+ }
+
+ let endVertices = this.edgeStartToEndVertexMap[startVertex];
+ for (let i = 0; i < endVertices.length; i++) {
+ let endVertexItem = endVertices[i];
+ if (endVertexItem.endVertex === endVertex) {
+ return endVertexItem.edgeIndex;
+ }
+ }
+
+ let edgeIndex = this.edges.length;
+ endVertices.push ({
+ endVertex : endVertex,
+ edgeIndex : edgeIndex
+ });
+
+ this.edges.push (new OV.TopologyEdge (startVertex, endVertex));
+ return edgeIndex;
+ }
+};
diff --git a/test/tests/modelutils_test.js b/test/tests/modelutils_test.js
index 3a3d2e2..563dcbd 100644
--- a/test/tests/modelutils_test.js
+++ b/test/tests/modelutils_test.js
@@ -128,7 +128,7 @@ describe ('Model Utils', function () {
return Math.sqrt (areaSquare);
}
- var model = testUtils.GetCubeModel ();
+ var model = testUtils.GetModelWithOneMesh (testUtils.GetCubeMesh ());
let surface = 0.0;
let volume = 0.0;
for (let i = 0; i < model.MeshCount (); i++) {
@@ -146,4 +146,54 @@ describe ('Model Utils', function () {
assert (OV.IsEqual (volume, 1.0));
assert (OV.IsEqual (surface, 6.0));
});
+
+ it ('Tetrahedron Topology Calculation', function () {
+ let tetrahedron = testUtils.GetModelWithOneMesh (testUtils.GetTetrahedronMesh ());
+ let topology = OV.GetModelTopology (tetrahedron);
+ assert.strictEqual (topology.vertices.length, 4);
+ assert.strictEqual (topology.edges.length, 6);
+ assert.strictEqual (topology.triangleEdges.length, 4 * 3);
+ assert.strictEqual (topology.triangles.length, 4);
+ for (let i = 0; i < topology.vertices.length; i++) {
+ assert.strictEqual (topology.vertices[i].edges.length, 3);
+ assert.strictEqual (topology.vertices[i].triangles.length, 3);
+ }
+ for (let i = 0; i < topology.edges.length; i++) {
+ assert.strictEqual (topology.edges[i].triangles.length, 2);
+ }
+ });
+
+ it ('Cube Topology Calculation', function () {
+ let cube = testUtils.GetModelWithOneMesh (testUtils.GetCubeMesh ());
+ let topology = OV.GetModelTopology (cube);
+ assert.strictEqual (topology.vertices.length, 8);
+ assert.strictEqual (topology.edges.length, 12 + 6);
+ assert.strictEqual (topology.triangleEdges.length, 6 * 2 * 3);
+ assert.strictEqual (topology.triangles.length, 6 * 2);
+
+ let verticesWith4Triangles = 0;
+ let verticesWith5Triangles = 0;
+ let verticesWith4Edges = 0;
+ let verticesWith5Edges = 0;
+ for (let i = 0; i < topology.vertices.length; i++) {
+ if (topology.vertices[i].triangles.length == 4) {
+ verticesWith4Triangles += 1;
+ } else if (topology.vertices[i].triangles.length == 5) {
+ verticesWith5Triangles += 1;
+ }
+ if (topology.vertices[i].edges.length == 4) {
+ verticesWith4Edges += 1;
+ } else if (topology.vertices[i].edges.length == 5) {
+ verticesWith5Edges += 1;
+ }
+ }
+ assert.strictEqual (verticesWith4Triangles, 4);
+ assert.strictEqual (verticesWith5Triangles, 4);
+ assert.strictEqual (verticesWith4Edges, 4);
+ assert.strictEqual (verticesWith5Edges, 4);
+
+ for (let i = 0; i < topology.edges.length; i++) {
+ assert.strictEqual (topology.edges[i].triangles.length, 2);
+ }
+ });
});
diff --git a/test/utils/testutils.js b/test/utils/testutils.js
index 6a38c46..8d247aa 100644
--- a/test/utils/testutils.js
+++ b/test/utils/testutils.js
@@ -163,12 +163,28 @@ module.exports =
return cube;
},
- GetCubeModel ()
+ GetTetrahedronMesh ()
+ {
+ var tetrahedron = new OV.Mesh ();
+
+ let a = 1.0;
+ tetrahedron.AddVertex (new OV.Coord3D (+a, +a, +a));
+ tetrahedron.AddVertex (new OV.Coord3D (-a, -a, +a));
+ tetrahedron.AddVertex (new OV.Coord3D (-a, +a, -a));
+ tetrahedron.AddVertex (new OV.Coord3D (+a, -a, -a));
+ tetrahedron.AddTriangle (new OV.Triangle (0, 1, 3));
+ tetrahedron.AddTriangle (new OV.Triangle (0, 2, 1));
+ tetrahedron.AddTriangle (new OV.Triangle (0, 3, 2));
+ tetrahedron.AddTriangle (new OV.Triangle (1, 2, 3));
+
+ return tetrahedron;
+ },
+
+ GetModelWithOneMesh (mesh)
{
var model = new OV.Model ();
- var cube = this.GetCubeMesh ();
- model.AddMesh (cube);
+ model.AddMesh (mesh);
OV.FinalizeModel (model, function () { new OV.Material () });
return model;
- }
+ }
}
diff --git a/tools/config.json b/tools/config.json
index a3954ed..d44a042 100644
--- a/tools/config.json
+++ b/tools/config.json
@@ -24,6 +24,7 @@
"source/model/mesh.js",
"source/model/meshbuffer.js",
"source/model/model.js",
+ "source/model/topology.js",
"source/model/modelutils.js",
"source/model/modelfinalization.js",
"source/import/importerutils.js",
diff --git a/website/embed.html b/website/embed.html
index 115ccbe..356f0da 100644
--- a/website/embed.html
+++ b/website/embed.html
@@ -37,6 +37,7 @@
+
diff --git a/website/index.html b/website/index.html
index bebe7a4..80cecc0 100644
--- a/website/index.html
+++ b/website/index.html
@@ -37,6 +37,7 @@
+