From c1a9cae13feedca64613d70d3a29959c63d10186 Mon Sep 17 00:00:00 2001 From: kovacsv Date: Sat, 24 Jul 2021 09:58:21 +0200 Subject: [PATCH] Add sphere generator. --- source/import/importero3dv.js | 8 ++ source/model/generator.js | 89 +++++++++++++++++-- test/testfiles/o3dv/cube_with_material.o3dv | 20 ----- test/testfiles/o3dv/cylinder_non_smooth.o3dv | 13 --- test/testfiles/o3dv/cylinder_segments.o3dv | 12 --- test/testfiles/o3dv/cylinder_types.o3dv | 45 ++++++++++ test/testfiles/o3dv/sphere.o3dv | 10 +++ test/testfiles/o3dv/sphere_types.o3dv | 41 +++++++++ ...ransformation.o3dv => transformation.o3dv} | 0 test/tests/generator_test.js | 10 ++- test/tests/importero3dv_test.js | 58 +----------- 11 files changed, 196 insertions(+), 110 deletions(-) delete mode 100644 test/testfiles/o3dv/cube_with_material.o3dv delete mode 100644 test/testfiles/o3dv/cylinder_non_smooth.o3dv delete mode 100644 test/testfiles/o3dv/cylinder_segments.o3dv create mode 100644 test/testfiles/o3dv/cylinder_types.o3dv create mode 100644 test/testfiles/o3dv/sphere.o3dv create mode 100644 test/testfiles/o3dv/sphere_types.o3dv rename test/testfiles/o3dv/{cube_transformation.o3dv => transformation.o3dv} (100%) diff --git a/source/import/importero3dv.js b/source/import/importero3dv.js index 6426cdc..704d530 100644 --- a/source/import/importero3dv.js +++ b/source/import/importero3dv.js @@ -107,6 +107,14 @@ OV.ImporterO3dv = class extends OV.ImporterBase let smooth = OV.ValueOrDefault (parameters.smooth, true); const mesh = OV.GenerateCylinder (genParams, parameters.radius, parameters.height, segments, smooth); this.model.AddMesh (mesh); + } else if (meshContent.type === 'sphere') { + if (parameters.radius === undefined) { + return; + } + let segments = OV.ValueOrDefault (parameters.segments, 20); + let smooth = OV.ValueOrDefault (parameters.smooth, true); + const mesh = OV.GenerateSphere (genParams, parameters.radius, segments, smooth); + this.model.AddMesh (mesh); } } }; diff --git a/source/model/generator.js b/source/model/generator.js index b9cb850..db1843d 100644 --- a/source/model/generator.js +++ b/source/model/generator.js @@ -58,6 +58,16 @@ OV.Generator = class return this.mesh.AddVertex (coord); } + AddVertices (vertices) + { + let indices = []; + for (let i = 0; i < vertices.length; i++) { + let vertex = vertices[i]; + indices.push (this.AddVertex (vertex.x, vertex.y, vertex.z)); + } + return indices; + } + SetCurve (curve) { this.curve = curve; @@ -115,7 +125,7 @@ OV.GeneratorHelper = class this.generator = generator; } - GenerateExtrude (vertices, height, smooth) + GenerateExtrude (vertices, height, curve) { let topPolygon = []; let bottomPolygon = []; @@ -124,12 +134,9 @@ OV.GeneratorHelper = class bottomPolygon.push (this.generator.AddVertex (vertex.x, vertex.y, 0.0)); topPolygon.push (this.generator.AddVertex (vertex.x, vertex.y, height)); } - if (smooth) { - this.generator.SetCurve (1); - } - this.GenerateSurfaceBetweenPolygons (bottomPolygon, topPolygon, smooth); + this.generator.SetCurve (curve); + this.GenerateSurfaceBetweenPolygons (bottomPolygon, topPolygon); this.generator.ResetCurve (); - this.generator.AddConvexPolygonInverted (bottomPolygon); this.generator.AddConvexPolygon (topPolygon); } @@ -151,6 +158,20 @@ OV.GeneratorHelper = class ]); } } + + GenerateTriangleFan (startIndices, endIndex) + { + const vertexCount = startIndices.length; + for (let i = 0; i < vertexCount; i++) { + const index = i; + const nextIndex = (i < vertexCount - 1) ? index + 1 : 0; + this.generator.AddTriangle ( + endIndex, + startIndices[index], + startIndices[nextIndex] + ); + } + } }; OV.GenerateCuboid = function (genParams, xSize, ySize, zSize) @@ -163,7 +184,7 @@ OV.GenerateCuboid = function (genParams, xSize, ySize, zSize) new OV.Coord2D (0.0, ySize), ]; let helper = new OV.GeneratorHelper (generator); - helper.GenerateExtrude (vertices, zSize, false); + helper.GenerateExtrude (vertices, zSize, null); return generator.GetMesh (); }; @@ -177,6 +198,10 @@ OV.GenerateCylinder = function (genParams, radius, height, segments, smooth) ); } + if (segments < 3) { + return null; + } + let generator = new OV.Generator (genParams); let baseVertices = []; const step = 2.0 * Math.PI / segments; @@ -185,6 +210,54 @@ OV.GenerateCylinder = function (genParams, radius, height, segments, smooth) baseVertices.push (cylindrical); } let helper = new OV.GeneratorHelper (generator); - helper.GenerateExtrude (baseVertices, height, smooth); + helper.GenerateExtrude (baseVertices, height, smooth ? 1 : null); + return generator.GetMesh (); +}; + +OV.GenerateSphere = function (genParams, radius, segments, smooth) +{ + function GetSphericalCoord (radius, theta, phi) + { + return new OV.Coord3D ( + radius * Math.sin (theta) * Math.cos (phi), + radius * Math.sin (theta) * Math.sin (phi), + radius * Math.cos (theta) + ); + } + + if (segments < 3) { + return null; + } + + let generator = new OV.Generator (genParams); + let helper = new OV.GeneratorHelper (generator); + + generator.SetCurve (smooth ? 1 : null); + + let allLevelVertices = []; + let levels = segments + 1; + const levelStep = Math.PI / segments; + const cylindricalStep = 2.0 * Math.PI / segments; + for (let levelIndex = 1; levelIndex < levels - 1; levelIndex++) { + let levelVertices = []; + let theta = levelIndex * levelStep; + for (let cylindricalIndex = 0; cylindricalIndex < segments; cylindricalIndex++) { + let phi = cylindricalIndex * cylindricalStep; + let vertex = GetSphericalCoord (radius, theta, -phi); + levelVertices.push (generator.AddVertex (vertex.x, vertex.y, vertex.z)); + } + if (levelIndex > 1) { + helper.GenerateSurfaceBetweenPolygons (allLevelVertices[allLevelVertices.length - 1], levelVertices); + } + allLevelVertices.push (levelVertices); + } + + let topVertex = generator.AddVertex (0.0, 0.0, radius); + let bottomVertex = generator.AddVertex (0.0, 0.0, -radius); + helper.GenerateTriangleFan (allLevelVertices[0].slice ().reverse (), topVertex); + helper.GenerateTriangleFan (allLevelVertices[allLevelVertices.length - 1], bottomVertex); + + generator.ResetCurve (); + return generator.GetMesh (); }; diff --git a/test/testfiles/o3dv/cube_with_material.o3dv b/test/testfiles/o3dv/cube_with_material.o3dv deleted file mode 100644 index 86da30d..0000000 --- a/test/testfiles/o3dv/cube_with_material.o3dv +++ /dev/null @@ -1,20 +0,0 @@ -{ - "materials" : [ - { - "name" : "Material", - "color" : [200, 0, 0] - } - ], - "meshes" : [ - { - "name" : "Cube", - "material" : 0, - "type" : "cuboid", - "parameters" : { - "size_x" : 1.0, - "size_y" : 1.0, - "size_z" : 1.0 - } - } - ] -} diff --git a/test/testfiles/o3dv/cylinder_non_smooth.o3dv b/test/testfiles/o3dv/cylinder_non_smooth.o3dv deleted file mode 100644 index d7b3d24..0000000 --- a/test/testfiles/o3dv/cylinder_non_smooth.o3dv +++ /dev/null @@ -1,13 +0,0 @@ -{ - "meshes" : [ - { - "type" : "cylinder", - "parameters" : { - "radius" : 0.5, - "height" : 1.0, - "segments" : 20, - "smooth" : false - } - } - ] -} diff --git a/test/testfiles/o3dv/cylinder_segments.o3dv b/test/testfiles/o3dv/cylinder_segments.o3dv deleted file mode 100644 index 57c70a2..0000000 --- a/test/testfiles/o3dv/cylinder_segments.o3dv +++ /dev/null @@ -1,12 +0,0 @@ -{ - "meshes" : [ - { - "type" : "cylinder", - "parameters" : { - "radius" : 0.5, - "height" : 1.0, - "segments" : 50 - } - } - ] -} diff --git a/test/testfiles/o3dv/cylinder_types.o3dv b/test/testfiles/o3dv/cylinder_types.o3dv new file mode 100644 index 0000000..2e9af7f --- /dev/null +++ b/test/testfiles/o3dv/cylinder_types.o3dv @@ -0,0 +1,45 @@ +{ + "meshes" : [ + { + "type" : "cylinder", + "parameters" : { + "radius" : 0.5, + "height" : 1.0 + } + }, + { + "type" : "cylinder", + "parameters" : { + "radius" : 0.8, + "height" : 1.2 + }, + "transformation" : { + "translation" : [2.0, 0.0, 0.0] + } + }, + { + "type" : "cylinder", + "parameters" : { + "radius" : 0.5, + "height" : 1.0, + "smooth" : false, + "segments" : 5 + }, + "transformation" : { + "translation" : [2.0, 2.0, 0.0] + } + }, + { + "type" : "cylinder", + "parameters" : { + "radius" : 0.5, + "height" : 1.0, + "smooth" : false, + "segments" : 10 + }, + "transformation" : { + "translation" : [0.0, 2.0, 0.0] + } + } + ] +} diff --git a/test/testfiles/o3dv/sphere.o3dv b/test/testfiles/o3dv/sphere.o3dv new file mode 100644 index 0000000..a47f2bb --- /dev/null +++ b/test/testfiles/o3dv/sphere.o3dv @@ -0,0 +1,10 @@ +{ + "meshes" : [ + { + "type" : "sphere", + "parameters" : { + "radius" : 0.5 + } + } + ] +} diff --git a/test/testfiles/o3dv/sphere_types.o3dv b/test/testfiles/o3dv/sphere_types.o3dv new file mode 100644 index 0000000..c7aaa17 --- /dev/null +++ b/test/testfiles/o3dv/sphere_types.o3dv @@ -0,0 +1,41 @@ +{ + "meshes" : [ + { + "type" : "sphere", + "parameters" : { + "radius" : 0.5 + } + }, + { + "type" : "sphere", + "parameters" : { + "radius" : 0.8 + }, + "transformation" : { + "translation" : [2.0, 0.0, 0.0] + } + }, + { + "type" : "sphere", + "parameters" : { + "radius" : 0.5, + "smooth" : false, + "segments" : 5 + }, + "transformation" : { + "translation" : [2.0, 2.0, 0.0] + } + }, + { + "type" : "sphere", + "parameters" : { + "radius" : 0.5, + "smooth" : false, + "segments" : 10 + }, + "transformation" : { + "translation" : [0.0, 2.0, 0.0] + } + } + ] +} diff --git a/test/testfiles/o3dv/cube_transformation.o3dv b/test/testfiles/o3dv/transformation.o3dv similarity index 100% rename from test/testfiles/o3dv/cube_transformation.o3dv rename to test/testfiles/o3dv/transformation.o3dv diff --git a/test/tests/generator_test.js b/test/tests/generator_test.js index eb090c6..135547d 100644 --- a/test/tests/generator_test.js +++ b/test/tests/generator_test.js @@ -29,8 +29,14 @@ describe ('Generator', function () { }); it ('Cylinder with Default Parameters', function () { - const cylinder = OV.GenerateCylinder (null, 0.5, 1.0, 10, false); + const cylinder = OV.GenerateCylinder (null, 0.5, 1.0, 25, false); assert (OV.IsSolid (cylinder)); assert (OV.IsEqualEps (OV.CalculateVolume (cylinder), Math.PI * 0.5 * 0.5 * 1.0, 0.1)); - }); + }); + + it ('Sphere with Default Parameters', function () { + const cylinder = OV.GenerateSphere (null, 0.5, 20, false); + assert (OV.IsSolid (cylinder)); + assert (OV.IsEqualEps (OV.CalculateVolume (cylinder), Math.PI * 0.5 * 0.5 * 0.5 * 4.0 / 3.0, 0.1)); + }); }); diff --git a/test/tests/importero3dv_test.js b/test/tests/importero3dv_test.js index 6cc20d7..32ea001 100644 --- a/test/tests/importero3dv_test.js +++ b/test/tests/importero3dv_test.js @@ -29,34 +29,8 @@ describe ('O3dv Importer', function () { }); }); - it ('cube_with_material.o3dv', function (done) { - testFiles.ImportO3dvFile ('cube_with_material.o3dv', function (model) { - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : 'Material' } - ], - meshes : [ - { - name : 'Cube', - vertexCount : 8, - normalCount : 12, - uvCount : 0, - triangleCount : 12, - boundingBox : { - min : [0, 0, 0], - max : [1, 1, 1] - } - } - ] - }); - done (); - }); - }); - - it ('cube_transformation.o3dv', function (done) { - testFiles.ImportO3dvFile ('cube_transformation.o3dv', function (model) { + it ('transformation.o3dv', function (done) { + testFiles.ImportO3dvFile ('transformation.o3dv', function (model) { assert (OV.CheckModel (model)); assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { name : '', @@ -141,31 +115,5 @@ describe ('O3dv Importer', function () { }); done (); }); - }); - - it ('cylinder_non_smooth.o3dv', function (done) { - testFiles.ImportO3dvFile ('cylinder_non_smooth.o3dv', function (model) { - assert (OV.CheckModel (model)); - assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), { - name : '', - materials : [ - { name : '' } - ], - meshes : [ - { - name : '', - vertexCount : 40, - normalCount : 76, - uvCount : 0, - triangleCount : 76, - boundingBox : { - min : [-0.5, -0.5, 0], - max : [0.5, 0.5, 1] - } - } - ] - }); - done (); - }); - }); + }); });