From f46ae4b88bf78d9d48de2ba1c075aa949c75cafe Mon Sep 17 00:00:00 2001 From: kovacsv Date: Tue, 28 Dec 2021 09:18:29 +0100 Subject: [PATCH] Add transformation option for exporter model. --- package.json | 1 - source/export/exportermodel.js | 37 +++++++++++++++++++++++--------- source/model/meshinstance.js | 12 ++++++++++- source/viewer/domutils.js | 2 +- test/tests/exportermodel_test.js | 31 ++++++++++++++++++++++++++ website/o3dv/js/exportdialog.js | 21 +++++++++--------- 6 files changed, 81 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index cd8c0d7..23c08e4 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,6 @@ "single" ], "block-scoped-var": "error", - "no-loop-func": "error", "no-undef": "error", "no-extend-native": "error", "eqeqeq": "error", diff --git a/source/export/exportermodel.js b/source/export/exportermodel.js index 6f82779..18e466e 100644 --- a/source/export/exportermodel.js +++ b/source/export/exportermodel.js @@ -2,6 +2,7 @@ OV.ExporterSettings = class { constructor (settings) { + this.transformation = new OV.Transformation (); this.isMeshVisible = (meshInstanceId) => { return true; }; @@ -67,31 +68,47 @@ OV.ExporterModel = class EnumerateTransformedMeshes (onMesh) { this.EnumerateMeshInstances ((meshInstance) => { - const transformed = meshInstance.GetTransformedMesh (); + let transformation = meshInstance.GetTransformation (); + if (!this.settings.transformation.IsIdentity ()) { + transformation.Append (this.settings.transformation); + } + + let mesh = meshInstance.GetMesh (); + let transformed = OV.CloneMesh (mesh); + if (!transformation.IsIdentity ()) { + OV.TransformMesh (transformed, transformation); + } + onMesh (transformed); }); } EnumerateVerticesAndTriangles (callbacks) { - this.EnumerateMeshInstances ((meshInstance) => { - meshInstance.EnumerateVertices ((vertex) => { + let transformedMeshes = []; + this.EnumerateTransformedMeshes ((mesh) => { + transformedMeshes.push (mesh); + }); + + for (let mesh of transformedMeshes) { + mesh.EnumerateVertices ((vertex) => { callbacks.onVertex (vertex.x, vertex.y, vertex.z); }); - }); + } + let vertexOffset = 0; - this.EnumerateMeshInstances ((meshInstance) => { - meshInstance.EnumerateTriangleVertexIndices ((v0, v1, v2) => { + for (let mesh of transformedMeshes) { + mesh.EnumerateTriangleVertexIndices ((v0, v1, v2) => { callbacks.onTriangle (v0 + vertexOffset, v1 + vertexOffset, v2 + vertexOffset); }); - vertexOffset += meshInstance.VertexCount (); - }); + vertexOffset += mesh.VertexCount (); + } } EnumerateTrianglesWithNormals (onTriangle) { - this.EnumerateMeshInstances ((meshInstance) => { - meshInstance.EnumerateTriangleVertices ((v0, v1, v2) => { + this.EnumerateTransformedMeshes ((mesh) => { + mesh.EnumerateTriangleVertices ((v0, v1, v2) => { let normal = OV.CalculateTriangleNormal (v0, v1, v2); onTriangle (v0, v1, v2, normal); }); diff --git a/source/model/meshinstance.js b/source/model/meshinstance.js index 15a7f8b..a7a205c 100644 --- a/source/model/meshinstance.js +++ b/source/model/meshinstance.js @@ -32,6 +32,16 @@ OV.MeshInstance = class extends OV.ModelObject3D return this.id; } + GetTransformation () + { + return this.node.GetWorldTransformation (); + } + + GetMesh () + { + return this.mesh; + } + VertexCount () { return this.mesh.VertexCount (); @@ -103,7 +113,7 @@ OV.MeshInstance = class extends OV.ModelObject3D GetTransformedMesh () { let transformation = this.node.GetWorldTransformation (); - const transformed = OV.CloneMesh (this.mesh); + let transformed = OV.CloneMesh (this.mesh); OV.TransformMesh (transformed, transformation); return transformed; } diff --git a/source/viewer/domutils.js b/source/viewer/domutils.js index eaedf77..0b5a3b8 100644 --- a/source/viewer/domutils.js +++ b/source/viewer/domutils.js @@ -135,8 +135,8 @@ OV.AddCheckbox = function (parentElement, id, text, isChecked, onChange) label.setAttribute ('for', id); let check = OV.AddDomElement (label, 'input', 'ov_checkbox'); check.setAttribute ('type', 'checkbox'); - check.setAttribute ('checked', isChecked); check.setAttribute ('id', id); + check.checked = isChecked; OV.AddDomElement (label, 'span', null, text); if (onChange) { check.addEventListener ('change', onChange); diff --git a/test/tests/exportermodel_test.js b/test/tests/exportermodel_test.js index dca5275..bcb6f61 100644 --- a/test/tests/exportermodel_test.js +++ b/test/tests/exportermodel_test.js @@ -60,4 +60,35 @@ describe ('Exporter Model', function () { assert (OV.CoordIsEqual3D (boundingBox.min, new OV.Coord3D (0.0, 0.0, 0.0))); assert (OV.CoordIsEqual3D (boundingBox.max, new OV.Coord3D (2.0, 1.0, 1.0))); }); + + it ('Model transformation test', function () { + let rotation = OV.QuaternionFromAxisAngle (new OV.Coord3D (0.0, 1.0, 0.0), -Math.PI / 2.0); + + let model = CreateTestModel (); + let settings = new OV.ExporterSettings ({ + transformation : new OV.Transformation (new OV.Matrix ().CreateRotation (rotation.x, rotation.y, rotation.z, rotation.w)) + }); + let exporterModel = new OV.ExporterModel (model, settings); + assert.strictEqual (exporterModel.MeshInstanceCount (), 3); + let boundingBox = GetExporterModelBoundingBox (exporterModel); + assert (OV.CoordIsEqual3D (boundingBox.min, new OV.Coord3D (-1.0, 0.0, 0.0))); + assert (OV.CoordIsEqual3D (boundingBox.max, new OV.Coord3D (0.0, 1.0, 3.0))); + }); + + it ('Model filter and transformation test', function () { + let rotation = OV.QuaternionFromAxisAngle (new OV.Coord3D (0.0, 1.0, 0.0), -Math.PI / 2.0); + + let model = CreateTestModel (); + let settings = new OV.ExporterSettings ({ + transformation : new OV.Transformation (new OV.Matrix ().CreateRotation (rotation.x, rotation.y, rotation.z, rotation.w)), + isMeshVisible : (meshInstanceId) => { + return !meshInstanceId.IsEqual (new OV.MeshInstanceId (3, 2)); + } + }); + let exporterModel = new OV.ExporterModel (model, settings); + assert.strictEqual (exporterModel.MeshInstanceCount (), 2); + let boundingBox = GetExporterModelBoundingBox (exporterModel); + assert (OV.CoordIsEqual3D (boundingBox.min, new OV.Coord3D (-1.0, 0.0, 0.0))); + assert (OV.CoordIsEqual3D (boundingBox.max, new OV.Coord3D (0.0, 1.0, 2.0))); + }); }); diff --git a/website/o3dv/js/exportdialog.js b/website/o3dv/js/exportdialog.js index 0439a55..4b25f7a 100644 --- a/website/o3dv/js/exportdialog.js +++ b/website/o3dv/js/exportdialog.js @@ -52,6 +52,7 @@ OV.ModelExporterUI = class extends OV.ExporterUI { let visibleOnly = this.visibleOnlyCheckbox.checked; let settings = new OV.ExporterSettings ({ + transformation : new OV.Transformation (), isMeshVisible : (meshInstanceId) => { if (visibleOnly) { return callbacks.isMeshVisible (meshInstanceId); @@ -61,16 +62,16 @@ OV.ModelExporterUI = class extends OV.ExporterUI } }); - // TODO - // if (exporterModel.MeshInstanceCount () === 0) { - // let errorDialog = OV.ShowMessageDialog ( - // 'Export Failed', - // 'The model doesn\'t contain any meshes.', - // null - // ); - // callbacks.onDialog (errorDialog); - // return; - // } + let exporterModel = new OV.ExporterModel (model, settings); + if (exporterModel.MeshInstanceCount () === 0) { + let errorDialog = OV.ShowMessageDialog ( + 'Export Failed', + 'The model doesn\'t contain any meshes.', + null + ); + callbacks.onDialog (errorDialog); + return; + } let progressDialog = new OV.ProgressDialog (); progressDialog.Init ('Exporting Model');