diff --git a/source/engine/main.js b/source/engine/main.js index 6d09507..4b15948 100644 --- a/source/engine/main.js +++ b/source/engine/main.js @@ -52,7 +52,7 @@ import { MeshInstanceId, MeshInstance } from './model/meshinstance.js'; import { GetMeshType, CalculateTriangleNormal, TransformMesh, FlipMeshTrianglesOrientation, MeshType } from './model/meshutils.js'; import { Model } from './model/model.js'; import { FinalizeModel, CheckModel } from './model/modelfinalization.js'; -import { IsModelEmpty, GetBoundingBox, GetTopology, IsSolid, HasDefaultMaterial, ReplaceDefaultMaterialColor } from './model/modelutils.js'; +import { IsModelEmpty, GetBoundingBox, GetTopology, IsTwoManifold, HasDefaultMaterial, ReplaceDefaultMaterialColor } from './model/modelutils.js'; import { Node, NodeType } from './model/node.js'; import { Object3D, ModelObject3D } from './model/object.js'; import { Property, PropertyGroup, PropertyToString, PropertyType } from './model/property.js'; @@ -242,7 +242,7 @@ export { IsModelEmpty, GetBoundingBox, GetTopology, - IsSolid, + IsTwoManifold, HasDefaultMaterial, ReplaceDefaultMaterialColor, Node, diff --git a/source/engine/model/modelutils.js b/source/engine/model/modelutils.js index 02f986b..02ae22c 100644 --- a/source/engine/model/modelutils.js +++ b/source/engine/model/modelutils.js @@ -1,6 +1,7 @@ import { BoundingBoxCalculator3D } from '../geometry/box3d.js'; import { Octree } from '../geometry/octree.js'; import { GetMeshType, MeshType } from './meshutils.js'; +import { Model } from './model.js'; import { Topology } from './topology.js'; export function IsModelEmpty (model) @@ -48,7 +49,7 @@ export function GetTopology (object3D) return topology; } -export function IsSolid (object3D) +export function IsTwoManifold (object3D) { function GetEdgeOrientationInTriangle (topology, triangleIndex, edgeIndex) { @@ -68,28 +69,30 @@ export function IsSolid (object3D) return null; } - const topology = GetTopology (object3D); - for (let edgeIndex = 0; edgeIndex < topology.edges.length; edgeIndex++) { - const edge = topology.edges[edgeIndex]; - let triCount = edge.triangles.length; - if (triCount === 0 || triCount % 2 !== 0) { - return false; - } - let edgesDirection = 0; - for (let triIndex = 0; triIndex < edge.triangles.length; triIndex++) { - const triangleIndex = edge.triangles[triIndex]; - const edgeOrientation = GetEdgeOrientationInTriangle (topology, triangleIndex, edgeIndex); - if (edgeOrientation) { - edgesDirection += 1; - } else { - edgesDirection -= 1; + if (object3D instanceof Model) { + let isSolid = true; + object3D.EnumerateMeshInstances ((meshInstance) => { + if (isSolid) { + isSolid = IsTwoManifold (meshInstance); + } + }); + return isSolid; + } else { + const topology = GetTopology (object3D); + for (let edgeIndex = 0; edgeIndex < topology.edges.length; edgeIndex++) { + const edge = topology.edges[edgeIndex]; + if (edge.triangles.length !== 2) { + return false; + } + + let edgeOrientation1 = GetEdgeOrientationInTriangle (topology, edge.triangles[0], edgeIndex); + let edgeOrientation2 = GetEdgeOrientationInTriangle (topology, edge.triangles[1], edgeIndex); + if (edgeOrientation1 === null || edgeOrientation2 === null || edgeOrientation1 === edgeOrientation2) { + return false; } } - if (edgesDirection !== 0) { - return false; - } + return true; } - return true; } export function HasDefaultMaterial (model) diff --git a/source/engine/model/quantities.js b/source/engine/model/quantities.js index b12cddc..8e68395 100644 --- a/source/engine/model/quantities.js +++ b/source/engine/model/quantities.js @@ -1,4 +1,5 @@ import { CoordDistance3D, CrossVector3D, DotVector3D } from '../geometry/coord3d.js'; +import { Model } from './model.js'; export function GetTriangleArea (v0, v1, v2) { @@ -20,11 +21,19 @@ export function GetTetrahedronSignedVolume (v0, v1, v2) export function CalculateVolume (object3D) { - let volume = 0.0; - object3D.EnumerateTriangleVertices ((v0, v1, v2) => { - volume += GetTetrahedronSignedVolume (v0, v1, v2); - }); - return volume; + if (object3D instanceof Model) { + let volume = 0.0; + object3D.EnumerateMeshInstances ((meshInstance) => { + volume += CalculateVolume (meshInstance); + }); + return volume; + } else { + let volume = 0.0; + object3D.EnumerateTriangleVertices ((v0, v1, v2) => { + volume += GetTetrahedronSignedVolume (v0, v1, v2); + }); + return volume; + } } export function CalculateSurfaceArea (object3D) diff --git a/source/engine/model/topology.js b/source/engine/model/topology.js index 02b5748..6923d5d 100644 --- a/source/engine/model/topology.js +++ b/source/engine/model/topology.js @@ -76,6 +76,7 @@ export class Topology } let triangleIndex = this.triangles.length; + let triangle = new TopologyTriangle (); triangle.triEdge1 = this.AddTriangleEdge (vertex1, vertex2); triangle.triEdge2 = this.AddTriangleEdge (vertex2, vertex3); diff --git a/source/website/sidebardetailspanel.js b/source/website/sidebardetailspanel.js index 226b71a..4002486 100644 --- a/source/website/sidebardetailspanel.js +++ b/source/website/sidebardetailspanel.js @@ -1,6 +1,6 @@ import { RunTaskAsync } from '../engine/core/taskrunner.js'; import { SubCoord3D } from '../engine/geometry/coord3d.js'; -import { GetBoundingBox, IsSolid } from '../engine/model/modelutils.js'; +import { GetBoundingBox, IsTwoManifold } from '../engine/model/modelutils.js'; import { CalculateVolume, CalculateSurfaceArea } from '../engine/model/quantities.js'; import { Property, PropertyToString, PropertyType } from '../engine/model/property.js'; import { AddDiv, AddDomElement, ClearDomElement } from '../engine/viewer/domutils.js'; @@ -39,7 +39,7 @@ export class SidebarDetailsPanel extends SidebarPanel this.AddProperty (table, new Property (PropertyType.Number, 'Size Y', size.y)); this.AddProperty (table, new Property (PropertyType.Number, 'Size Z', size.z)); this.AddCalculatedProperty (table, 'Volume', () => { - if (!IsSolid (object3D)) { + if (!IsTwoManifold (object3D)) { return null; } const volume = CalculateVolume (object3D); diff --git a/test/test.js b/test/test.js index 2b913f7..8b6c70b 100644 --- a/test/test.js +++ b/test/test.js @@ -10,6 +10,7 @@ import geometry_test from './tests/geometry_test.js'; import meshbuffer_test from './tests/meshbuffer_test.js'; import mesh_test from './tests/mesh_test.js'; import modelutils_test from './tests/modelutils_test.js'; +import topology_test from './tests/topology_test.js'; import node_test from './tests/node_test.js'; import model_test from './tests/model_test.js'; import quantities_test from './tests/quantities_test.js'; @@ -41,6 +42,7 @@ geometry_test (); meshbuffer_test (); mesh_test (); modelutils_test (); +topology_test (); node_test (); model_test (); quantities_test (); diff --git a/test/tests/generator_test.js b/test/tests/generator_test.js index d8ef5cb..3990abb 100644 --- a/test/tests/generator_test.js +++ b/test/tests/generator_test.js @@ -7,7 +7,7 @@ export default function suite () describe ('Generator', function () { it ('Cuboid with Default Parameters', function () { const cuboid = OV.GenerateCuboid (null, 1.0, 1.0, 1.0); - assert.ok (OV.IsSolid (cuboid)); + assert.ok (OV.IsTwoManifold (cuboid)); assert.ok (OV.IsEqual (OV.CalculateVolume (cuboid), 1.0)); }); @@ -22,53 +22,53 @@ describe ('Generator', function () { it ('Cylinder with Default Parameters', function () { const cylinder = OV.GenerateCylinder (null, 0.5, 1.0, 25, false); - assert.ok (OV.IsSolid (cylinder)); + assert.ok (OV.IsTwoManifold (cylinder)); assert.ok (OV.IsEqualEps (OV.CalculateVolume (cylinder), Math.PI * 0.5 * 0.5 * 1.0, 0.1)); }); it ('Cone with Default Parameters', function () { const cone = OV.GenerateCone (null, 0.2, 0.5, 1.0, 20, false); - assert.ok (OV.IsSolid (cone)); + assert.ok (OV.IsTwoManifold (cone)); assert.ok (OV.IsEqualEps (OV.CalculateVolume (cone), Math.PI / 3.0 * 1.0 * (0.2 * 0.2 + 0.2 * 0.5 + 0.5 * 0.5), 0.1)); }); it ('Cone Zero Top', function () { const cone = OV.GenerateCone (null, 0.0, 0.5, 1.0, 20, false); - assert.ok (OV.IsSolid (cone)); + assert.ok (OV.IsTwoManifold (cone)); assert.ok (OV.IsEqualEps (OV.CalculateVolume (cone), 0.5 * 0.5 * Math.PI * 1.0 / 3.0, 1.0)); }); it ('Cone Zero Bottom', function () { const cone = OV.GenerateCone (null, 0.5, 0.0, 1.0, 20, false); - assert.ok (OV.IsSolid (cone)); + assert.ok (OV.IsTwoManifold (cone)); assert.ok (OV.IsEqualEps (OV.CalculateVolume (cone), 0.5 * 0.5 * Math.PI * 1.0 / 3.0, 1.0)); }); it ('Sphere with Default Parameters', function () { const cylinder = OV.GenerateSphere (null, 0.5, 20, false); - assert.ok (OV.IsSolid (cylinder)); + assert.ok (OV.IsTwoManifold (cylinder)); assert.ok (OV.IsEqualEps (OV.CalculateVolume (cylinder), Math.PI * 0.5 * 0.5 * 0.5 * 4.0 / 3.0, 0.1)); }); it ('Platonic Solids', function () { let tetrahedron = OV.GeneratePlatonicSolid (null, 'tetrahedron', 1.0); - assert.ok (OV.IsSolid (tetrahedron)); + assert.ok (OV.IsTwoManifold (tetrahedron)); assert.ok (OV.IsEqual (OV.CalculateVolume (tetrahedron), 0.5132002392796676)); let hexahedron = OV.GeneratePlatonicSolid (null, 'hexahedron', 1.0); - assert.ok (OV.IsSolid (hexahedron)); + assert.ok (OV.IsTwoManifold (hexahedron)); assert.ok (OV.IsEqual (OV.CalculateVolume (hexahedron), 1.5396007178390028)); let octahedron = OV.GeneratePlatonicSolid (null, 'octahedron', 1.0); - assert.ok (OV.IsSolid (octahedron)); + assert.ok (OV.IsTwoManifold (octahedron)); assert.ok (OV.IsEqual (OV.CalculateVolume (octahedron), 1.3333333333333333)); let dodecahedron = OV.GeneratePlatonicSolid (null, 'dodecahedron', 1.0); - assert.ok (OV.IsSolid (dodecahedron)); + assert.ok (OV.IsTwoManifold (dodecahedron)); assert.ok (OV.IsEqual (OV.CalculateVolume (dodecahedron), 2.7851638631226248)); let icosahedron = OV.GeneratePlatonicSolid (null, 'icosahedron', 1.0); - assert.ok (OV.IsSolid (icosahedron)); + assert.ok (OV.IsTwoManifold (icosahedron)); assert.ok (OV.IsEqual (OV.CalculateVolume (icosahedron), 2.5361507101204093)); }); }); diff --git a/test/tests/importero3dv_test.js b/test/tests/importero3dv_test.js index 03e1f10..f9deee3 100644 --- a/test/tests/importero3dv_test.js +++ b/test/tests/importero3dv_test.js @@ -115,7 +115,7 @@ describe ('O3dv Importer', function () { assert.strictEqual (model.MeshCount (), 5); assert.strictEqual (model.MeshInstanceCount (), 5); - assert.ok (OV.IsSolid (model)); + assert.ok (OV.IsTwoManifold (model)); assert.ok (OV.IsEqual (OV.CalculateVolume (model), 8.707448863695035)); assert.ok (OV.IsEqual (OV.CalculateSurfaceArea (model), 39.636169009449105)); diff --git a/test/tests/modelutils_test.js b/test/tests/modelutils_test.js index b4dad53..52845af 100644 --- a/test/tests/modelutils_test.js +++ b/test/tests/modelutils_test.js @@ -1,6 +1,5 @@ import * as assert from 'assert'; import * as OV from '../../source/engine/main.js'; -import { GetModelWithOneMesh, GetTetrahedronMesh, GetTwoCubesConnectingInOneEdgeModel, GetTwoCubesConnectingInOneFaceModel, GetTwoCubesConnectingInOneVertexModel } from '../utils/testutils.js'; export default function suite () { @@ -55,80 +54,6 @@ describe ('Model Utils', function () { assert.ok (OV.CoordIsEqual3D (modelBounds.min, new OV.Coord3D (0.0, 0.0, 0.0))); assert.ok (OV.CoordIsEqual3D (modelBounds.max, new OV.Coord3D (1.0, 1.0, 1.0))); }); - - it ('Tetrahedron Topology Calculation', function () { - let tetrahedron = GetModelWithOneMesh (GetTetrahedronMesh ()); - let topology = OV.GetTopology (tetrahedron); - assert.ok (OV.IsSolid (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 = GetModelWithOneMesh (OV.GenerateCuboid (null, 1.0, 1.0, 1.0)); - assert.ok (OV.IsSolid (cube)); - - let topology = OV.GetTopology (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); - } - }); - - it ('Two Cubes Connecting in One Vertex Topology Calculation', function () { - const model = GetTwoCubesConnectingInOneVertexModel (); - let topology = OV.GetTopology (model); - assert.strictEqual (topology.vertices.length, 15); - assert.ok (OV.IsSolid (model)); - }); - - it ('Two Cubes Connecting in One Edge Topology Calculation', function () { - const model = GetTwoCubesConnectingInOneEdgeModel (); - let topology = OV.GetTopology (model); - assert.strictEqual (topology.vertices.length, 14); - assert.ok (OV.IsSolid (model)); - }); - - it ('Two Cubes Connecting in One Face Topology Calculation', function () { - const model = GetTwoCubesConnectingInOneFaceModel (); - let topology = OV.GetTopology (model); - assert.strictEqual (topology.vertices.length, 12); - assert.ok (OV.IsSolid (model)); - }); }); } diff --git a/test/tests/quantities_test.js b/test/tests/quantities_test.js index 56e790e..f9af90e 100644 --- a/test/tests/quantities_test.js +++ b/test/tests/quantities_test.js @@ -9,8 +9,8 @@ describe ('Quantities', function () { it ('Cube Volume Calculation', function () { const mesh = OV.GenerateCuboid (null, 1.0, 1.0, 1.0); const model = GetModelWithOneMesh (mesh); - assert.ok (OV.IsSolid (mesh)); - assert.ok (OV.IsSolid (model)); + assert.ok (OV.IsTwoManifold (mesh)); + assert.ok (OV.IsTwoManifold (model)); assert.ok (OV.IsEqual (OV.CalculateVolume (mesh), 1.0)); assert.ok (OV.IsEqual (OV.CalculateVolume (model), 1.0)); }); @@ -18,24 +18,24 @@ describe ('Quantities', function () { it ('Cube with Missing Face Volume Calculation', function () { const mesh = GetCubeWithOneMissingFaceMesh (); const model = GetModelWithOneMesh (mesh); - assert.ok (!OV.IsSolid (model)); + assert.ok (!OV.IsTwoManifold (model)); }); it ('Two Cubes Connecting in One Vertex Volume Calculation', function () { const model = GetTwoCubesConnectingInOneVertexModel (); - assert.ok (OV.IsSolid (model)); + assert.ok (OV.IsTwoManifold (model)); assert.ok (OV.IsEqual (OV.CalculateVolume (model), 2.0)); }); it ('Two Cubes Connecting in One Edge Volume Calculation', function () { const model = GetTwoCubesConnectingInOneEdgeModel (); - assert.ok (OV.IsSolid (model)); + assert.ok (OV.IsTwoManifold (model)); assert.ok (OV.IsEqual (OV.CalculateVolume (model), 2.0)); }); it ('Two Cubes Connecting in One Face Volume Calculation', function () { const model = GetTwoCubesConnectingInOneFaceModel (); - assert.ok (OV.IsSolid (model)); + assert.ok (OV.IsTwoManifold (model)); assert.ok (OV.IsEqual (OV.CalculateVolume (model), 2.0)); }); @@ -62,15 +62,15 @@ describe ('Quantities', function () { mesh.AddTriangle (new OV.Triangle (4, 5, 6)); mesh.AddTriangle (new OV.Triangle (4, 7, 6)); const model = GetModelWithOneMesh (mesh); - assert.ok (!OV.IsSolid (mesh)); - assert.ok (!OV.IsSolid (model)); + assert.ok (!OV.IsTwoManifold (mesh)); + assert.ok (!OV.IsTwoManifold (model)); }); it ('Cube Surface Area Calculation', function () { const mesh = OV.GenerateCuboid (null, 1.0, 1.0, 1.0); const model = GetModelWithOneMesh (mesh); - assert.ok (OV.IsSolid (mesh)); - assert.ok (OV.IsSolid (model)); + assert.ok (OV.IsTwoManifold (mesh)); + assert.ok (OV.IsTwoManifold (model)); assert.ok (OV.IsEqual (OV.CalculateSurfaceArea (mesh), 6.0)); assert.ok (OV.IsEqual (OV.CalculateSurfaceArea (model), 6.0)); }); @@ -78,8 +78,8 @@ describe ('Quantities', function () { it ('Cube with Missing Face Surface Area Calculation', function () { const mesh = GetCubeWithOneMissingFaceMesh (); const model = GetModelWithOneMesh (mesh); - assert.ok (!OV.IsSolid (mesh)); - assert.ok (!OV.IsSolid (model)); + assert.ok (!OV.IsTwoManifold (mesh)); + assert.ok (!OV.IsTwoManifold (model)); assert.ok (OV.IsEqual (OV.CalculateSurfaceArea (mesh), 5.0)); assert.ok (OV.IsEqual (OV.CalculateSurfaceArea (model), 5.0)); }); @@ -88,8 +88,8 @@ describe ('Quantities', function () { const edgeLength = OV.CoordDistance3D (new OV.Coord3D (1.0, 1.0, 1.0), new OV.Coord3D (-1.0, -1.0, 1.0)); const mesh = GetTetrahedronMesh (); const model = GetModelWithOneMesh (mesh); - assert.ok (OV.IsSolid (mesh)); - assert.ok (OV.IsSolid (model)); + assert.ok (OV.IsTwoManifold (mesh)); + assert.ok (OV.IsTwoManifold (model)); assert.ok (OV.IsEqual (OV.CalculateVolume (mesh), Math.pow (edgeLength, 3.0) / (6.0 * Math.sqrt (2)))); assert.ok (OV.IsEqual (OV.CalculateVolume (model), Math.pow (edgeLength, 3.0) / (6.0 * Math.sqrt (2)))); }); @@ -98,8 +98,8 @@ describe ('Quantities', function () { const edgeLength = OV.CoordDistance3D (new OV.Coord3D (1.0, 1.0, 1.0), new OV.Coord3D (-1.0, -1.0, 1.0)); const mesh = GetTetrahedronMesh (); const model = GetModelWithOneMesh (mesh); - assert.ok (OV.IsSolid (mesh)); - assert.ok (OV.IsSolid (model)); + assert.ok (OV.IsTwoManifold (mesh)); + assert.ok (OV.IsTwoManifold (model)); assert.ok (OV.IsEqual (OV.CalculateSurfaceArea (mesh), Math.sqrt (3) * Math.pow (edgeLength, 2.0))); assert.ok (OV.IsEqual (OV.CalculateSurfaceArea (model), Math.sqrt (3) * Math.pow (edgeLength, 2.0))); }); @@ -110,7 +110,7 @@ describe ('Quantities', function () { let node = new OV.Node (); node.SetTransformation (transformation); const meshInstance = new OV.MeshInstance (null, node, mesh); - assert.ok (OV.IsSolid (meshInstance)); + assert.ok (OV.IsTwoManifold (meshInstance)); assert.ok (OV.IsEqual (OV.CalculateVolume (meshInstance), 8.0)); assert.ok (OV.IsEqual (OV.CalculateSurfaceArea (meshInstance), 24.0)); }); diff --git a/test/tests/topology_test.js b/test/tests/topology_test.js new file mode 100644 index 0000000..3e4f67e --- /dev/null +++ b/test/tests/topology_test.js @@ -0,0 +1,84 @@ +import * as assert from 'assert'; +import * as OV from '../../source/engine/main.js'; +import { GetModelWithOneMesh, GetTetrahedronMesh, GetTwoCubesConnectingInOneEdgeModel, GetTwoCubesConnectingInOneFaceModel, GetTwoCubesConnectingInOneVertexModel } from '../utils/testutils.js'; + +export default function suite () +{ + +describe ('Topology', function () { + it ('Tetrahedron Topology Calculation', function () { + let tetrahedron = GetModelWithOneMesh (GetTetrahedronMesh ()); + let topology = OV.GetTopology (tetrahedron); + assert.ok (OV.IsTwoManifold (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 = GetModelWithOneMesh (OV.GenerateCuboid (null, 1.0, 1.0, 1.0)); + assert.ok (OV.IsTwoManifold (cube)); + + let topology = OV.GetTopology (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); + } + }); + + it ('Two Cubes Connecting in One Vertex Topology Calculation', function () { + const model = GetTwoCubesConnectingInOneVertexModel (); + let topology = OV.GetTopology (model); + assert.strictEqual (topology.vertices.length, 15); + assert.ok (OV.IsTwoManifold (model)); + }); + + it ('Two Cubes Connecting in One Edge Topology Calculation', function () { + const model = GetTwoCubesConnectingInOneEdgeModel (); + let topology = OV.GetTopology (model); + assert.strictEqual (topology.vertices.length, 14); + assert.ok (OV.IsTwoManifold (model)); + }); + + it ('Two Cubes Connecting in One Face Topology Calculation', function () { + const model = GetTwoCubesConnectingInOneFaceModel (); + let topology = OV.GetTopology (model); + assert.strictEqual (topology.vertices.length, 12); + assert.ok (OV.IsTwoManifold (model)); + }); +}); + +}