UNPKG

angular-3d-viewer

Version:
434 lines (391 loc) 14.3 kB
import { Coord2D } from '../geometry/coord2d.js'; import { Coord3D } from '../geometry/coord3d.js'; import { IsPositive, IsNegative, IsZero } from '../geometry/geometry.js'; import { Mesh } from './mesh.js'; import { Triangle } from './triangle.js'; export class GeneratorParams { constructor () { this.name = null; this.material = null; } SetName (name) { this.name = name; return this; } SetMaterial (material) { this.material = material; return this; } } export class Generator { constructor (params) { this.params = params || new GeneratorParams (); this.mesh = new Mesh (); if (this.params.name !== null) { this.mesh.SetName (this.params.name); } this.curve = null; } GetMesh () { return this.mesh; } AddVertex (x, y, z) { let coord = new Coord3D (x, y, z); 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; } ResetCurve () { this.curve = null; } AddTriangle (v0, v1, v2) { let triangle = new Triangle (v0, v1, v2); if (this.params.material !== null) { triangle.mat = this.params.material; } if (this.curve !== null) { triangle.SetCurve (this.curve); } return this.mesh.AddTriangle (triangle); } AddTriangleInverted (v0, v1, v2) { this.AddTriangle (v0, v2, v1); } AddConvexPolygon (vertices) { for (let vertexIndex = 0; vertexIndex < vertices.length - 2; vertexIndex++) { this.AddTriangle ( vertices[0], vertices[vertexIndex + 1], vertices[vertexIndex + 2] ); } } AddConvexPolygonInverted (vertices) { for (let vertexIndex = 0; vertexIndex < vertices.length - 2; vertexIndex++) { this.AddTriangleInverted ( vertices[0], vertices[vertexIndex + 1], vertices[vertexIndex + 2] ); } } } export class GeneratorHelper { constructor (generator) { this.generator = generator; } GenerateSurfaceBetweenPolygons (startIndices, endIndices) { if (startIndices.length !== endIndices.length) { return; } const vertexCount = startIndices.length; for (let i = 0; i < vertexCount; i++) { const index = i; const nextIndex = (i < vertexCount - 1) ? index + 1 : 0; this.generator.AddConvexPolygon ([ startIndices[index], startIndices[nextIndex], endIndices[nextIndex], endIndices[index] ]); } } 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] ); } } } function GetCylindricalCoord (radius, angle) { return new Coord2D ( radius * Math.cos (angle), radius * Math.sin (angle) ); } export function GenerateCuboid (genParams, xSize, ySize, zSize) { if (!IsPositive (xSize) || !IsPositive (ySize) || !IsPositive (zSize)) { return null; } let generator = new Generator (genParams); generator.AddVertex (0.0, 0.0, 0.0); generator.AddVertex (xSize, 0.0, 0.0); generator.AddVertex (xSize, ySize, 0.0); generator.AddVertex (0.0, ySize, 0.0); generator.AddVertex (0.0, 0.0, zSize); generator.AddVertex (xSize, 0.0, zSize); generator.AddVertex (xSize, ySize, zSize); generator.AddVertex (0.0, ySize, zSize); generator.AddConvexPolygon ([0, 3, 2, 1]); generator.AddConvexPolygon ([0, 1, 5, 4]); generator.AddConvexPolygon ([1, 2, 6, 5]); generator.AddConvexPolygon ([2, 3, 7, 6]); generator.AddConvexPolygon ([3, 0, 4, 7]); generator.AddConvexPolygon ([4, 5, 6, 7]); return generator.GetMesh (); } export function GenerateCone (genParams, topRadius, bottomRadius, height, segments, smooth) { if (IsNegative (topRadius) || IsNegative (bottomRadius)) { return null; } if (!IsPositive (height) || segments < 3) { return null; } let isZeroTop = IsZero (topRadius); let isZeroBottom = IsZero (bottomRadius); if (isZeroTop && isZeroBottom) { return null; } let generator = new Generator (genParams); let helper = new GeneratorHelper (generator); const step = 2.0 * Math.PI / segments; const curve = (smooth ? 1 : null); let topPolygon = []; if (isZeroTop) { topPolygon.push (generator.AddVertex (0.0, 0.0, height)); } else { for (let i = 0; i < segments; i++) { let topVertex = GetCylindricalCoord (topRadius, i * step); topPolygon.push (generator.AddVertex (topVertex.x, topVertex.y, height)); } } let bottomPolygon = []; if (isZeroBottom) { bottomPolygon.push (generator.AddVertex (0.0, 0.0, 0.0)); } else { for (let i = 0; i < segments; i++) { let bottomVertex = GetCylindricalCoord (bottomRadius, i * step); bottomPolygon.push (generator.AddVertex (bottomVertex.x, bottomVertex.y, 0.0)); } } if (isZeroTop) { generator.SetCurve (curve); helper.GenerateTriangleFan (bottomPolygon, topPolygon[0]); generator.ResetCurve (); generator.AddConvexPolygonInverted (bottomPolygon); } else if (isZeroBottom) { generator.SetCurve (curve); helper.GenerateTriangleFan (topPolygon.slice ().reverse (), bottomPolygon[0]); generator.ResetCurve (); generator.AddConvexPolygon (topPolygon); } else { generator.SetCurve (curve); helper.GenerateSurfaceBetweenPolygons (bottomPolygon, topPolygon); generator.ResetCurve (); generator.AddConvexPolygonInverted (bottomPolygon); generator.AddConvexPolygon (topPolygon); } return generator.GetMesh (); } export function GenerateCylinder (genParams, radius, height, segments, smooth) { return GenerateCone (genParams, radius, radius, height, segments, smooth); } export function GenerateSphere (genParams, radius, segments, smooth) { function GetSphericalCoord (radius, theta, phi) { return new Coord3D ( radius * Math.sin (theta) * Math.cos (phi), radius * Math.sin (theta) * Math.sin (phi), radius * Math.cos (theta) ); } if (!IsPositive (radius) || segments < 3) { return null; } let generator = new Generator (genParams); let helper = new 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 (); } export function GeneratePlatonicSolid (genParams, type, radius) { function AddVertex (generator, radius, x, y, z) { let vertex = new Coord3D (x, y, z); vertex.MultiplyScalar (radius / vertex.Length ()); generator.AddVertex (vertex.x, vertex.y, vertex.z); } if (!IsPositive (radius)) { return null; } let generator = new Generator (genParams); if (type === 'tetrahedron') { let a = 1.0; AddVertex (generator, radius, +a, +a, +a); AddVertex (generator, radius, -a, -a, +a); AddVertex (generator, radius, -a, +a, -a); AddVertex (generator, radius, +a, -a, -a); generator.AddTriangle (0, 1, 3); generator.AddTriangle (0, 2, 1); generator.AddTriangle (0, 3, 2); generator.AddTriangle (1, 2, 3); } else if (type === 'hexahedron') { let a = 1.0; AddVertex (generator, radius, +a, +a, +a); AddVertex (generator, radius, +a, +a, -a); AddVertex (generator, radius, +a, -a, +a); AddVertex (generator, radius, +a, -a, -a); AddVertex (generator, radius, -a, +a, +a); AddVertex (generator, radius, -a, +a, -a); AddVertex (generator, radius, -a, -a, +a); AddVertex (generator, radius, -a, -a, -a); generator.AddConvexPolygon ([0, 1, 5, 4]); generator.AddConvexPolygon ([0, 2, 3, 1]); generator.AddConvexPolygon ([0, 4, 6, 2]); generator.AddConvexPolygon ([1, 3, 7, 5]); generator.AddConvexPolygon ([2, 6, 7, 3]); generator.AddConvexPolygon ([4, 5, 7, 6]); } else if (type === 'octahedron') { let a = 1.0; let b = 0.0; AddVertex (generator, radius, +a, +b, +b); AddVertex (generator, radius, -a, +b, +b); AddVertex (generator, radius, +b, +a, +b); AddVertex (generator, radius, +b, -a, +b); AddVertex (generator, radius, +b, +b, +a); AddVertex (generator, radius, +b, +b, -a); generator.AddTriangle (0, 2, 4); generator.AddTriangle (0, 3, 5); generator.AddTriangle (0, 4, 3); generator.AddTriangle (0, 5, 2); generator.AddTriangle (1, 2, 5); generator.AddTriangle (1, 3, 4); generator.AddTriangle (1, 4, 2); generator.AddTriangle (1, 5, 3); } else if (type === 'dodecahedron') { let a = 1.0; let b = 0.0; let c = (1.0 + Math.sqrt (5.0)) / 2.0; let d = 1.0 / c; AddVertex (generator, radius, +a, +a, +a); AddVertex (generator, radius, +a, +a, -a); AddVertex (generator, radius, +a, -a, +a); AddVertex (generator, radius, -a, +a, +a); AddVertex (generator, radius, +a, -a, -a); AddVertex (generator, radius, -a, +a, -a); AddVertex (generator, radius, -a, -a, +a); AddVertex (generator, radius, -a, -a, -a); AddVertex (generator, radius, +b, +d, +c); AddVertex (generator, radius, +b, +d, -c); AddVertex (generator, radius, +b, -d, +c); AddVertex (generator, radius, +b, -d, -c); AddVertex (generator, radius, +d, +c, +b); AddVertex (generator, radius, +d, -c, +b); AddVertex (generator, radius, -d, +c, +b); AddVertex (generator, radius, -d, -c, +b); AddVertex (generator, radius, +c, +b, +d); AddVertex (generator, radius, -c, +b, +d); AddVertex (generator, radius, +c, +b, -d); AddVertex (generator, radius, -c, +b, -d); generator.AddConvexPolygon ([0, 8, 10, 2, 16]); generator.AddConvexPolygon ([0, 16, 18, 1, 12]); generator.AddConvexPolygon ([0, 12, 14, 3, 8]); generator.AddConvexPolygon ([1, 9, 5, 14, 12]); generator.AddConvexPolygon ([1, 18, 4, 11, 9]); generator.AddConvexPolygon ([2, 10, 6, 15, 13]); generator.AddConvexPolygon ([2, 13, 4, 18, 16]); generator.AddConvexPolygon ([3, 14, 5, 19, 17]); generator.AddConvexPolygon ([3, 17, 6, 10, 8]); generator.AddConvexPolygon ([4, 13, 15, 7, 11]); generator.AddConvexPolygon ([5, 9, 11, 7, 19]); generator.AddConvexPolygon ([6, 17, 19, 7, 15]); } else if (type === 'icosahedron') { let a = 1.0; let b = 0.0; let c = (1.0 + Math.sqrt (5.0)) / 2.0; AddVertex (generator, radius, +b, +a, +c); AddVertex (generator, radius, +b, +a, -c); AddVertex (generator, radius, +b, -a, +c); AddVertex (generator, radius, +b, -a, -c); AddVertex (generator, radius, +a, +c, +b); AddVertex (generator, radius, +a, -c, +b); AddVertex (generator, radius, -a, +c, +b); AddVertex (generator, radius, -a, -c, +b); AddVertex (generator, radius, +c, +b, +a); AddVertex (generator, radius, +c, +b, -a); AddVertex (generator, radius, -c, +b, +a); AddVertex (generator, radius, -c, +b, -a); generator.AddTriangle (0, 2, 8); generator.AddTriangle (0, 4, 6); generator.AddTriangle (0, 6, 10); generator.AddTriangle (0, 8, 4); generator.AddTriangle (0, 10, 2); generator.AddTriangle (1, 3, 11); generator.AddTriangle (1, 4, 9); generator.AddTriangle (1, 6, 4); generator.AddTriangle (1, 9, 3); generator.AddTriangle (1, 11, 6); generator.AddTriangle (2, 5, 8); generator.AddTriangle (2, 7, 5); generator.AddTriangle (2, 10, 7); generator.AddTriangle (3, 5, 7); generator.AddTriangle (3, 7, 11); generator.AddTriangle (3, 9, 5); generator.AddTriangle (4, 8, 9); generator.AddTriangle (5, 9, 8); generator.AddTriangle (6, 11, 10); generator.AddTriangle (7, 10, 11); } return generator.GetMesh (); }