diff --git a/base_models/test_split2_unchanged.stl b/base_models/test_split2_unchanged.stl new file mode 100644 index 0000000000000000000000000000000000000000..a5dce1f755bcf10486e3585c866f34a5832e5bab --- /dev/null +++ b/base_models/test_split2_unchanged.stl @@ -0,0 +1,58 @@ +solid base_models/test_split2_unchanged + facet normal 0. 0. -1. + outer loop + vertex 2. 0. 0. + vertex 1. -1. 0. + vertex 0.20000000000000001 -1. 0. + endloop + endfacet + facet normal 0. 0. 1. + outer loop + vertex 2. 0. 0. + vertex 0.20000000000000001 -1. 0. + vertex 0.5 -1. 0. + endloop + endfacet + facet normal -0.55470019622522915 0.83205029433784372 0. + outer loop + vertex 2. 0. 0. + vertex 0.5 -1. 0. + vertex 0.5 -1. 1. + endloop + endfacet + facet normal 0. -0.70710678118654746 -0.70710678118654746 + outer loop + vertex 2. 0. 0. + vertex 0.5 -1. 1. + vertex 0. -1. 1. + endloop + endfacet + facet normal -0.57735026918962584 0.57735026918962584 -0.57735026918962584 + outer loop + vertex 2. 0. 0. + vertex 1. -1. 0. + vertex 0. -1. 1. + endloop + endfacet + facet normal 0. 1. 0. + outer loop + vertex 1. -1. 0. + vertex 0.20000000000000001 -1. 0. + vertex 0. -1. 1. + endloop + endfacet + facet normal 0. -1. 0. + outer loop + vertex 0.20000000000000001 -1. 0. + vertex 0.5 -1. 1. + vertex 0. -1. 1. + endloop + endfacet + facet normal 0. -1. 0. + outer loop + vertex 0.20000000000000001 -1. 0. + vertex 0.5 -1. 0. + vertex 0.5 -1. 1. + endloop + endfacet +endsolid base_models/test_split2_unchanged \ No newline at end of file diff --git a/examples.gi b/examples.gi index 4fe9b97bfedfb2e6dca75322853801b6161557ee..0f359fb3e82df544a84a1d87154bbc7f39e0f4fc 100644 --- a/examples.gi +++ b/examples.gi @@ -1789,23 +1789,20 @@ InstallMethod( TestIntersections, [], function() local surf, verticesPositions, pRecord; - surf := SimplicialSurfaceByVerticesInFaces( [[4,5,6],[1,2,3],[4,6,7],[5,4,8],[5,6,9]] ); - verticesPositions :=[[ -1.0000000000, 0.0000000000, 0.0000000000 ], - [ 0.0000000000, 1.0000000000 , 0.0000000000 ], - [ 1.0000000000, 0.0000000000, 0.0000000000 ], - [ 0.0000000000, 0.300000000, -1.000000000 ], - [ 0.0000000000, 0.8000000000 , 0.0000000000 ], - [ 0.0000000000, 0.3000000000, 1.0000000000 ], - [ 0.0000000000, -1.0000000000 , 0.0000000000], - [ 0.0000000000, 1.0000000000, -1.000000000 ], - [ 0.0000000000, 1.000000000, 1.000000000 ], + surf := TriangularComplexByVerticesInFaces( [[1,2,6],[1,4,5]]); + verticesPositions :=[[ 2.0000000000, 0.0000000000, 0.0000000000 ], + [ 1.0000000000, -1.0000000000 , 0.0000000000 ], + [ 0.2000000000, -1.5000000000, 0.0000000000 ], + [ 0.3000000000, -1.500000000, 0.500000000 ], + [ 0.3000000000, -1.5000000000 , 1.0000000000 ], + [ -1.0000000000, -1.000000000, 1.0000000000 ], ]; pRecord := SetVertexCoordinates3D(surf, verticesPositions, rec()); - DrawSurfaceToSTL(surf,"test_split2",pRecord, true); + DrawSurfaceToSTL(surf,"test_split2",pRecord, false); end ); - +#Coords := [[[ 2.0000000000, 0.0000000000, 0.0000000000 ],[ 1.0000000000, -1.0000000000 , 0.0000000000 ],[ -1.0000000000, -1.000000000, 1.0000000000 ]],[[ 2.0000000000, 0.0000000000, 0.0000000000 ],[ 0.5000000000, -1.500000000, 0.000000000 ],[ 0.4000000000, -1.5000000000 , 1.0000000000 ]]]; InstallMethod( TestIntersections2, [], function() @@ -1827,6 +1824,7 @@ InstallMethod( TestIntersections2, end ); + InstallMethod( TestTriang2, [], function() diff --git a/htmls/3gs_files.g b/htmls/3gs_files.g new file mode 100644 index 0000000000000000000000000000000000000000..cce6de6a9a4202958b353ed911f4cbf429bc1161 --- /dev/null +++ b/htmls/3gs_files.g @@ -0,0 +1,73 @@ +#3_2 + +ico := Icosahedron(); + +Coord3_2:= [ + [ 0.9510565160, 0.0000000000, 0.0000000000 ], + [ 0.4253254040, 0.8506508085, 0.0000000000 ], + [ 0.4253254040, 0.2628655560, 0.8090169940 ], + [ -0.0449027976, -0.0277514551, 0.0854101965 ], + [ 0.4253254040, -0.6881909604, -0.4999999998 ], + [ 0.4253254040, -0.6881909604, 0.4999999998 ], + [ -0.4253254040, 0.6881909604, 0.4999999998 ], + [ -0.4253254040, 0.6881909604, -0.4999999998 ], + [ -0.4253254040, -0.2628655560, -0.8090169940 ], + [ -0.4253254040, -0.8506508085, 0.0000000000 ], + [ 0.0449027976, 0.0277514551, -0.0854101965 ], + [ -0.9510565160, 0.0000000000, 0.0000000000 ], + ]; +pRecord1 := SetVertexCoordinates3D(ico, Coord3_2, rec()); +DrawComplexToJavaScript(ico,"ico_32",pRecord1); + +# intersection example 1 +coordinates:=[[0.,0.,1.],[1.5,0.,1],[0.,2.,1.],[0.75,0.5,1.5],[0.75,0.5,0.5],[2,0.5,0.5]]; + +faces:=[ [ 1, 2, 3 ], [ 4, 5, 6 ]]; + +t:=TriangularComplexByVerticesInFaces(faces); +pRecord2 := SetVertexCoordinates3D(t, coordinates, rec()); + + + +DrawComplexToJavaScript(t,"Intersection",pRecord2); + +# intersection example 2 +coordinates:=[[0.,0.,1.],[1.,0.,1],[0.,2.,1.],[1.5,0,1],[0.5,1.,1]]; + +faces:=[ [ 1, 2, 3 ], [ 2, 4, 5]]; + +t:=TriangularComplexByVerticesInFaces(faces); +pRecord2 := SetVertexCoordinates3D(t, coordinates, rec()); + + +DrawComplexToJavaScript(t,"Intersection2",pRecord2); + + +# ramified example + +coordinates:=[[0.,-1.,0.],[0.,1.,0.],[0.5,1.,0.5],[0.5,1.,-0.5],[-0.5,1.,0.5],[-0.5,1.,-0.5]]; + +faces:=[ [ 1, 2, 3 ], [ 1, 2, 4], [ 1, 2, 5], [ 1, 2, 6]]; + +t:=TriangularComplexByVerticesInFaces(faces); +pRecord3 := SetVertexCoordinates3D(t, coordinates, rec()); +SetEdgeColour(t,1,0xFF0000,pRecord3); +pRecord3:=ActivateLineWidth(t, pRecord3); + + +DrawComplexToJavaScript(t,"ramified1",pRecord3); + +# unramified example + +coordinates:=[[0.,-1.,-0.1],[0.,1.,-0.1],[0.,-1.,0.1],[0.,1.,0.1],[0.5,1.,0.5],[0.5,1.,-0.5],[-0.5,1.,0.5],[-0.5,1.,-0.5]]; + +faces:=[ [ 3, 4, 5 ], [ 1, 2, 6], [ 3, 4, 7], [ 1, 2, 8]]; + +t:=TriangularComplexByVerticesInFaces(faces); +pRecord3 := SetVertexCoordinates3D(t, coordinates, rec()); +SetEdgeColour(t,1,"0xFF0000",pRecord3); +SetEdgeColour(t,6,"0xFF0000",pRecord3); +pRecord3:=ActivateLineWidth(t, pRecord3); + + +DrawComplexToJavaScript(t,"un_ramified1",pRecord3); diff --git a/htmls/Intersection.html b/htmls/Intersection.html new file mode 100644 index 0000000000000000000000000000000000000000..dddb0c07e8412ae92db8f1ffa0e0f488807ec9c1 --- /dev/null +++ b/htmls/Intersection.html @@ -0,0 +1,761 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>SimplicialSurface</title> + <style> + body { margin: 0; } + </style> + + + </head> + <body> + +<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> + + +<script type="importmap"> + { + "imports": { + "three": "https://unpkg.com/three@0.148.0/build/three.module.js", + "three/addons/": "https://unpkg.com/three@0.148.0/examples/jsm/", + "gui": "https://unpkg.com/dat.gui@0.7.9/build/dat.gui.module.js" + } + } +</script> + + +<script type="module"> + import * as THREE from 'three'; + import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + import { GUI } from 'gui'; + import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js'; + import { Line2 } from 'three/addons/lines/Line2.js'; + import { LineMaterial } from 'three/addons/lines/LineMaterial.js'; + import { LineGeometry } from 'three/addons/lines/LineGeometry.js'; + + //start scene and camera + const scene = new THREE.Scene(); + const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 100 ); + + const renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setSize( window.innerWidth, window.innerHeight ); + document.body.appendChild( renderer.domElement ); + + //Lights + const skyColor = 0xFFFFFF; + const skyIntensity = 0.3; + const skyLight = new THREE.AmbientLight(skyColor, skyIntensity); + scene.add(skyLight); + + const color = 0xFFFFFF; + const intensity = 1; + const light = new THREE.PointLight(color, intensity); + light.position.set(0, 3, -5); + scene.add(light); + + //create groups to add everything to + const meshRoot = new THREE.Group(); + const wireRoot = new THREE.Group(); + const vertexRoot = new THREE.Group(); + const vertexlabelRoot = new THREE.Group(); + const edgeRoot = new THREE.Group(); + const ringRoot = new THREE.Group(); + const normalsRoot = new THREE.Group(); + const normalMeshRoot = new THREE.Group(); + + //parameters for the controls on the top right + var guiParameters = new function() { + this.speedX = 0.0; + this.speedY = 0.0; + this.speedZ = 0.0; + this.transparency = 1; + this.edgeVisibility = false; + this.edgeWidth = 0.2; + + this.vertexVisibility = true; + this.vertexlabelVisibility = false; + this.vertexSize = 1; + this.planeX = 0.0; + this.minX = -1.5; + this.maxX = 1.5; + this.planeXactive = false; + this.planeY = 0.0; + this.minY = -1.5; + + this.maxY = 1.5; + this.planeYactive = false; + this.planeZ = 0.0; + this.minZ = -1.5; + this.maxZ = 1.5; + this.planeZactive = false; + this.normalsMaterial = false; + this.circleVisibility = false; + this.circleWidth = 0.005; + this.normalsVisibility = false; + this.normalsLength = 1; + } ; + + //generate the plane for intersections + const planeX = new THREE.Plane( new THREE.Vector3( -1, 0, 0 ), guiParameters.planeX ); + const planeY = new THREE.Plane( new THREE.Vector3( 0, -1, 0 ), guiParameters.planeY ); + const planeZ = new THREE.Plane( new THREE.Vector3( 0, 0, -1 ), guiParameters.planeZ ); + + // the array which ones are currently active + var activePlanes = []; + + //rederer for lables + const labelRenderer = new CSS2DRenderer(); + labelRenderer.setSize( window.innerWidth, window.innerHeight ); + labelRenderer.domElement.style.position = 'absolute'; + labelRenderer.domElement.style.top = '0px'; + document.body.appendChild( labelRenderer.domElement ); + + //controls for mouse + const controls = new OrbitControls( camera, labelRenderer.domElement ); + + //controls in the top right corner + var gui = new GUI(); + + const animationFolder = gui.addFolder("Animations"); + animationFolder.add(guiParameters, 'speedX', 0, 5); + animationFolder.add(guiParameters, 'speedY', 0, 5); + animationFolder.add(guiParameters, 'speedZ', 0, 5); + animationFolder.open(); + + const controlFolder = gui.addFolder("Controls"); + controlFolder.add(guiParameters, "transparency", 0, 1); + controlFolder.add(guiParameters, "edgeVisibility"); + var edgeWidthGUI = controlFolder.add(guiParameters, "edgeWidth", 0.01, 2); + controlFolder.add(guiParameters, "vertexVisibility"); + controlFolder.add(guiParameters, "vertexlabelVisibility"); + controlFolder.add(guiParameters, "vertexSize", 0.1, 3); + controlFolder.add(guiParameters, "normalsMaterial"); + controlFolder.add(guiParameters, "circleVisibility"); + controlFolder.add(guiParameters, "circleWidth", 0.0001, 0.1); + controlFolder.add(guiParameters, "normalsVisibility"); + controlFolder.add(guiParameters, "normalsLength", 0, 2); + controlFolder.open(); + + //generate a sphere geometry for the vertices + const sphereGeometry = new THREE.SphereGeometry( 0.02, 32, 16 ); + sphereGeometry.transparent = guiParameters.vertexVisibility; + + //functions for later calculations + + function calulateIncenter(A, B, C){ + //we follow the math and variable names from here: https://math.stackexchange.com/questions/740111/incenter-of-triangle-in-3d + var a = Math.sqrt((B[0]-C[0])**2 + (B[1]-C[1])**2 + (B[2]-C[2])**2); + var b = Math.sqrt((C[0]-A[0])**2 + (C[1]-A[1])**2 + (C[2]-A[2])**2); + var c = Math.sqrt((A[0]-B[0])**2 + (A[1]-B[1])**2 + (A[2]-B[2])**2); + + var res = []; + res[0] = a/(a+b+c)*A[0] + b/(a+b+c)*B[0] + c/(a+b+c)*C[0]; + res[1] = a/(a+b+c)*A[1] + b/(a+b+c)*B[1] + c/(a+b+c)*C[1]; + res[2] = a/(a+b+c)*A[2] + b/(a+b+c)*B[2] + c/(a+b+c)*C[2]; + + return res; + } + + function calulateInradius(A, B, C){ + var a = Math.sqrt((B[0]-C[0])**2 + (B[1]-C[1])**2 + (B[2]-C[2])**2); + var b = Math.sqrt((C[0]-A[0])**2 + (C[1]-A[1])**2 + (C[2]-A[2])**2); + var c = Math.sqrt((A[0]-B[0])**2 + (A[1]-B[1])**2 + (A[2]-B[2])**2); + + var s = (a+b+c)/2; + var inradius = Math.sqrt(((s-a)*(s-b)*(s-c)) / s ); + + return inradius; + } + + // --- start of generated output --- // + + // preperations for parameterized vertex coordinates + const vertexParametriziation = false; + // generate the faces color by color + const geometry1 = new THREE.BufferGeometry(); + function setVertices1(){ + var vertices1 = new Float32Array( [ + 0.,0.,1., + 1.5,0.,1, + 0.,2.,1., + + 0.75,0.5,1.5, + 0.75,0.5,0.5, + 2,0.5,0.5, + + ] ); + + return vertices1; + } + + geometry1.setAttribute( 'position', new THREE.BufferAttribute( setVertices1(), 3 ) ); + + // generate materials in the given color and normals material for the faces + + const materialNormal1 = new THREE.MeshNormalMaterial({ + flatShading: true, + }); + materialNormal1.transparent = true; + materialNormal1.side = THREE.DoubleSide; + + const material1 = new THREE.MeshPhongMaterial({ + color: 0x049EF4, + flatShading: true, + }); + material1.transparent = true; + material1.side = THREE.DoubleSide; + + // generate meshes for the faces from the materials with the vertex coordinates from before + + const mesh1 = new THREE.Mesh( geometry1, material1 ); + mesh1.castShadow = true; + mesh1.receiveShadow = true; + + meshRoot.add(mesh1); + + const meshNormal1 = new THREE.Mesh( geometry1, materialNormal1 ); + mesh1.castShadow = true; + mesh1.receiveShadow = true; + + normalMeshRoot.add(meshNormal1); + + // generate the edges grouped by color + controlFolder.remove(edgeWidthGUI); + + const edgeMaterial1 = new THREE.LineBasicMaterial( { + color: 0x000000, + linewidth: 3., + } ); + + function getEdges1(){ + const edges1 = new Float32Array( [ + 0.,0.,1., + 1.5,0.,1, + + 0.,0.,1., + 0.,2.,1., + + 1.5,0.,1, + 0.,2.,1., + + 0.75,0.5,1.5, + 0.75,0.5,0.5, + + 0.75,0.5,1.5, + 2,0.5,0.5, + + 0.75,0.5,0.5, + 2,0.5,0.5, + + ]); + return edges1; + } + + + // generate geometries and lines for the edges + + const edgeGeometry1 = new THREE.BufferGeometry(); + edgeGeometry1.setAttribute( 'position', new THREE.BufferAttribute( getEdges1(), 3 ) ); + + const edgeLine1 = new THREE.LineSegments( edgeGeometry1, edgeMaterial1 ); + edgeRoot.add(edgeLine1); + + // update function to be called every frame + // generate labels and spheres for the vertices + + + function getVertex1(){ + return [0.,0.,1.,]; + } + const sphereMaterial1 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere1 = new THREE.Mesh( sphereGeometry, sphereMaterial1 ); + vertexRoot.add(sphere1); + sphere1.position.set(getVertex1()[0],getVertex1()[1],getVertex1()[2]); + + const lableDiv1 = document.createElement( 'div' ); + lableDiv1.className = 'label'; + lableDiv1.textContent = '1'; + lableDiv1.style.marginTop = '-1em'; + + const vertexLabel1 = new CSS2DObject( lableDiv1 ); + vertexLabel1.position.set(getVertex1()[0],getVertex1()[1],getVertex1()[2]); + vertexlabelRoot.add( vertexLabel1 ); + + + + function getVertex2(){ + return [1.5,0.,1,]; + } + const sphereMaterial2 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere2 = new THREE.Mesh( sphereGeometry, sphereMaterial2 ); + vertexRoot.add(sphere2); + sphere2.position.set(getVertex2()[0],getVertex2()[1],getVertex2()[2]); + + const lableDiv2 = document.createElement( 'div' ); + lableDiv2.className = 'label'; + lableDiv2.textContent = '2'; + lableDiv2.style.marginTop = '-1em'; + + const vertexLabel2 = new CSS2DObject( lableDiv2 ); + vertexLabel2.position.set(getVertex2()[0],getVertex2()[1],getVertex2()[2]); + vertexlabelRoot.add( vertexLabel2 ); + + + + function getVertex3(){ + return [0.,2.,1.,]; + } + const sphereMaterial3 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere3 = new THREE.Mesh( sphereGeometry, sphereMaterial3 ); + vertexRoot.add(sphere3); + sphere3.position.set(getVertex3()[0],getVertex3()[1],getVertex3()[2]); + + const lableDiv3 = document.createElement( 'div' ); + lableDiv3.className = 'label'; + lableDiv3.textContent = '3'; + lableDiv3.style.marginTop = '-1em'; + + const vertexLabel3 = new CSS2DObject( lableDiv3 ); + vertexLabel3.position.set(getVertex3()[0],getVertex3()[1],getVertex3()[2]); + vertexlabelRoot.add( vertexLabel3 ); + + + + function getVertex4(){ + return [0.75,0.5,1.5,]; + } + const sphereMaterial4 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere4 = new THREE.Mesh( sphereGeometry, sphereMaterial4 ); + vertexRoot.add(sphere4); + sphere4.position.set(getVertex4()[0],getVertex4()[1],getVertex4()[2]); + + const lableDiv4 = document.createElement( 'div' ); + lableDiv4.className = 'label'; + lableDiv4.textContent = '4'; + lableDiv4.style.marginTop = '-1em'; + + const vertexLabel4 = new CSS2DObject( lableDiv4 ); + vertexLabel4.position.set(getVertex4()[0],getVertex4()[1],getVertex4()[2]); + vertexlabelRoot.add( vertexLabel4 ); + + + + function getVertex5(){ + return [0.75,0.5,0.5,]; + } + const sphereMaterial5 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere5 = new THREE.Mesh( sphereGeometry, sphereMaterial5 ); + vertexRoot.add(sphere5); + sphere5.position.set(getVertex5()[0],getVertex5()[1],getVertex5()[2]); + + const lableDiv5 = document.createElement( 'div' ); + lableDiv5.className = 'label'; + lableDiv5.textContent = '5'; + lableDiv5.style.marginTop = '-1em'; + + const vertexLabel5 = new CSS2DObject( lableDiv5 ); + vertexLabel5.position.set(getVertex5()[0],getVertex5()[1],getVertex5()[2]); + vertexlabelRoot.add( vertexLabel5 ); + + + + function getVertex6(){ + return [2,0.5,0.5,]; + } + const sphereMaterial6 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere6 = new THREE.Mesh( sphereGeometry, sphereMaterial6 ); + vertexRoot.add(sphere6); + sphere6.position.set(getVertex6()[0],getVertex6()[1],getVertex6()[2]); + + const lableDiv6 = document.createElement( 'div' ); + lableDiv6.className = 'label'; + lableDiv6.textContent = '6'; + lableDiv6.style.marginTop = '-1em'; + + const vertexLabel6 = new CSS2DObject( lableDiv6 ); + vertexLabel6.position.set(getVertex6()[0],getVertex6()[1],getVertex6()[2]); + vertexlabelRoot.add( vertexLabel6 ); + + // generate the rings for the incircles + + var inradius1 = calulateInradius(getVertex1(), getVertex2(), getVertex3()); + var incenter1 = calulateIncenter(getVertex1(), getVertex2(), getVertex3()); + var ringGeometry1 = new THREE.RingGeometry((inradius1 - 0.005),inradius1, 32); + const ringMaterial1 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh1 = new THREE.Mesh(ringGeometry1, ringMaterial1); + + function setCircleRotation1(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.,0.,1.],[ 1.5,0.,1],[0.,2.,1.]); + + ringMesh1.position.setX(incenter[0]); + ringMesh1.position.setY(incenter[1]); + ringMesh1.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex1(), getVertex2(), getVertex3()); + var relRadius = inradius/inradius1; + + ringMesh1.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A1 = new THREE.Vector3(0.,0.,1.); + const B1 = new THREE.Vector3(1.5,0.,1); + const C1 = new THREE.Vector3(0.,2.,1.); + + const normalVec1 = new THREE.Vector3(); + normalVec1.crossVectors(B1.sub(A1), C1.sub(A1)); + normalVec1.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal1 = new THREE.Vector3(0,0,1); + + const quaternionRotation1 = new THREE.Quaternion(); + quaternionRotation1.setFromUnitVectors(initialNormal1, normalVec1); + + ringMesh1.setRotationFromQuaternion(quaternionRotation1); + + return quaternionRotation1; + } + + ringRoot.add(ringMesh1); + + var inradius2 = calulateInradius(getVertex4(), getVertex5(), getVertex6()); + var incenter2 = calulateIncenter(getVertex4(), getVertex5(), getVertex6()); + var ringGeometry2 = new THREE.RingGeometry((inradius2 - 0.005),inradius2, 32); + const ringMaterial2 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh2 = new THREE.Mesh(ringGeometry2, ringMaterial2); + + function setCircleRotation2(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.75,0.5,1.5],[ 0.75,0.5,0.5],[2,0.5,0.5]); + + ringMesh2.position.setX(incenter[0]); + ringMesh2.position.setY(incenter[1]); + ringMesh2.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex4(), getVertex5(), getVertex6()); + var relRadius = inradius/inradius2; + + ringMesh2.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A2 = new THREE.Vector3(0.75,0.5,1.5); + const B2 = new THREE.Vector3(0.75,0.5,0.5); + const C2 = new THREE.Vector3(2,0.5,0.5); + + const normalVec2 = new THREE.Vector3(); + normalVec2.crossVectors(B2.sub(A2), C2.sub(A2)); + normalVec2.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal2 = new THREE.Vector3(0,0,1); + + const quaternionRotation2 = new THREE.Quaternion(); + quaternionRotation2.setFromUnitVectors(initialNormal2, normalVec2); + + ringMesh2.setRotationFromQuaternion(quaternionRotation2); + + return quaternionRotation2; + } + + ringRoot.add(ringMesh2); + // function to update the circles every frame + function updateCircles(){ + setCircleRotation1(); + setCircleRotation2(); + } + + // needs to be called once to be initialized + updateCircles(); + + // function to update the circles width, that is called every frame even if the surface is not parameterized + function updateCircleWidth(){ + ringGeometry1.dispose(); + ringGeometry1 = new THREE.RingGeometry((inradius1 - guiParameters.circleWidth),inradius1, 32); + ringMesh1.geometry = ringGeometry1; + ringGeometry2.dispose(); + ringGeometry2 = new THREE.RingGeometry((inradius2 - guiParameters.circleWidth),inradius2, 32); + ringMesh2.geometry = ringGeometry2; + } + + updateCircleWidth(); + + // generate the normals trough the incenter orthogonal to the face + // getNormalsVectors generates the coordinates for the current values of the parameterized surface + function getNormalsVectors(){ + var vector1; + var vector2; + + var normals = []; + vector1 = []; + vector2 = []; + vector1[0] = (1.5)-(0.); + vector1[1] = (0.)-(0.); + vector1[2] = (1)-(1.); + + vector2[0] = (0.)-(0.); + vector2[1] = (2.)-(0.); + vector2[2] = (1.)-(1.); + + var incenter = calulateIncenter([0.,0.,1.],[ 1.5,0.,1],[0.,2.,1.]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.75)-(0.75); + vector1[1] = (0.5)-(0.5); + vector1[2] = (0.5)-(1.5); + + vector2[0] = (2)-(0.75); + vector2[1] = (0.5)-(0.5); + vector2[2] = (0.5)-(1.5); + + var incenter = calulateIncenter([0.75,0.5,1.5],[ 0.75,0.5,0.5],[2,0.5,0.5]); + normals.push([vector1, vector2, incenter]); + + return normals; + } + // getNormalsCoordinates calculates the right coordinates for the ortogonality and fitting values from the gui + function getNormalsCoordinates(){ + var res = []; + var normals = getNormalsVectors(); + for(var i = 0; i < normals.length; i++){ + var plus = []; + var minus = []; + + minus[0] = normals[i][2][0] - (1/2)*guiParameters.normalsLength*(normals[i][0][1]*normals[i][1][2] - normals[i][0][2]*normals[i][1][1]); + minus[1] = normals[i][2][1] - (1/2)*guiParameters.normalsLength*(normals[i][0][2]*normals[i][1][0] - normals[i][0][0]*normals[i][1][2]); + minus[2] = normals[i][2][2] - (1/2)*guiParameters.normalsLength*(normals[i][0][0]*normals[i][1][1] - normals[i][0][1]*normals[i][1][0]); + + plus[0] = normals[i][2][0] + (1/2)*guiParameters.normalsLength*(normals[i][0][1]*normals[i][1][2] - normals[i][0][2]*normals[i][1][1]); + plus[1] = normals[i][2][1] + (1/2)*guiParameters.normalsLength*(normals[i][0][2]*normals[i][1][0] - normals[i][0][0]*normals[i][1][2]); + plus[2] = normals[i][2][2] + (1/2)*guiParameters.normalsLength*(normals[i][0][0]*normals[i][1][1] - normals[i][0][1]*normals[i][1][0]); + + res.push(minus[0]); + res.push(minus[1]); + res.push(minus[2]); + res.push(plus[0]); + res.push(plus[1]); + res.push(plus[2]); + } + res = Float32Array.from(res); + + + return res; + } + + + const normalsMaterial = new THREE.LineBasicMaterial( { + color: 0x000000, + } ); + + const normalsGeometry = new THREE.BufferGeometry(); + normalsGeometry.setAttribute( 'position', new THREE.BufferAttribute( getNormalsCoordinates(), 3 ) ); + var normalsLine = new THREE.LineSegments( normalsGeometry, normalsMaterial ); + + function updateNormals(){ + normalsGeometry.setAttribute( 'position', new THREE.BufferAttribute( getNormalsCoordinates(), 3 ) ); + normalsLine = new THREE.LineSegments( normalsGeometry, normalsMaterial ); + } + + normalsRoot.add(normalsLine); + + + // generate automatic ranges for the intersections if the surface is not parameterized + guiParameters.maxX = 2.; + guiParameters.maxY = 2.; + guiParameters.maxZ = 1.5; + guiParameters.minX = 0.; + guiParameters.minY = 0.; + guiParameters.minZ = 0.; + + guiParameters.planeX = 1.; + guiParameters.planeY = 1.; + guiParameters.planeZ = 0.75; + // --- end of generated output --- // + + const planeFolder = gui.addFolder("Intersection Planes"); + planeFolder.add(guiParameters, 'planeXactive'); + planeFolder.add(guiParameters, 'planeX', guiParameters.minX*1.1, guiParameters.maxX*1.1); + planeFolder.add(guiParameters, 'planeYactive'); + planeFolder.add(guiParameters, 'planeY', guiParameters.minY*1.1, guiParameters.maxY*1.1); + planeFolder.add(guiParameters, 'planeZactive'); + planeFolder.add(guiParameters, 'planeZ', guiParameters.minZ*1.1, guiParameters.maxZ*1.1); + + camera.position.z = Math.max((1.5)*guiParameters.minZ, 1) + camera.lookAt(0,0,-1); + + scene.background = new THREE.Color( 'white' ); + + // add both roots to the scene + scene.add( meshRoot ); + scene.add( wireRoot ); + scene.add( vertexRoot ); + scene.add( vertexlabelRoot ); + scene.add( edgeRoot ); + scene.add( ringRoot ); + scene.add( normalsRoot ); + scene.add( normalMeshRoot ); + + //presave some current gui parameters to only update if they change + var currentCircleWidth = guiParameters.circleWidth; + + function animate() { + requestAnimationFrame( animate ); + meshRoot.rotation.x += guiParameters.speedX/100; + meshRoot.rotation.y += guiParameters.speedY/100; + meshRoot.rotation.z += guiParameters.speedZ/100; + + wireRoot.rotation.x += guiParameters.speedX/100; + wireRoot.rotation.y += guiParameters.speedY/100; + wireRoot.rotation.z += guiParameters.speedZ/100; + + vertexRoot.rotation.x += guiParameters.speedX/100; + vertexRoot.rotation.y += guiParameters.speedY/100; + vertexRoot.rotation.z += guiParameters.speedZ/100; + + vertexlabelRoot.rotation.x += guiParameters.speedX/100; + vertexlabelRoot.rotation.y += guiParameters.speedY/100; + vertexlabelRoot.rotation.z += guiParameters.speedZ/100; + + edgeRoot.rotation.x += guiParameters.speedX/100; + edgeRoot.rotation.y += guiParameters.speedY/100; + edgeRoot.rotation.z += guiParameters.speedZ/100; + + ringRoot.rotation.x += guiParameters.speedX/100; + ringRoot.rotation.y += guiParameters.speedY/100; + ringRoot.rotation.z += guiParameters.speedZ/100; + + normalsRoot.rotation.x += guiParameters.speedX/100; + normalsRoot.rotation.y += guiParameters.speedY/100; + normalsRoot.rotation.z += guiParameters.speedZ/100; + + normalMeshRoot.rotation.x += guiParameters.speedX/100; + normalMeshRoot.rotation.y += guiParameters.speedY/100; + normalMeshRoot.rotation.z += guiParameters.speedZ/100; + + //update the light when the camera moves (with orbitcontrols) + light.position.set(camera.position.x, camera.position.y, camera.position.z); + + planeX.constant = guiParameters.planeX; + planeY.constant = guiParameters.planeY; + planeZ.constant = guiParameters.planeZ; + + activePlanes = []; + if(guiParameters.planeXactive){ + activePlanes.push(planeX); + } + if(guiParameters.planeYactive){ + activePlanes.push(planeY); + } + if(guiParameters.planeZactive){ + activePlanes.push(planeZ); + } + + if(vertexParametriziation){ + updateFaceCoordinates(); + if(guiParameters.edgeVisibility){ + updateEdgeCoordinates(); + } + if(guiParameters.vertexlabelVisibility || guiParameters.vertexVisibility){ + updateVertexCoordinates(); + } + if(guiParameters.circleVisibility){ + updateCircles(); + } + } + + //update stuff that changes from the gui + meshRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.opacity = guiParameters.transparency; + node.material.clippingPlanes = activePlanes; + if(guiParameters.normalsMaterial){ + node.material.opacity = 0; + } + } + } ); + + normalMeshRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.opacity = guiParameters.transparency; + node.material.clippingPlanes = activePlanes; + if(!guiParameters.normalsMaterial){ + node.material.opacity = 0; + } + } + } ); + + edgeRoot.traverse( function( node ) { + if ( node instanceof Line2 ) { + node.material.visible = guiParameters.edgeVisibility; + node.material.linewidth = guiParameters.edgeWidth/100; + } + if ( node instanceof THREE.LineSegments ) { + node.material.visible = guiParameters.edgeVisibility; + } + } ); + + vertexRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.visible = guiParameters.vertexVisibility; + node.scale.setScalar(guiParameters.vertexSize); + } + } ); + + vertexlabelRoot.traverse( function( node ) { + if( node instanceof CSS2DObject) { + node.visible = guiParameters.vertexlabelVisibility; + } + } ); + + ringRoot.traverse( function( node ) { + if( node instanceof THREE.Mesh) { + node.visible = guiParameters.circleVisibility; + } + } ); + + normalsRoot.traverse( function( node ) { + if( node instanceof THREE.LineSegments) { + node.visible = guiParameters.normalsVisibility; + } + } ); + + // update the circle width + if(guiParameters.circleVisibility && currentCircleWidth != guiParameters.circleWidth){ + updateCircleWidth(); + currentCircleWidth = guiParameters.circleWidth; + } + + //update the normals length + if(guiParameters.normalsVisibility){ + updateNormals(); + } + + controls.update(); + + renderer.localClippingEnabled = true; + + renderer.render( scene, camera ); + labelRenderer.render( scene, camera ); + } + animate(); + + //resize of window size changes + window.addEventListener( 'resize', onWindowResize ); + function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + labelRenderer.setSize( window.innerWidth, window.innerHeight ); + } +</script> + +</body> +</html> \ No newline at end of file diff --git a/htmls/Intersection2.html b/htmls/Intersection2.html new file mode 100644 index 0000000000000000000000000000000000000000..5ba3e2a2813feb3df8e9529117c1da0543bce8bf --- /dev/null +++ b/htmls/Intersection2.html @@ -0,0 +1,742 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>SimplicialSurface</title> + <style> + body { margin: 0; } + </style> + + + </head> + <body> + +<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> + + +<script type="importmap"> + { + "imports": { + "three": "https://unpkg.com/three@0.148.0/build/three.module.js", + "three/addons/": "https://unpkg.com/three@0.148.0/examples/jsm/", + "gui": "https://unpkg.com/dat.gui@0.7.9/build/dat.gui.module.js" + } + } +</script> + + +<script type="module"> + import * as THREE from 'three'; + import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + import { GUI } from 'gui'; + import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js'; + import { Line2 } from 'three/addons/lines/Line2.js'; + import { LineMaterial } from 'three/addons/lines/LineMaterial.js'; + import { LineGeometry } from 'three/addons/lines/LineGeometry.js'; + + //start scene and camera + const scene = new THREE.Scene(); + const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 100 ); + + const renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setSize( window.innerWidth, window.innerHeight ); + document.body.appendChild( renderer.domElement ); + + //Lights + const skyColor = 0xFFFFFF; + const skyIntensity = 0.3; + const skyLight = new THREE.AmbientLight(skyColor, skyIntensity); + scene.add(skyLight); + + const color = 0xFFFFFF; + const intensity = 1; + const light = new THREE.PointLight(color, intensity); + light.position.set(0, 3, -5); + scene.add(light); + + //create groups to add everything to + const meshRoot = new THREE.Group(); + const wireRoot = new THREE.Group(); + const vertexRoot = new THREE.Group(); + const vertexlabelRoot = new THREE.Group(); + const edgeRoot = new THREE.Group(); + const ringRoot = new THREE.Group(); + const normalsRoot = new THREE.Group(); + const normalMeshRoot = new THREE.Group(); + + //parameters for the controls on the top right + var guiParameters = new function() { + this.speedX = 0.0; + this.speedY = 0.0; + this.speedZ = 0.0; + this.transparency = 1; + this.edgeVisibility = false; + this.edgeWidth = 0.2; + + this.vertexVisibility = true; + this.vertexlabelVisibility = false; + this.vertexSize = 1; + this.planeX = 0.0; + this.minX = -1.5; + this.maxX = 1.5; + this.planeXactive = false; + this.planeY = 0.0; + this.minY = -1.5; + + this.maxY = 1.5; + this.planeYactive = false; + this.planeZ = 0.0; + this.minZ = -1.5; + this.maxZ = 1.5; + this.planeZactive = false; + this.normalsMaterial = false; + this.circleVisibility = false; + this.circleWidth = 0.005; + this.normalsVisibility = false; + this.normalsLength = 1; + } ; + + //generate the plane for intersections + const planeX = new THREE.Plane( new THREE.Vector3( -1, 0, 0 ), guiParameters.planeX ); + const planeY = new THREE.Plane( new THREE.Vector3( 0, -1, 0 ), guiParameters.planeY ); + const planeZ = new THREE.Plane( new THREE.Vector3( 0, 0, -1 ), guiParameters.planeZ ); + + // the array which ones are currently active + var activePlanes = []; + + //rederer for lables + const labelRenderer = new CSS2DRenderer(); + labelRenderer.setSize( window.innerWidth, window.innerHeight ); + labelRenderer.domElement.style.position = 'absolute'; + labelRenderer.domElement.style.top = '0px'; + document.body.appendChild( labelRenderer.domElement ); + + //controls for mouse + const controls = new OrbitControls( camera, labelRenderer.domElement ); + + //controls in the top right corner + var gui = new GUI(); + + const animationFolder = gui.addFolder("Animations"); + animationFolder.add(guiParameters, 'speedX', 0, 5); + animationFolder.add(guiParameters, 'speedY', 0, 5); + animationFolder.add(guiParameters, 'speedZ', 0, 5); + animationFolder.open(); + + const controlFolder = gui.addFolder("Controls"); + controlFolder.add(guiParameters, "transparency", 0, 1); + controlFolder.add(guiParameters, "edgeVisibility"); + var edgeWidthGUI = controlFolder.add(guiParameters, "edgeWidth", 0.01, 2); + controlFolder.add(guiParameters, "vertexVisibility"); + controlFolder.add(guiParameters, "vertexlabelVisibility"); + controlFolder.add(guiParameters, "vertexSize", 0.1, 3); + controlFolder.add(guiParameters, "normalsMaterial"); + controlFolder.add(guiParameters, "circleVisibility"); + controlFolder.add(guiParameters, "circleWidth", 0.0001, 0.1); + controlFolder.add(guiParameters, "normalsVisibility"); + controlFolder.add(guiParameters, "normalsLength", 0, 2); + controlFolder.open(); + + //generate a sphere geometry for the vertices + const sphereGeometry = new THREE.SphereGeometry( 0.02, 32, 16 ); + sphereGeometry.transparent = guiParameters.vertexVisibility; + + //functions for later calculations + + function calulateIncenter(A, B, C){ + //we follow the math and variable names from here: https://math.stackexchange.com/questions/740111/incenter-of-triangle-in-3d + var a = Math.sqrt((B[0]-C[0])**2 + (B[1]-C[1])**2 + (B[2]-C[2])**2); + var b = Math.sqrt((C[0]-A[0])**2 + (C[1]-A[1])**2 + (C[2]-A[2])**2); + var c = Math.sqrt((A[0]-B[0])**2 + (A[1]-B[1])**2 + (A[2]-B[2])**2); + + var res = []; + res[0] = a/(a+b+c)*A[0] + b/(a+b+c)*B[0] + c/(a+b+c)*C[0]; + res[1] = a/(a+b+c)*A[1] + b/(a+b+c)*B[1] + c/(a+b+c)*C[1]; + res[2] = a/(a+b+c)*A[2] + b/(a+b+c)*B[2] + c/(a+b+c)*C[2]; + + return res; + } + + function calulateInradius(A, B, C){ + var a = Math.sqrt((B[0]-C[0])**2 + (B[1]-C[1])**2 + (B[2]-C[2])**2); + var b = Math.sqrt((C[0]-A[0])**2 + (C[1]-A[1])**2 + (C[2]-A[2])**2); + var c = Math.sqrt((A[0]-B[0])**2 + (A[1]-B[1])**2 + (A[2]-B[2])**2); + + var s = (a+b+c)/2; + var inradius = Math.sqrt(((s-a)*(s-b)*(s-c)) / s ); + + return inradius; + } + + // --- start of generated output --- // + + // preperations for parameterized vertex coordinates + const vertexParametriziation = false; + // generate the faces color by color + const geometry1 = new THREE.BufferGeometry(); + function setVertices1(){ + var vertices1 = new Float32Array( [ + 0.,0.,1., + 1.,0.,1, + 0.,2.,1., + + 1.,0.,1, + 1.5,0,1, + 0.5,1.,1, + + ] ); + + return vertices1; + } + + geometry1.setAttribute( 'position', new THREE.BufferAttribute( setVertices1(), 3 ) ); + + // generate materials in the given color and normals material for the faces + + const materialNormal1 = new THREE.MeshNormalMaterial({ + flatShading: true, + }); + materialNormal1.transparent = true; + materialNormal1.side = THREE.DoubleSide; + + const material1 = new THREE.MeshPhongMaterial({ + color: 0x049EF4, + flatShading: true, + }); + material1.transparent = true; + material1.side = THREE.DoubleSide; + + // generate meshes for the faces from the materials with the vertex coordinates from before + + const mesh1 = new THREE.Mesh( geometry1, material1 ); + mesh1.castShadow = true; + mesh1.receiveShadow = true; + + meshRoot.add(mesh1); + + const meshNormal1 = new THREE.Mesh( geometry1, materialNormal1 ); + mesh1.castShadow = true; + mesh1.receiveShadow = true; + + normalMeshRoot.add(meshNormal1); + + // generate the edges grouped by color + controlFolder.remove(edgeWidthGUI); + + const edgeMaterial1 = new THREE.LineBasicMaterial( { + color: 0x000000, + linewidth: 3., + } ); + + function getEdges1(){ + const edges1 = new Float32Array( [ + 0.,0.,1., + 1.,0.,1, + + 0.,0.,1., + 0.,2.,1., + + 1.,0.,1, + 0.,2.,1., + + 1.,0.,1, + 1.5,0,1, + + 1.,0.,1, + 0.5,1.,1, + + 1.5,0,1, + 0.5,1.,1, + + ]); + return edges1; + } + + + // generate geometries and lines for the edges + + const edgeGeometry1 = new THREE.BufferGeometry(); + edgeGeometry1.setAttribute( 'position', new THREE.BufferAttribute( getEdges1(), 3 ) ); + + const edgeLine1 = new THREE.LineSegments( edgeGeometry1, edgeMaterial1 ); + edgeRoot.add(edgeLine1); + + // update function to be called every frame + // generate labels and spheres for the vertices + + + function getVertex1(){ + return [0.,0.,1.,]; + } + const sphereMaterial1 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere1 = new THREE.Mesh( sphereGeometry, sphereMaterial1 ); + vertexRoot.add(sphere1); + sphere1.position.set(getVertex1()[0],getVertex1()[1],getVertex1()[2]); + + const lableDiv1 = document.createElement( 'div' ); + lableDiv1.className = 'label'; + lableDiv1.textContent = '1'; + lableDiv1.style.marginTop = '-1em'; + + const vertexLabel1 = new CSS2DObject( lableDiv1 ); + vertexLabel1.position.set(getVertex1()[0],getVertex1()[1],getVertex1()[2]); + vertexlabelRoot.add( vertexLabel1 ); + + + + function getVertex2(){ + return [1.,0.,1,]; + } + const sphereMaterial2 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere2 = new THREE.Mesh( sphereGeometry, sphereMaterial2 ); + vertexRoot.add(sphere2); + sphere2.position.set(getVertex2()[0],getVertex2()[1],getVertex2()[2]); + + const lableDiv2 = document.createElement( 'div' ); + lableDiv2.className = 'label'; + lableDiv2.textContent = '2'; + lableDiv2.style.marginTop = '-1em'; + + const vertexLabel2 = new CSS2DObject( lableDiv2 ); + vertexLabel2.position.set(getVertex2()[0],getVertex2()[1],getVertex2()[2]); + vertexlabelRoot.add( vertexLabel2 ); + + + + function getVertex3(){ + return [0.,2.,1.,]; + } + const sphereMaterial3 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere3 = new THREE.Mesh( sphereGeometry, sphereMaterial3 ); + vertexRoot.add(sphere3); + sphere3.position.set(getVertex3()[0],getVertex3()[1],getVertex3()[2]); + + const lableDiv3 = document.createElement( 'div' ); + lableDiv3.className = 'label'; + lableDiv3.textContent = '3'; + lableDiv3.style.marginTop = '-1em'; + + const vertexLabel3 = new CSS2DObject( lableDiv3 ); + vertexLabel3.position.set(getVertex3()[0],getVertex3()[1],getVertex3()[2]); + vertexlabelRoot.add( vertexLabel3 ); + + + + function getVertex4(){ + return [1.5,0,1,]; + } + const sphereMaterial4 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere4 = new THREE.Mesh( sphereGeometry, sphereMaterial4 ); + vertexRoot.add(sphere4); + sphere4.position.set(getVertex4()[0],getVertex4()[1],getVertex4()[2]); + + const lableDiv4 = document.createElement( 'div' ); + lableDiv4.className = 'label'; + lableDiv4.textContent = '4'; + lableDiv4.style.marginTop = '-1em'; + + const vertexLabel4 = new CSS2DObject( lableDiv4 ); + vertexLabel4.position.set(getVertex4()[0],getVertex4()[1],getVertex4()[2]); + vertexlabelRoot.add( vertexLabel4 ); + + + + function getVertex5(){ + return [0.5,1.,1,]; + } + const sphereMaterial5 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere5 = new THREE.Mesh( sphereGeometry, sphereMaterial5 ); + vertexRoot.add(sphere5); + sphere5.position.set(getVertex5()[0],getVertex5()[1],getVertex5()[2]); + + const lableDiv5 = document.createElement( 'div' ); + lableDiv5.className = 'label'; + lableDiv5.textContent = '5'; + lableDiv5.style.marginTop = '-1em'; + + const vertexLabel5 = new CSS2DObject( lableDiv5 ); + vertexLabel5.position.set(getVertex5()[0],getVertex5()[1],getVertex5()[2]); + vertexlabelRoot.add( vertexLabel5 ); + + // generate the rings for the incircles + + var inradius1 = calulateInradius(getVertex1(), getVertex2(), getVertex3()); + var incenter1 = calulateIncenter(getVertex1(), getVertex2(), getVertex3()); + var ringGeometry1 = new THREE.RingGeometry((inradius1 - 0.005),inradius1, 32); + const ringMaterial1 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh1 = new THREE.Mesh(ringGeometry1, ringMaterial1); + + function setCircleRotation1(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.,0.,1.],[ 1.,0.,1],[0.,2.,1.]); + + ringMesh1.position.setX(incenter[0]); + ringMesh1.position.setY(incenter[1]); + ringMesh1.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex1(), getVertex2(), getVertex3()); + var relRadius = inradius/inradius1; + + ringMesh1.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A1 = new THREE.Vector3(0.,0.,1.); + const B1 = new THREE.Vector3(1.,0.,1); + const C1 = new THREE.Vector3(0.,2.,1.); + + const normalVec1 = new THREE.Vector3(); + normalVec1.crossVectors(B1.sub(A1), C1.sub(A1)); + normalVec1.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal1 = new THREE.Vector3(0,0,1); + + const quaternionRotation1 = new THREE.Quaternion(); + quaternionRotation1.setFromUnitVectors(initialNormal1, normalVec1); + + ringMesh1.setRotationFromQuaternion(quaternionRotation1); + + return quaternionRotation1; + } + + ringRoot.add(ringMesh1); + + var inradius2 = calulateInradius(getVertex2(), getVertex4(), getVertex5()); + var incenter2 = calulateIncenter(getVertex2(), getVertex4(), getVertex5()); + var ringGeometry2 = new THREE.RingGeometry((inradius2 - 0.005),inradius2, 32); + const ringMaterial2 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh2 = new THREE.Mesh(ringGeometry2, ringMaterial2); + + function setCircleRotation2(){ + + //translate ring to incenter + var incenter = calulateIncenter([1.,0.,1],[ 1.5,0,1],[0.5,1.,1]); + + ringMesh2.position.setX(incenter[0]); + ringMesh2.position.setY(incenter[1]); + ringMesh2.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex2(), getVertex4(), getVertex5()); + var relRadius = inradius/inradius2; + + ringMesh2.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A2 = new THREE.Vector3(1.,0.,1); + const B2 = new THREE.Vector3(1.5,0,1); + const C2 = new THREE.Vector3(0.5,1.,1); + + const normalVec2 = new THREE.Vector3(); + normalVec2.crossVectors(B2.sub(A2), C2.sub(A2)); + normalVec2.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal2 = new THREE.Vector3(0,0,1); + + const quaternionRotation2 = new THREE.Quaternion(); + quaternionRotation2.setFromUnitVectors(initialNormal2, normalVec2); + + ringMesh2.setRotationFromQuaternion(quaternionRotation2); + + return quaternionRotation2; + } + + ringRoot.add(ringMesh2); + // function to update the circles every frame + function updateCircles(){ + setCircleRotation1(); + setCircleRotation2(); + } + + // needs to be called once to be initialized + updateCircles(); + + // function to update the circles width, that is called every frame even if the surface is not parameterized + function updateCircleWidth(){ + ringGeometry1.dispose(); + ringGeometry1 = new THREE.RingGeometry((inradius1 - guiParameters.circleWidth),inradius1, 32); + ringMesh1.geometry = ringGeometry1; + ringGeometry2.dispose(); + ringGeometry2 = new THREE.RingGeometry((inradius2 - guiParameters.circleWidth),inradius2, 32); + ringMesh2.geometry = ringGeometry2; + } + + updateCircleWidth(); + + // generate the normals trough the incenter orthogonal to the face + // getNormalsVectors generates the coordinates for the current values of the parameterized surface + function getNormalsVectors(){ + var vector1; + var vector2; + + var normals = []; + vector1 = []; + vector2 = []; + vector1[0] = (1.)-(0.); + vector1[1] = (0.)-(0.); + vector1[2] = (1)-(1.); + + vector2[0] = (0.)-(0.); + vector2[1] = (2.)-(0.); + vector2[2] = (1.)-(1.); + + var incenter = calulateIncenter([0.,0.,1.],[ 1.,0.,1],[0.,2.,1.]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (1.5)-(1.); + vector1[1] = (0)-(0.); + vector1[2] = (1)-(1); + + vector2[0] = (0.5)-(1.); + vector2[1] = (1.)-(0.); + vector2[2] = (1)-(1); + + var incenter = calulateIncenter([1.,0.,1],[ 1.5,0,1],[0.5,1.,1]); + normals.push([vector1, vector2, incenter]); + + return normals; + } + // getNormalsCoordinates calculates the right coordinates for the ortogonality and fitting values from the gui + function getNormalsCoordinates(){ + var res = []; + var normals = getNormalsVectors(); + for(var i = 0; i < normals.length; i++){ + var plus = []; + var minus = []; + + minus[0] = normals[i][2][0] - (1/2)*guiParameters.normalsLength*(normals[i][0][1]*normals[i][1][2] - normals[i][0][2]*normals[i][1][1]); + minus[1] = normals[i][2][1] - (1/2)*guiParameters.normalsLength*(normals[i][0][2]*normals[i][1][0] - normals[i][0][0]*normals[i][1][2]); + minus[2] = normals[i][2][2] - (1/2)*guiParameters.normalsLength*(normals[i][0][0]*normals[i][1][1] - normals[i][0][1]*normals[i][1][0]); + + plus[0] = normals[i][2][0] + (1/2)*guiParameters.normalsLength*(normals[i][0][1]*normals[i][1][2] - normals[i][0][2]*normals[i][1][1]); + plus[1] = normals[i][2][1] + (1/2)*guiParameters.normalsLength*(normals[i][0][2]*normals[i][1][0] - normals[i][0][0]*normals[i][1][2]); + plus[2] = normals[i][2][2] + (1/2)*guiParameters.normalsLength*(normals[i][0][0]*normals[i][1][1] - normals[i][0][1]*normals[i][1][0]); + + res.push(minus[0]); + res.push(minus[1]); + res.push(minus[2]); + res.push(plus[0]); + res.push(plus[1]); + res.push(plus[2]); + } + res = Float32Array.from(res); + + + return res; + } + + + const normalsMaterial = new THREE.LineBasicMaterial( { + color: 0x000000, + } ); + + const normalsGeometry = new THREE.BufferGeometry(); + normalsGeometry.setAttribute( 'position', new THREE.BufferAttribute( getNormalsCoordinates(), 3 ) ); + var normalsLine = new THREE.LineSegments( normalsGeometry, normalsMaterial ); + + function updateNormals(){ + normalsGeometry.setAttribute( 'position', new THREE.BufferAttribute( getNormalsCoordinates(), 3 ) ); + normalsLine = new THREE.LineSegments( normalsGeometry, normalsMaterial ); + } + + normalsRoot.add(normalsLine); + + + // generate automatic ranges for the intersections if the surface is not parameterized + guiParameters.maxX = 1.5; + guiParameters.maxY = 2.; + guiParameters.maxZ = 1.; + guiParameters.minX = 0.; + guiParameters.minY = 0.; + guiParameters.minZ = 0.; + + guiParameters.planeX = 0.75; + guiParameters.planeY = 1.; + guiParameters.planeZ = 0.5; + // --- end of generated output --- // + + const planeFolder = gui.addFolder("Intersection Planes"); + planeFolder.add(guiParameters, 'planeXactive'); + planeFolder.add(guiParameters, 'planeX', guiParameters.minX*1.1, guiParameters.maxX*1.1); + planeFolder.add(guiParameters, 'planeYactive'); + planeFolder.add(guiParameters, 'planeY', guiParameters.minY*1.1, guiParameters.maxY*1.1); + planeFolder.add(guiParameters, 'planeZactive'); + planeFolder.add(guiParameters, 'planeZ', guiParameters.minZ*1.1, guiParameters.maxZ*1.1); + + camera.position.z = Math.max((1.5)*guiParameters.minZ, 1) + camera.lookAt(0,0,-1); + + scene.background = new THREE.Color( 'white' ); + + // add both roots to the scene + scene.add( meshRoot ); + scene.add( wireRoot ); + scene.add( vertexRoot ); + scene.add( vertexlabelRoot ); + scene.add( edgeRoot ); + scene.add( ringRoot ); + scene.add( normalsRoot ); + scene.add( normalMeshRoot ); + + //presave some current gui parameters to only update if they change + var currentCircleWidth = guiParameters.circleWidth; + + function animate() { + requestAnimationFrame( animate ); + meshRoot.rotation.x += guiParameters.speedX/100; + meshRoot.rotation.y += guiParameters.speedY/100; + meshRoot.rotation.z += guiParameters.speedZ/100; + + wireRoot.rotation.x += guiParameters.speedX/100; + wireRoot.rotation.y += guiParameters.speedY/100; + wireRoot.rotation.z += guiParameters.speedZ/100; + + vertexRoot.rotation.x += guiParameters.speedX/100; + vertexRoot.rotation.y += guiParameters.speedY/100; + vertexRoot.rotation.z += guiParameters.speedZ/100; + + vertexlabelRoot.rotation.x += guiParameters.speedX/100; + vertexlabelRoot.rotation.y += guiParameters.speedY/100; + vertexlabelRoot.rotation.z += guiParameters.speedZ/100; + + edgeRoot.rotation.x += guiParameters.speedX/100; + edgeRoot.rotation.y += guiParameters.speedY/100; + edgeRoot.rotation.z += guiParameters.speedZ/100; + + ringRoot.rotation.x += guiParameters.speedX/100; + ringRoot.rotation.y += guiParameters.speedY/100; + ringRoot.rotation.z += guiParameters.speedZ/100; + + normalsRoot.rotation.x += guiParameters.speedX/100; + normalsRoot.rotation.y += guiParameters.speedY/100; + normalsRoot.rotation.z += guiParameters.speedZ/100; + + normalMeshRoot.rotation.x += guiParameters.speedX/100; + normalMeshRoot.rotation.y += guiParameters.speedY/100; + normalMeshRoot.rotation.z += guiParameters.speedZ/100; + + //update the light when the camera moves (with orbitcontrols) + light.position.set(camera.position.x, camera.position.y, camera.position.z); + + planeX.constant = guiParameters.planeX; + planeY.constant = guiParameters.planeY; + planeZ.constant = guiParameters.planeZ; + + activePlanes = []; + if(guiParameters.planeXactive){ + activePlanes.push(planeX); + } + if(guiParameters.planeYactive){ + activePlanes.push(planeY); + } + if(guiParameters.planeZactive){ + activePlanes.push(planeZ); + } + + if(vertexParametriziation){ + updateFaceCoordinates(); + if(guiParameters.edgeVisibility){ + updateEdgeCoordinates(); + } + if(guiParameters.vertexlabelVisibility || guiParameters.vertexVisibility){ + updateVertexCoordinates(); + } + if(guiParameters.circleVisibility){ + updateCircles(); + } + } + + //update stuff that changes from the gui + meshRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.opacity = guiParameters.transparency; + node.material.clippingPlanes = activePlanes; + if(guiParameters.normalsMaterial){ + node.material.opacity = 0; + } + } + } ); + + normalMeshRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.opacity = guiParameters.transparency; + node.material.clippingPlanes = activePlanes; + if(!guiParameters.normalsMaterial){ + node.material.opacity = 0; + } + } + } ); + + edgeRoot.traverse( function( node ) { + if ( node instanceof Line2 ) { + node.material.visible = guiParameters.edgeVisibility; + node.material.linewidth = guiParameters.edgeWidth/100; + } + if ( node instanceof THREE.LineSegments ) { + node.material.visible = guiParameters.edgeVisibility; + } + } ); + + vertexRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.visible = guiParameters.vertexVisibility; + node.scale.setScalar(guiParameters.vertexSize); + } + } ); + + vertexlabelRoot.traverse( function( node ) { + if( node instanceof CSS2DObject) { + node.visible = guiParameters.vertexlabelVisibility; + } + } ); + + ringRoot.traverse( function( node ) { + if( node instanceof THREE.Mesh) { + node.visible = guiParameters.circleVisibility; + } + } ); + + normalsRoot.traverse( function( node ) { + if( node instanceof THREE.LineSegments) { + node.visible = guiParameters.normalsVisibility; + } + } ); + + // update the circle width + if(guiParameters.circleVisibility && currentCircleWidth != guiParameters.circleWidth){ + updateCircleWidth(); + currentCircleWidth = guiParameters.circleWidth; + } + + //update the normals length + if(guiParameters.normalsVisibility){ + updateNormals(); + } + + controls.update(); + + renderer.localClippingEnabled = true; + + renderer.render( scene, camera ); + labelRenderer.render( scene, camera ); + } + animate(); + + //resize of window size changes + window.addEventListener( 'resize', onWindowResize ); + function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + labelRenderer.setSize( window.innerWidth, window.innerHeight ); + } +</script> + +</body> +</html> \ No newline at end of file diff --git a/htmls/TwoFacesIntersection.html b/htmls/TwoFacesIntersection.html new file mode 100644 index 0000000000000000000000000000000000000000..0a31cc69514120f98718bab78917616197398880 --- /dev/null +++ b/htmls/TwoFacesIntersection.html @@ -0,0 +1,761 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>SimplicialSurface</title> + <style> + body { margin: 0; } + </style> + + + </head> + <body> + +<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> + + +<script type="importmap"> + { + "imports": { + "three": "https://unpkg.com/three@0.148.0/build/three.module.js", + "three/addons/": "https://unpkg.com/three@0.148.0/examples/jsm/", + "gui": "https://unpkg.com/dat.gui@0.7.9/build/dat.gui.module.js" + } + } +</script> + + +<script type="module"> + import * as THREE from 'three'; + import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + import { GUI } from 'gui'; + import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js'; + import { Line2 } from 'three/addons/lines/Line2.js'; + import { LineMaterial } from 'three/addons/lines/LineMaterial.js'; + import { LineGeometry } from 'three/addons/lines/LineGeometry.js'; + + //start scene and camera + const scene = new THREE.Scene(); + const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 100 ); + + const renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setSize( window.innerWidth, window.innerHeight ); + document.body.appendChild( renderer.domElement ); + + //Lights + const skyColor = 0xFFFFFF; + const skyIntensity = 0.3; + const skyLight = new THREE.AmbientLight(skyColor, skyIntensity); + scene.add(skyLight); + + const color = 0xFFFFFF; + const intensity = 1; + const light = new THREE.PointLight(color, intensity); + light.position.set(0, 3, -5); + scene.add(light); + + //create groups to add everything to + const meshRoot = new THREE.Group(); + const wireRoot = new THREE.Group(); + const vertexRoot = new THREE.Group(); + const vertexlabelRoot = new THREE.Group(); + const edgeRoot = new THREE.Group(); + const ringRoot = new THREE.Group(); + const normalsRoot = new THREE.Group(); + const normalMeshRoot = new THREE.Group(); + + //parameters for the controls on the top right + var guiParameters = new function() { + this.speedX = 0.0; + this.speedY = 0.0; + this.speedZ = 0.0; + this.transparency = 1; + this.edgeVisibility = false; + this.edgeWidth = 0.2; + + this.vertexVisibility = true; + this.vertexlabelVisibility = false; + this.vertexSize = 1; + this.planeX = 0.0; + this.minX = -1.5; + this.maxX = 1.5; + this.planeXactive = false; + this.planeY = 0.0; + this.minY = -1.5; + + this.maxY = 1.5; + this.planeYactive = false; + this.planeZ = 0.0; + this.minZ = -1.5; + this.maxZ = 1.5; + this.planeZactive = false; + this.normalsMaterial = false; + this.circleVisibility = false; + this.circleWidth = 0.005; + this.normalsVisibility = false; + this.normalsLength = 1; + } ; + + //generate the plane for intersections + const planeX = new THREE.Plane( new THREE.Vector3( -1, 0, 0 ), guiParameters.planeX ); + const planeY = new THREE.Plane( new THREE.Vector3( 0, -1, 0 ), guiParameters.planeY ); + const planeZ = new THREE.Plane( new THREE.Vector3( 0, 0, -1 ), guiParameters.planeZ ); + + // the array which ones are currently active + var activePlanes = []; + + //rederer for lables + const labelRenderer = new CSS2DRenderer(); + labelRenderer.setSize( window.innerWidth, window.innerHeight ); + labelRenderer.domElement.style.position = 'absolute'; + labelRenderer.domElement.style.top = '0px'; + document.body.appendChild( labelRenderer.domElement ); + + //controls for mouse + const controls = new OrbitControls( camera, labelRenderer.domElement ); + + //controls in the top right corner + var gui = new GUI(); + + const animationFolder = gui.addFolder("Animations"); + animationFolder.add(guiParameters, 'speedX', 0, 5); + animationFolder.add(guiParameters, 'speedY', 0, 5); + animationFolder.add(guiParameters, 'speedZ', 0, 5); + animationFolder.open(); + + const controlFolder = gui.addFolder("Controls"); + controlFolder.add(guiParameters, "transparency", 0, 1); + controlFolder.add(guiParameters, "edgeVisibility"); + var edgeWidthGUI = controlFolder.add(guiParameters, "edgeWidth", 0.01, 2); + controlFolder.add(guiParameters, "vertexVisibility"); + controlFolder.add(guiParameters, "vertexlabelVisibility"); + controlFolder.add(guiParameters, "vertexSize", 0.1, 3); + controlFolder.add(guiParameters, "normalsMaterial"); + controlFolder.add(guiParameters, "circleVisibility"); + controlFolder.add(guiParameters, "circleWidth", 0.0001, 0.1); + controlFolder.add(guiParameters, "normalsVisibility"); + controlFolder.add(guiParameters, "normalsLength", 0, 2); + controlFolder.open(); + + //generate a sphere geometry for the vertices + const sphereGeometry = new THREE.SphereGeometry( 0.02, 32, 16 ); + sphereGeometry.transparent = guiParameters.vertexVisibility; + + //functions for later calculations + + function calulateIncenter(A, B, C){ + //we follow the math and variable names from here: https://math.stackexchange.com/questions/740111/incenter-of-triangle-in-3d + var a = Math.sqrt((B[0]-C[0])**2 + (B[1]-C[1])**2 + (B[2]-C[2])**2); + var b = Math.sqrt((C[0]-A[0])**2 + (C[1]-A[1])**2 + (C[2]-A[2])**2); + var c = Math.sqrt((A[0]-B[0])**2 + (A[1]-B[1])**2 + (A[2]-B[2])**2); + + var res = []; + res[0] = a/(a+b+c)*A[0] + b/(a+b+c)*B[0] + c/(a+b+c)*C[0]; + res[1] = a/(a+b+c)*A[1] + b/(a+b+c)*B[1] + c/(a+b+c)*C[1]; + res[2] = a/(a+b+c)*A[2] + b/(a+b+c)*B[2] + c/(a+b+c)*C[2]; + + return res; + } + + function calulateInradius(A, B, C){ + var a = Math.sqrt((B[0]-C[0])**2 + (B[1]-C[1])**2 + (B[2]-C[2])**2); + var b = Math.sqrt((C[0]-A[0])**2 + (C[1]-A[1])**2 + (C[2]-A[2])**2); + var c = Math.sqrt((A[0]-B[0])**2 + (A[1]-B[1])**2 + (A[2]-B[2])**2); + + var s = (a+b+c)/2; + var inradius = Math.sqrt(((s-a)*(s-b)*(s-c)) / s ); + + return inradius; + } + + // --- start of generated output --- // + + // preperations for parameterized vertex coordinates + const vertexParametriziation = false; + // generate the faces color by color + const geometry1 = new THREE.BufferGeometry(); + function setVertices1(){ + var vertices1 = new Float32Array( [ + 1.,0.,0., + -1.,0.,0., + 0.,2.,0., + + 0.5,0.5,0.5, + 0.5,0.5,-0.5, + 1.5,1,0, + + ] ); + + return vertices1; + } + + geometry1.setAttribute( 'position', new THREE.BufferAttribute( setVertices1(), 3 ) ); + + // generate materials in the given color and normals material for the faces + + const materialNormal1 = new THREE.MeshNormalMaterial({ + flatShading: true, + }); + materialNormal1.transparent = true; + materialNormal1.side = THREE.DoubleSide; + + const material1 = new THREE.MeshPhongMaterial({ + color: 0x049EF4, + flatShading: true, + }); + material1.transparent = true; + material1.side = THREE.DoubleSide; + + // generate meshes for the faces from the materials with the vertex coordinates from before + + const mesh1 = new THREE.Mesh( geometry1, material1 ); + mesh1.castShadow = true; + mesh1.receiveShadow = true; + + meshRoot.add(mesh1); + + const meshNormal1 = new THREE.Mesh( geometry1, materialNormal1 ); + mesh1.castShadow = true; + mesh1.receiveShadow = true; + + normalMeshRoot.add(meshNormal1); + + // generate the edges grouped by color + controlFolder.remove(edgeWidthGUI); + + const edgeMaterial1 = new THREE.LineBasicMaterial( { + color: 0x000000, + linewidth: 3., + } ); + + function getEdges1(){ + const edges1 = new Float32Array( [ + 1.,0.,0., + -1.,0.,0., + + 1.,0.,0., + 0.,2.,0., + + -1.,0.,0., + 0.,2.,0., + + 0.5,0.5,0.5, + 0.5,0.5,-0.5, + + 0.5,0.5,0.5, + 1.5,1,0, + + 0.5,0.5,-0.5, + 1.5,1,0, + + ]); + return edges1; + } + + + // generate geometries and lines for the edges + + const edgeGeometry1 = new THREE.BufferGeometry(); + edgeGeometry1.setAttribute( 'position', new THREE.BufferAttribute( getEdges1(), 3 ) ); + + const edgeLine1 = new THREE.LineSegments( edgeGeometry1, edgeMaterial1 ); + edgeRoot.add(edgeLine1); + + // update function to be called every frame + // generate labels and spheres for the vertices + + + function getVertex1(){ + return [1.,0.,0.,]; + } + const sphereMaterial1 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere1 = new THREE.Mesh( sphereGeometry, sphereMaterial1 ); + vertexRoot.add(sphere1); + sphere1.position.set(getVertex1()[0],getVertex1()[1],getVertex1()[2]); + + const lableDiv1 = document.createElement( 'div' ); + lableDiv1.className = 'label'; + lableDiv1.textContent = '1'; + lableDiv1.style.marginTop = '-1em'; + + const vertexLabel1 = new CSS2DObject( lableDiv1 ); + vertexLabel1.position.set(getVertex1()[0],getVertex1()[1],getVertex1()[2]); + vertexlabelRoot.add( vertexLabel1 ); + + + + function getVertex2(){ + return [-1.,0.,0.,]; + } + const sphereMaterial2 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere2 = new THREE.Mesh( sphereGeometry, sphereMaterial2 ); + vertexRoot.add(sphere2); + sphere2.position.set(getVertex2()[0],getVertex2()[1],getVertex2()[2]); + + const lableDiv2 = document.createElement( 'div' ); + lableDiv2.className = 'label'; + lableDiv2.textContent = '2'; + lableDiv2.style.marginTop = '-1em'; + + const vertexLabel2 = new CSS2DObject( lableDiv2 ); + vertexLabel2.position.set(getVertex2()[0],getVertex2()[1],getVertex2()[2]); + vertexlabelRoot.add( vertexLabel2 ); + + + + function getVertex3(){ + return [0.,2.,0.,]; + } + const sphereMaterial3 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere3 = new THREE.Mesh( sphereGeometry, sphereMaterial3 ); + vertexRoot.add(sphere3); + sphere3.position.set(getVertex3()[0],getVertex3()[1],getVertex3()[2]); + + const lableDiv3 = document.createElement( 'div' ); + lableDiv3.className = 'label'; + lableDiv3.textContent = '3'; + lableDiv3.style.marginTop = '-1em'; + + const vertexLabel3 = new CSS2DObject( lableDiv3 ); + vertexLabel3.position.set(getVertex3()[0],getVertex3()[1],getVertex3()[2]); + vertexlabelRoot.add( vertexLabel3 ); + + + + function getVertex4(){ + return [0.5,0.5,0.5,]; + } + const sphereMaterial4 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere4 = new THREE.Mesh( sphereGeometry, sphereMaterial4 ); + vertexRoot.add(sphere4); + sphere4.position.set(getVertex4()[0],getVertex4()[1],getVertex4()[2]); + + const lableDiv4 = document.createElement( 'div' ); + lableDiv4.className = 'label'; + lableDiv4.textContent = '4'; + lableDiv4.style.marginTop = '-1em'; + + const vertexLabel4 = new CSS2DObject( lableDiv4 ); + vertexLabel4.position.set(getVertex4()[0],getVertex4()[1],getVertex4()[2]); + vertexlabelRoot.add( vertexLabel4 ); + + + + function getVertex5(){ + return [0.5,0.5,-0.5,]; + } + const sphereMaterial5 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere5 = new THREE.Mesh( sphereGeometry, sphereMaterial5 ); + vertexRoot.add(sphere5); + sphere5.position.set(getVertex5()[0],getVertex5()[1],getVertex5()[2]); + + const lableDiv5 = document.createElement( 'div' ); + lableDiv5.className = 'label'; + lableDiv5.textContent = '5'; + lableDiv5.style.marginTop = '-1em'; + + const vertexLabel5 = new CSS2DObject( lableDiv5 ); + vertexLabel5.position.set(getVertex5()[0],getVertex5()[1],getVertex5()[2]); + vertexlabelRoot.add( vertexLabel5 ); + + + + function getVertex6(){ + return [1.5,1,0,]; + } + const sphereMaterial6 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere6 = new THREE.Mesh( sphereGeometry, sphereMaterial6 ); + vertexRoot.add(sphere6); + sphere6.position.set(getVertex6()[0],getVertex6()[1],getVertex6()[2]); + + const lableDiv6 = document.createElement( 'div' ); + lableDiv6.className = 'label'; + lableDiv6.textContent = '6'; + lableDiv6.style.marginTop = '-1em'; + + const vertexLabel6 = new CSS2DObject( lableDiv6 ); + vertexLabel6.position.set(getVertex6()[0],getVertex6()[1],getVertex6()[2]); + vertexlabelRoot.add( vertexLabel6 ); + + // generate the rings for the incircles + + var inradius1 = calulateInradius(getVertex1(), getVertex2(), getVertex3()); + var incenter1 = calulateIncenter(getVertex1(), getVertex2(), getVertex3()); + var ringGeometry1 = new THREE.RingGeometry((inradius1 - 0.005),inradius1, 32); + const ringMaterial1 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh1 = new THREE.Mesh(ringGeometry1, ringMaterial1); + + function setCircleRotation1(){ + + //translate ring to incenter + var incenter = calulateIncenter([1.,0.,0.],[ -1.,0.,0.],[0.,2.,0.]); + + ringMesh1.position.setX(incenter[0]); + ringMesh1.position.setY(incenter[1]); + ringMesh1.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex1(), getVertex2(), getVertex3()); + var relRadius = inradius/inradius1; + + ringMesh1.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A1 = new THREE.Vector3(1.,0.,0.); + const B1 = new THREE.Vector3(-1.,0.,0.); + const C1 = new THREE.Vector3(0.,2.,0.); + + const normalVec1 = new THREE.Vector3(); + normalVec1.crossVectors(B1.sub(A1), C1.sub(A1)); + normalVec1.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal1 = new THREE.Vector3(0,0,1); + + const quaternionRotation1 = new THREE.Quaternion(); + quaternionRotation1.setFromUnitVectors(initialNormal1, normalVec1); + + ringMesh1.setRotationFromQuaternion(quaternionRotation1); + + return quaternionRotation1; + } + + ringRoot.add(ringMesh1); + + var inradius2 = calulateInradius(getVertex4(), getVertex5(), getVertex6()); + var incenter2 = calulateIncenter(getVertex4(), getVertex5(), getVertex6()); + var ringGeometry2 = new THREE.RingGeometry((inradius2 - 0.005),inradius2, 32); + const ringMaterial2 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh2 = new THREE.Mesh(ringGeometry2, ringMaterial2); + + function setCircleRotation2(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.5,0.5,0.5],[ 0.5,0.5,-0.5],[1.5,1,0]); + + ringMesh2.position.setX(incenter[0]); + ringMesh2.position.setY(incenter[1]); + ringMesh2.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex4(), getVertex5(), getVertex6()); + var relRadius = inradius/inradius2; + + ringMesh2.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A2 = new THREE.Vector3(0.5,0.5,0.5); + const B2 = new THREE.Vector3(0.5,0.5,-0.5); + const C2 = new THREE.Vector3(1.5,1,0); + + const normalVec2 = new THREE.Vector3(); + normalVec2.crossVectors(B2.sub(A2), C2.sub(A2)); + normalVec2.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal2 = new THREE.Vector3(0,0,1); + + const quaternionRotation2 = new THREE.Quaternion(); + quaternionRotation2.setFromUnitVectors(initialNormal2, normalVec2); + + ringMesh2.setRotationFromQuaternion(quaternionRotation2); + + return quaternionRotation2; + } + + ringRoot.add(ringMesh2); + // function to update the circles every frame + function updateCircles(){ + setCircleRotation1(); + setCircleRotation2(); + } + + // needs to be called once to be initialized + updateCircles(); + + // function to update the circles width, that is called every frame even if the surface is not parameterized + function updateCircleWidth(){ + ringGeometry1.dispose(); + ringGeometry1 = new THREE.RingGeometry((inradius1 - guiParameters.circleWidth),inradius1, 32); + ringMesh1.geometry = ringGeometry1; + ringGeometry2.dispose(); + ringGeometry2 = new THREE.RingGeometry((inradius2 - guiParameters.circleWidth),inradius2, 32); + ringMesh2.geometry = ringGeometry2; + } + + updateCircleWidth(); + + // generate the normals trough the incenter orthogonal to the face + // getNormalsVectors generates the coordinates for the current values of the parameterized surface + function getNormalsVectors(){ + var vector1; + var vector2; + + var normals = []; + vector1 = []; + vector2 = []; + vector1[0] = (-1.)-(1.); + vector1[1] = (0.)-(0.); + vector1[2] = (0.)-(0.); + + vector2[0] = (0.)-(1.); + vector2[1] = (2.)-(0.); + vector2[2] = (0.)-(0.); + + var incenter = calulateIncenter([1.,0.,0.],[ -1.,0.,0.],[0.,2.,0.]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.5)-(0.5); + vector1[1] = (0.5)-(0.5); + vector1[2] = (-0.5)-(0.5); + + vector2[0] = (1.5)-(0.5); + vector2[1] = (1)-(0.5); + vector2[2] = (0)-(0.5); + + var incenter = calulateIncenter([0.5,0.5,0.5],[ 0.5,0.5,-0.5],[1.5,1,0]); + normals.push([vector1, vector2, incenter]); + + return normals; + } + // getNormalsCoordinates calculates the right coordinates for the ortogonality and fitting values from the gui + function getNormalsCoordinates(){ + var res = []; + var normals = getNormalsVectors(); + for(var i = 0; i < normals.length; i++){ + var plus = []; + var minus = []; + + minus[0] = normals[i][2][0] - (1/2)*guiParameters.normalsLength*(normals[i][0][1]*normals[i][1][2] - normals[i][0][2]*normals[i][1][1]); + minus[1] = normals[i][2][1] - (1/2)*guiParameters.normalsLength*(normals[i][0][2]*normals[i][1][0] - normals[i][0][0]*normals[i][1][2]); + minus[2] = normals[i][2][2] - (1/2)*guiParameters.normalsLength*(normals[i][0][0]*normals[i][1][1] - normals[i][0][1]*normals[i][1][0]); + + plus[0] = normals[i][2][0] + (1/2)*guiParameters.normalsLength*(normals[i][0][1]*normals[i][1][2] - normals[i][0][2]*normals[i][1][1]); + plus[1] = normals[i][2][1] + (1/2)*guiParameters.normalsLength*(normals[i][0][2]*normals[i][1][0] - normals[i][0][0]*normals[i][1][2]); + plus[2] = normals[i][2][2] + (1/2)*guiParameters.normalsLength*(normals[i][0][0]*normals[i][1][1] - normals[i][0][1]*normals[i][1][0]); + + res.push(minus[0]); + res.push(minus[1]); + res.push(minus[2]); + res.push(plus[0]); + res.push(plus[1]); + res.push(plus[2]); + } + res = Float32Array.from(res); + + + return res; + } + + + const normalsMaterial = new THREE.LineBasicMaterial( { + color: 0x000000, + } ); + + const normalsGeometry = new THREE.BufferGeometry(); + normalsGeometry.setAttribute( 'position', new THREE.BufferAttribute( getNormalsCoordinates(), 3 ) ); + var normalsLine = new THREE.LineSegments( normalsGeometry, normalsMaterial ); + + function updateNormals(){ + normalsGeometry.setAttribute( 'position', new THREE.BufferAttribute( getNormalsCoordinates(), 3 ) ); + normalsLine = new THREE.LineSegments( normalsGeometry, normalsMaterial ); + } + + normalsRoot.add(normalsLine); + + + // generate automatic ranges for the intersections if the surface is not parameterized + guiParameters.maxX = 1.5; + guiParameters.maxY = 2.; + guiParameters.maxZ = 0.5; + guiParameters.minX = -1.; + guiParameters.minY = 0.; + guiParameters.minZ = -0.5; + + guiParameters.planeX = 0.25; + guiParameters.planeY = 1.; + guiParameters.planeZ = 0.; + // --- end of generated output --- // + + const planeFolder = gui.addFolder("Intersection Planes"); + planeFolder.add(guiParameters, 'planeXactive'); + planeFolder.add(guiParameters, 'planeX', guiParameters.minX*1.1, guiParameters.maxX*1.1); + planeFolder.add(guiParameters, 'planeYactive'); + planeFolder.add(guiParameters, 'planeY', guiParameters.minY*1.1, guiParameters.maxY*1.1); + planeFolder.add(guiParameters, 'planeZactive'); + planeFolder.add(guiParameters, 'planeZ', guiParameters.minZ*1.1, guiParameters.maxZ*1.1); + + camera.position.z = Math.max((1.5)*guiParameters.minZ, 1) + camera.lookAt(0,0,-1); + + scene.background = new THREE.Color( 'white' ); + + // add both roots to the scene + scene.add( meshRoot ); + scene.add( wireRoot ); + scene.add( vertexRoot ); + scene.add( vertexlabelRoot ); + scene.add( edgeRoot ); + scene.add( ringRoot ); + scene.add( normalsRoot ); + scene.add( normalMeshRoot ); + + //presave some current gui parameters to only update if they change + var currentCircleWidth = guiParameters.circleWidth; + + function animate() { + requestAnimationFrame( animate ); + meshRoot.rotation.x += guiParameters.speedX/100; + meshRoot.rotation.y += guiParameters.speedY/100; + meshRoot.rotation.z += guiParameters.speedZ/100; + + wireRoot.rotation.x += guiParameters.speedX/100; + wireRoot.rotation.y += guiParameters.speedY/100; + wireRoot.rotation.z += guiParameters.speedZ/100; + + vertexRoot.rotation.x += guiParameters.speedX/100; + vertexRoot.rotation.y += guiParameters.speedY/100; + vertexRoot.rotation.z += guiParameters.speedZ/100; + + vertexlabelRoot.rotation.x += guiParameters.speedX/100; + vertexlabelRoot.rotation.y += guiParameters.speedY/100; + vertexlabelRoot.rotation.z += guiParameters.speedZ/100; + + edgeRoot.rotation.x += guiParameters.speedX/100; + edgeRoot.rotation.y += guiParameters.speedY/100; + edgeRoot.rotation.z += guiParameters.speedZ/100; + + ringRoot.rotation.x += guiParameters.speedX/100; + ringRoot.rotation.y += guiParameters.speedY/100; + ringRoot.rotation.z += guiParameters.speedZ/100; + + normalsRoot.rotation.x += guiParameters.speedX/100; + normalsRoot.rotation.y += guiParameters.speedY/100; + normalsRoot.rotation.z += guiParameters.speedZ/100; + + normalMeshRoot.rotation.x += guiParameters.speedX/100; + normalMeshRoot.rotation.y += guiParameters.speedY/100; + normalMeshRoot.rotation.z += guiParameters.speedZ/100; + + //update the light when the camera moves (with orbitcontrols) + light.position.set(camera.position.x, camera.position.y, camera.position.z); + + planeX.constant = guiParameters.planeX; + planeY.constant = guiParameters.planeY; + planeZ.constant = guiParameters.planeZ; + + activePlanes = []; + if(guiParameters.planeXactive){ + activePlanes.push(planeX); + } + if(guiParameters.planeYactive){ + activePlanes.push(planeY); + } + if(guiParameters.planeZactive){ + activePlanes.push(planeZ); + } + + if(vertexParametriziation){ + updateFaceCoordinates(); + if(guiParameters.edgeVisibility){ + updateEdgeCoordinates(); + } + if(guiParameters.vertexlabelVisibility || guiParameters.vertexVisibility){ + updateVertexCoordinates(); + } + if(guiParameters.circleVisibility){ + updateCircles(); + } + } + + //update stuff that changes from the gui + meshRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.opacity = guiParameters.transparency; + node.material.clippingPlanes = activePlanes; + if(guiParameters.normalsMaterial){ + node.material.opacity = 0; + } + } + } ); + + normalMeshRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.opacity = guiParameters.transparency; + node.material.clippingPlanes = activePlanes; + if(!guiParameters.normalsMaterial){ + node.material.opacity = 0; + } + } + } ); + + edgeRoot.traverse( function( node ) { + if ( node instanceof Line2 ) { + node.material.visible = guiParameters.edgeVisibility; + node.material.linewidth = guiParameters.edgeWidth/100; + } + if ( node instanceof THREE.LineSegments ) { + node.material.visible = guiParameters.edgeVisibility; + } + } ); + + vertexRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.visible = guiParameters.vertexVisibility; + node.scale.setScalar(guiParameters.vertexSize); + } + } ); + + vertexlabelRoot.traverse( function( node ) { + if( node instanceof CSS2DObject) { + node.visible = guiParameters.vertexlabelVisibility; + } + } ); + + ringRoot.traverse( function( node ) { + if( node instanceof THREE.Mesh) { + node.visible = guiParameters.circleVisibility; + } + } ); + + normalsRoot.traverse( function( node ) { + if( node instanceof THREE.LineSegments) { + node.visible = guiParameters.normalsVisibility; + } + } ); + + // update the circle width + if(guiParameters.circleVisibility && currentCircleWidth != guiParameters.circleWidth){ + updateCircleWidth(); + currentCircleWidth = guiParameters.circleWidth; + } + + //update the normals length + if(guiParameters.normalsVisibility){ + updateNormals(); + } + + controls.update(); + + renderer.localClippingEnabled = true; + + renderer.render( scene, camera ); + labelRenderer.render( scene, camera ); + } + animate(); + + //resize of window size changes + window.addEventListener( 'resize', onWindowResize ); + function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + labelRenderer.setSize( window.innerWidth, window.innerHeight ); + } +</script> + +</body> +</html> \ No newline at end of file diff --git a/htmls/ico_32.html b/htmls/ico_32.html new file mode 100644 index 0000000000000000000000000000000000000000..977b3b4732a3624b412e653a3b3d5bfe75504128 --- /dev/null +++ b/htmls/ico_32.html @@ -0,0 +1,2099 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>SimplicialSurface</title> + <style> + body { margin: 0; } + </style> + + + </head> + <body> + +<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> + + +<script type="importmap"> + { + "imports": { + "three": "https://unpkg.com/three@0.148.0/build/three.module.js", + "three/addons/": "https://unpkg.com/three@0.148.0/examples/jsm/", + "gui": "https://unpkg.com/dat.gui@0.7.9/build/dat.gui.module.js" + } + } +</script> + + +<script type="module"> + import * as THREE from 'three'; + import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + import { GUI } from 'gui'; + import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js'; + import { Line2 } from 'three/addons/lines/Line2.js'; + import { LineMaterial } from 'three/addons/lines/LineMaterial.js'; + import { LineGeometry } from 'three/addons/lines/LineGeometry.js'; + + //start scene and camera + const scene = new THREE.Scene(); + const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 100 ); + + const renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setSize( window.innerWidth, window.innerHeight ); + document.body.appendChild( renderer.domElement ); + + //Lights + const skyColor = 0xFFFFFF; + const skyIntensity = 0.3; + const skyLight = new THREE.AmbientLight(skyColor, skyIntensity); + scene.add(skyLight); + + const color = 0xFFFFFF; + const intensity = 1; + const light = new THREE.PointLight(color, intensity); + light.position.set(0, 3, -5); + scene.add(light); + + //create groups to add everything to + const meshRoot = new THREE.Group(); + const wireRoot = new THREE.Group(); + const vertexRoot = new THREE.Group(); + const vertexlabelRoot = new THREE.Group(); + const edgeRoot = new THREE.Group(); + const ringRoot = new THREE.Group(); + const normalsRoot = new THREE.Group(); + const normalMeshRoot = new THREE.Group(); + + //parameters for the controls on the top right + var guiParameters = new function() { + this.speedX = 0.0; + this.speedY = 0.0; + this.speedZ = 0.0; + this.transparency = 1; + this.edgeVisibility = false; + this.edgeWidth = 0.2; + + this.vertexVisibility = true; + this.vertexlabelVisibility = false; + this.vertexSize = 1; + this.planeX = 0.0; + this.minX = -1.5; + this.maxX = 1.5; + this.planeXactive = false; + this.planeY = 0.0; + this.minY = -1.5; + + this.maxY = 1.5; + this.planeYactive = false; + this.planeZ = 0.0; + this.minZ = -1.5; + this.maxZ = 1.5; + this.planeZactive = false; + this.normalsMaterial = false; + this.circleVisibility = false; + this.circleWidth = 0.005; + this.normalsVisibility = false; + this.normalsLength = 1; + } ; + + //generate the plane for intersections + const planeX = new THREE.Plane( new THREE.Vector3( -1, 0, 0 ), guiParameters.planeX ); + const planeY = new THREE.Plane( new THREE.Vector3( 0, -1, 0 ), guiParameters.planeY ); + const planeZ = new THREE.Plane( new THREE.Vector3( 0, 0, -1 ), guiParameters.planeZ ); + + // the array which ones are currently active + var activePlanes = []; + + //rederer for lables + const labelRenderer = new CSS2DRenderer(); + labelRenderer.setSize( window.innerWidth, window.innerHeight ); + labelRenderer.domElement.style.position = 'absolute'; + labelRenderer.domElement.style.top = '0px'; + document.body.appendChild( labelRenderer.domElement ); + + //controls for mouse + const controls = new OrbitControls( camera, labelRenderer.domElement ); + + //controls in the top right corner + var gui = new GUI(); + + const animationFolder = gui.addFolder("Animations"); + animationFolder.add(guiParameters, 'speedX', 0, 5); + animationFolder.add(guiParameters, 'speedY', 0, 5); + animationFolder.add(guiParameters, 'speedZ', 0, 5); + animationFolder.open(); + + const controlFolder = gui.addFolder("Controls"); + controlFolder.add(guiParameters, "transparency", 0, 1); + controlFolder.add(guiParameters, "edgeVisibility"); + var edgeWidthGUI = controlFolder.add(guiParameters, "edgeWidth", 0.01, 2); + controlFolder.add(guiParameters, "vertexVisibility"); + controlFolder.add(guiParameters, "vertexlabelVisibility"); + controlFolder.add(guiParameters, "vertexSize", 0.1, 3); + controlFolder.add(guiParameters, "normalsMaterial"); + controlFolder.add(guiParameters, "circleVisibility"); + controlFolder.add(guiParameters, "circleWidth", 0.0001, 0.1); + controlFolder.add(guiParameters, "normalsVisibility"); + controlFolder.add(guiParameters, "normalsLength", 0, 2); + controlFolder.open(); + + //generate a sphere geometry for the vertices + const sphereGeometry = new THREE.SphereGeometry( 0.02, 32, 16 ); + sphereGeometry.transparent = guiParameters.vertexVisibility; + + //functions for later calculations + + function calulateIncenter(A, B, C){ + //we follow the math and variable names from here: https://math.stackexchange.com/questions/740111/incenter-of-triangle-in-3d + var a = Math.sqrt((B[0]-C[0])**2 + (B[1]-C[1])**2 + (B[2]-C[2])**2); + var b = Math.sqrt((C[0]-A[0])**2 + (C[1]-A[1])**2 + (C[2]-A[2])**2); + var c = Math.sqrt((A[0]-B[0])**2 + (A[1]-B[1])**2 + (A[2]-B[2])**2); + + var res = []; + res[0] = a/(a+b+c)*A[0] + b/(a+b+c)*B[0] + c/(a+b+c)*C[0]; + res[1] = a/(a+b+c)*A[1] + b/(a+b+c)*B[1] + c/(a+b+c)*C[1]; + res[2] = a/(a+b+c)*A[2] + b/(a+b+c)*B[2] + c/(a+b+c)*C[2]; + + return res; + } + + function calulateInradius(A, B, C){ + var a = Math.sqrt((B[0]-C[0])**2 + (B[1]-C[1])**2 + (B[2]-C[2])**2); + var b = Math.sqrt((C[0]-A[0])**2 + (C[1]-A[1])**2 + (C[2]-A[2])**2); + var c = Math.sqrt((A[0]-B[0])**2 + (A[1]-B[1])**2 + (A[2]-B[2])**2); + + var s = (a+b+c)/2; + var inradius = Math.sqrt(((s-a)*(s-b)*(s-c)) / s ); + + return inradius; + } + + // --- start of generated output --- // + + // preperations for parameterized vertex coordinates + const vertexParametriziation = false; + // generate the faces color by color + const geometry1 = new THREE.BufferGeometry(); + function setVertices1(){ + var vertices1 = new Float32Array( [ + 0.951056516,0.,0., + 0.425325404,0.8506508085,0., + 0.425325404,0.262865556,0.809016994, + + 0.951056516,0.,0., + 0.425325404,0.8506508085,0., + -0.0449027976,-0.0277514551,0.08541019649999999, + + 0.951056516,0.,0., + -0.0449027976,-0.0277514551,0.08541019649999999, + 0.425325404,-0.6881909604000001,-0.4999999998, + + 0.951056516,0.,0., + 0.425325404,-0.6881909604000001,-0.4999999998, + 0.425325404,-0.6881909604000001,0.4999999998, + + 0.951056516,0.,0., + 0.425325404,0.262865556,0.809016994, + 0.425325404,-0.6881909604000001,0.4999999998, + + 0.425325404,0.8506508085,0., + 0.425325404,0.262865556,0.809016994, + -0.425325404,0.6881909604000001,0.4999999998, + + 0.425325404,0.8506508085,0., + -0.0449027976,-0.0277514551,0.08541019649999999, + -0.425325404,0.6881909604000001,-0.4999999998, + + -0.0449027976,-0.0277514551,0.08541019649999999, + 0.425325404,-0.6881909604000001,-0.4999999998, + -0.425325404,-0.262865556,-0.809016994, + + 0.425325404,-0.6881909604000001,-0.4999999998, + 0.425325404,-0.6881909604000001,0.4999999998, + -0.425325404,-0.8506508085,0., + + 0.425325404,0.262865556,0.809016994, + 0.425325404,-0.6881909604000001,0.4999999998, + 0.0449027976,0.0277514551,-0.08541019649999999, + + 0.425325404,0.8506508085,0., + -0.425325404,0.6881909604000001,0.4999999998, + -0.425325404,0.6881909604000001,-0.4999999998, + + -0.0449027976,-0.0277514551,0.08541019649999999, + -0.425325404,0.6881909604000001,-0.4999999998, + -0.425325404,-0.262865556,-0.809016994, + + 0.425325404,-0.6881909604000001,-0.4999999998, + -0.425325404,-0.262865556,-0.809016994, + -0.425325404,-0.8506508085,0., + + 0.425325404,-0.6881909604000001,0.4999999998, + -0.425325404,-0.8506508085,0., + 0.0449027976,0.0277514551,-0.08541019649999999, + + 0.425325404,0.262865556,0.809016994, + -0.425325404,0.6881909604000001,0.4999999998, + 0.0449027976,0.0277514551,-0.08541019649999999, + + -0.425325404,0.6881909604000001,0.4999999998, + -0.425325404,0.6881909604000001,-0.4999999998, + -0.951056516,0.,0., + + -0.425325404,0.6881909604000001,-0.4999999998, + -0.425325404,-0.262865556,-0.809016994, + -0.951056516,0.,0., + + -0.425325404,-0.262865556,-0.809016994, + -0.425325404,-0.8506508085,0., + -0.951056516,0.,0., + + -0.425325404,-0.8506508085,0., + 0.0449027976,0.0277514551,-0.08541019649999999, + -0.951056516,0.,0., + + -0.425325404,0.6881909604000001,0.4999999998, + 0.0449027976,0.0277514551,-0.08541019649999999, + -0.951056516,0.,0., + + ] ); + + return vertices1; + } + + geometry1.setAttribute( 'position', new THREE.BufferAttribute( setVertices1(), 3 ) ); + + // generate materials in the given color and normals material for the faces + + const materialNormal1 = new THREE.MeshNormalMaterial({ + flatShading: true, + }); + materialNormal1.transparent = true; + materialNormal1.side = THREE.DoubleSide; + + const material1 = new THREE.MeshPhongMaterial({ + color: 0x049EF4, + flatShading: true, + }); + material1.transparent = true; + material1.side = THREE.DoubleSide; + + // generate meshes for the faces from the materials with the vertex coordinates from before + + const mesh1 = new THREE.Mesh( geometry1, material1 ); + mesh1.castShadow = true; + mesh1.receiveShadow = true; + + meshRoot.add(mesh1); + + const meshNormal1 = new THREE.Mesh( geometry1, materialNormal1 ); + mesh1.castShadow = true; + mesh1.receiveShadow = true; + + normalMeshRoot.add(meshNormal1); + + // generate the edges grouped by color + controlFolder.remove(edgeWidthGUI); + + const edgeMaterial1 = new THREE.LineBasicMaterial( { + color: 0x000000, + linewidth: 3., + } ); + + function getEdges1(){ + const edges1 = new Float32Array( [ + 0.95105651599999996,0.,0., + 0.42532540400000002,0.85065080849999997,0., + + 0.95105651599999996,0.,0., + 0.42532540400000002,0.262865556,0.80901699400000004, + + 0.95105651599999996,0.,0., + -0.044902797600000002,-0.027751455099999999,0.085410196499999994, + + 0.95105651599999996,0.,0., + 0.42532540400000002,-0.68819096040000005,-0.49999999979999998, + + 0.95105651599999996,0.,0., + 0.42532540400000002,-0.68819096040000005,0.49999999979999998, + + 0.42532540400000002,0.85065080849999997,0., + 0.42532540400000002,0.262865556,0.80901699400000004, + + 0.42532540400000002,0.85065080849999997,0., + -0.044902797600000002,-0.027751455099999999,0.085410196499999994, + + 0.42532540400000002,0.85065080849999997,0., + -0.42532540400000002,0.68819096040000005,0.49999999979999998, + + 0.42532540400000002,0.85065080849999997,0., + -0.42532540400000002,0.68819096040000005,-0.49999999979999998, + + 0.42532540400000002,0.262865556,0.80901699400000004, + 0.42532540400000002,-0.68819096040000005,0.49999999979999998, + + 0.42532540400000002,0.262865556,0.80901699400000004, + -0.42532540400000002,0.68819096040000005,0.49999999979999998, + + 0.42532540400000002,0.262865556,0.80901699400000004, + 0.044902797600000002,0.027751455099999999,-0.085410196499999994, + + -0.044902797600000002,-0.027751455099999999,0.085410196499999994, + 0.42532540400000002,-0.68819096040000005,-0.49999999979999998, + + -0.044902797600000002,-0.027751455099999999,0.085410196499999994, + -0.42532540400000002,0.68819096040000005,-0.49999999979999998, + + -0.044902797600000002,-0.027751455099999999,0.085410196499999994, + -0.42532540400000002,-0.262865556,-0.80901699400000004, + + 0.42532540400000002,-0.68819096040000005,-0.49999999979999998, + 0.42532540400000002,-0.68819096040000005,0.49999999979999998, + + 0.42532540400000002,-0.68819096040000005,-0.49999999979999998, + -0.42532540400000002,-0.262865556,-0.80901699400000004, + + 0.42532540400000002,-0.68819096040000005,-0.49999999979999998, + -0.42532540400000002,-0.85065080849999997,0., + + 0.42532540400000002,-0.68819096040000005,0.49999999979999998, + -0.42532540400000002,-0.85065080849999997,0., + + 0.42532540400000002,-0.68819096040000005,0.49999999979999998, + 0.044902797600000002,0.027751455099999999,-0.085410196499999994, + + -0.42532540400000002,0.68819096040000005,0.49999999979999998, + -0.42532540400000002,0.68819096040000005,-0.49999999979999998, + + -0.42532540400000002,0.68819096040000005,0.49999999979999998, + 0.044902797600000002,0.027751455099999999,-0.085410196499999994, + + -0.42532540400000002,0.68819096040000005,0.49999999979999998, + -0.95105651599999996,0.,0., + + -0.42532540400000002,0.68819096040000005,-0.49999999979999998, + -0.42532540400000002,-0.262865556,-0.80901699400000004, + + -0.42532540400000002,0.68819096040000005,-0.49999999979999998, + -0.95105651599999996,0.,0., + + -0.42532540400000002,-0.262865556,-0.80901699400000004, + -0.42532540400000002,-0.85065080849999997,0., + + -0.42532540400000002,-0.262865556,-0.80901699400000004, + -0.95105651599999996,0.,0., + + -0.42532540400000002,-0.85065080849999997,0., + 0.044902797600000002,0.027751455099999999,-0.085410196499999994, + + -0.42532540400000002,-0.85065080849999997,0., + -0.95105651599999996,0.,0., + + 0.044902797600000002,0.027751455099999999,-0.085410196499999994, + -0.95105651599999996,0.,0., + + ]); + return edges1; + } + + + // generate geometries and lines for the edges + + const edgeGeometry1 = new THREE.BufferGeometry(); + edgeGeometry1.setAttribute( 'position', new THREE.BufferAttribute( getEdges1(), 3 ) ); + + const edgeLine1 = new THREE.LineSegments( edgeGeometry1, edgeMaterial1 ); + edgeRoot.add(edgeLine1); + + // update function to be called every frame + // generate labels and spheres for the vertices + + + function getVertex1(){ + return [0.95105651599999996,0.,0.,]; + } + const sphereMaterial1 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere1 = new THREE.Mesh( sphereGeometry, sphereMaterial1 ); + vertexRoot.add(sphere1); + sphere1.position.set(getVertex1()[0],getVertex1()[1],getVertex1()[2]); + + const lableDiv1 = document.createElement( 'div' ); + lableDiv1.className = 'label'; + lableDiv1.textContent = '1'; + lableDiv1.style.marginTop = '-1em'; + + const vertexLabel1 = new CSS2DObject( lableDiv1 ); + vertexLabel1.position.set(getVertex1()[0],getVertex1()[1],getVertex1()[2]); + vertexlabelRoot.add( vertexLabel1 ); + + + + function getVertex2(){ + return [0.42532540400000002,0.85065080849999997,0.,]; + } + const sphereMaterial2 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere2 = new THREE.Mesh( sphereGeometry, sphereMaterial2 ); + vertexRoot.add(sphere2); + sphere2.position.set(getVertex2()[0],getVertex2()[1],getVertex2()[2]); + + const lableDiv2 = document.createElement( 'div' ); + lableDiv2.className = 'label'; + lableDiv2.textContent = '2'; + lableDiv2.style.marginTop = '-1em'; + + const vertexLabel2 = new CSS2DObject( lableDiv2 ); + vertexLabel2.position.set(getVertex2()[0],getVertex2()[1],getVertex2()[2]); + vertexlabelRoot.add( vertexLabel2 ); + + + + function getVertex3(){ + return [0.42532540400000002,0.262865556,0.80901699400000004,]; + } + const sphereMaterial3 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere3 = new THREE.Mesh( sphereGeometry, sphereMaterial3 ); + vertexRoot.add(sphere3); + sphere3.position.set(getVertex3()[0],getVertex3()[1],getVertex3()[2]); + + const lableDiv3 = document.createElement( 'div' ); + lableDiv3.className = 'label'; + lableDiv3.textContent = '3'; + lableDiv3.style.marginTop = '-1em'; + + const vertexLabel3 = new CSS2DObject( lableDiv3 ); + vertexLabel3.position.set(getVertex3()[0],getVertex3()[1],getVertex3()[2]); + vertexlabelRoot.add( vertexLabel3 ); + + + + function getVertex4(){ + return [-0.044902797600000002,-0.027751455099999999,0.085410196499999994,]; + } + const sphereMaterial4 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere4 = new THREE.Mesh( sphereGeometry, sphereMaterial4 ); + vertexRoot.add(sphere4); + sphere4.position.set(getVertex4()[0],getVertex4()[1],getVertex4()[2]); + + const lableDiv4 = document.createElement( 'div' ); + lableDiv4.className = 'label'; + lableDiv4.textContent = '4'; + lableDiv4.style.marginTop = '-1em'; + + const vertexLabel4 = new CSS2DObject( lableDiv4 ); + vertexLabel4.position.set(getVertex4()[0],getVertex4()[1],getVertex4()[2]); + vertexlabelRoot.add( vertexLabel4 ); + + + + function getVertex5(){ + return [0.42532540400000002,-0.68819096040000005,-0.49999999979999998,]; + } + const sphereMaterial5 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere5 = new THREE.Mesh( sphereGeometry, sphereMaterial5 ); + vertexRoot.add(sphere5); + sphere5.position.set(getVertex5()[0],getVertex5()[1],getVertex5()[2]); + + const lableDiv5 = document.createElement( 'div' ); + lableDiv5.className = 'label'; + lableDiv5.textContent = '5'; + lableDiv5.style.marginTop = '-1em'; + + const vertexLabel5 = new CSS2DObject( lableDiv5 ); + vertexLabel5.position.set(getVertex5()[0],getVertex5()[1],getVertex5()[2]); + vertexlabelRoot.add( vertexLabel5 ); + + + + function getVertex6(){ + return [0.42532540400000002,-0.68819096040000005,0.49999999979999998,]; + } + const sphereMaterial6 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere6 = new THREE.Mesh( sphereGeometry, sphereMaterial6 ); + vertexRoot.add(sphere6); + sphere6.position.set(getVertex6()[0],getVertex6()[1],getVertex6()[2]); + + const lableDiv6 = document.createElement( 'div' ); + lableDiv6.className = 'label'; + lableDiv6.textContent = '6'; + lableDiv6.style.marginTop = '-1em'; + + const vertexLabel6 = new CSS2DObject( lableDiv6 ); + vertexLabel6.position.set(getVertex6()[0],getVertex6()[1],getVertex6()[2]); + vertexlabelRoot.add( vertexLabel6 ); + + + + function getVertex7(){ + return [-0.42532540400000002,0.68819096040000005,0.49999999979999998,]; + } + const sphereMaterial7 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere7 = new THREE.Mesh( sphereGeometry, sphereMaterial7 ); + vertexRoot.add(sphere7); + sphere7.position.set(getVertex7()[0],getVertex7()[1],getVertex7()[2]); + + const lableDiv7 = document.createElement( 'div' ); + lableDiv7.className = 'label'; + lableDiv7.textContent = '7'; + lableDiv7.style.marginTop = '-1em'; + + const vertexLabel7 = new CSS2DObject( lableDiv7 ); + vertexLabel7.position.set(getVertex7()[0],getVertex7()[1],getVertex7()[2]); + vertexlabelRoot.add( vertexLabel7 ); + + + + function getVertex8(){ + return [-0.42532540400000002,0.68819096040000005,-0.49999999979999998,]; + } + const sphereMaterial8 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere8 = new THREE.Mesh( sphereGeometry, sphereMaterial8 ); + vertexRoot.add(sphere8); + sphere8.position.set(getVertex8()[0],getVertex8()[1],getVertex8()[2]); + + const lableDiv8 = document.createElement( 'div' ); + lableDiv8.className = 'label'; + lableDiv8.textContent = '8'; + lableDiv8.style.marginTop = '-1em'; + + const vertexLabel8 = new CSS2DObject( lableDiv8 ); + vertexLabel8.position.set(getVertex8()[0],getVertex8()[1],getVertex8()[2]); + vertexlabelRoot.add( vertexLabel8 ); + + + + function getVertex9(){ + return [-0.42532540400000002,-0.262865556,-0.80901699400000004,]; + } + const sphereMaterial9 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere9 = new THREE.Mesh( sphereGeometry, sphereMaterial9 ); + vertexRoot.add(sphere9); + sphere9.position.set(getVertex9()[0],getVertex9()[1],getVertex9()[2]); + + const lableDiv9 = document.createElement( 'div' ); + lableDiv9.className = 'label'; + lableDiv9.textContent = '9'; + lableDiv9.style.marginTop = '-1em'; + + const vertexLabel9 = new CSS2DObject( lableDiv9 ); + vertexLabel9.position.set(getVertex9()[0],getVertex9()[1],getVertex9()[2]); + vertexlabelRoot.add( vertexLabel9 ); + + + + function getVertex10(){ + return [-0.42532540400000002,-0.85065080849999997,0.,]; + } + const sphereMaterial10 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere10 = new THREE.Mesh( sphereGeometry, sphereMaterial10 ); + vertexRoot.add(sphere10); + sphere10.position.set(getVertex10()[0],getVertex10()[1],getVertex10()[2]); + + const lableDiv10 = document.createElement( 'div' ); + lableDiv10.className = 'label'; + lableDiv10.textContent = '10'; + lableDiv10.style.marginTop = '-1em'; + + const vertexLabel10 = new CSS2DObject( lableDiv10 ); + vertexLabel10.position.set(getVertex10()[0],getVertex10()[1],getVertex10()[2]); + vertexlabelRoot.add( vertexLabel10 ); + + + + function getVertex11(){ + return [0.044902797600000002,0.027751455099999999,-0.085410196499999994,]; + } + const sphereMaterial11 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere11 = new THREE.Mesh( sphereGeometry, sphereMaterial11 ); + vertexRoot.add(sphere11); + sphere11.position.set(getVertex11()[0],getVertex11()[1],getVertex11()[2]); + + const lableDiv11 = document.createElement( 'div' ); + lableDiv11.className = 'label'; + lableDiv11.textContent = '11'; + lableDiv11.style.marginTop = '-1em'; + + const vertexLabel11 = new CSS2DObject( lableDiv11 ); + vertexLabel11.position.set(getVertex11()[0],getVertex11()[1],getVertex11()[2]); + vertexlabelRoot.add( vertexLabel11 ); + + + + function getVertex12(){ + return [-0.95105651599999996,0.,0.,]; + } + const sphereMaterial12 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere12 = new THREE.Mesh( sphereGeometry, sphereMaterial12 ); + vertexRoot.add(sphere12); + sphere12.position.set(getVertex12()[0],getVertex12()[1],getVertex12()[2]); + + const lableDiv12 = document.createElement( 'div' ); + lableDiv12.className = 'label'; + lableDiv12.textContent = '12'; + lableDiv12.style.marginTop = '-1em'; + + const vertexLabel12 = new CSS2DObject( lableDiv12 ); + vertexLabel12.position.set(getVertex12()[0],getVertex12()[1],getVertex12()[2]); + vertexlabelRoot.add( vertexLabel12 ); + + // generate the rings for the incircles + + var inradius1 = calulateInradius(getVertex1(), getVertex2(), getVertex3()); + var incenter1 = calulateIncenter(getVertex1(), getVertex2(), getVertex3()); + var ringGeometry1 = new THREE.RingGeometry((inradius1 - 0.005),inradius1, 32); + const ringMaterial1 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh1 = new THREE.Mesh(ringGeometry1, ringMaterial1); + + function setCircleRotation1(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.95105651599999996,0.,0.],[ 0.42532540400000002,0.85065080849999997,0.],[0.42532540400000002,0.262865556,0.80901699400000004]); + + ringMesh1.position.setX(incenter[0]); + ringMesh1.position.setY(incenter[1]); + ringMesh1.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex1(), getVertex2(), getVertex3()); + var relRadius = inradius/inradius1; + + ringMesh1.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A1 = new THREE.Vector3(0.95105651599999996,0.,0.); + const B1 = new THREE.Vector3(0.42532540400000002,0.85065080849999997,0.); + const C1 = new THREE.Vector3(0.42532540400000002,0.262865556,0.80901699400000004); + + const normalVec1 = new THREE.Vector3(); + normalVec1.crossVectors(B1.sub(A1), C1.sub(A1)); + normalVec1.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal1 = new THREE.Vector3(0,0,1); + + const quaternionRotation1 = new THREE.Quaternion(); + quaternionRotation1.setFromUnitVectors(initialNormal1, normalVec1); + + ringMesh1.setRotationFromQuaternion(quaternionRotation1); + + return quaternionRotation1; + } + + ringRoot.add(ringMesh1); + + var inradius2 = calulateInradius(getVertex1(), getVertex2(), getVertex4()); + var incenter2 = calulateIncenter(getVertex1(), getVertex2(), getVertex4()); + var ringGeometry2 = new THREE.RingGeometry((inradius2 - 0.005),inradius2, 32); + const ringMaterial2 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh2 = new THREE.Mesh(ringGeometry2, ringMaterial2); + + function setCircleRotation2(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.95105651599999996,0.,0.],[ 0.42532540400000002,0.85065080849999997,0.],[-0.044902797600000002,-0.027751455099999999,0.085410196499999994]); + + ringMesh2.position.setX(incenter[0]); + ringMesh2.position.setY(incenter[1]); + ringMesh2.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex1(), getVertex2(), getVertex4()); + var relRadius = inradius/inradius2; + + ringMesh2.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A2 = new THREE.Vector3(0.95105651599999996,0.,0.); + const B2 = new THREE.Vector3(0.42532540400000002,0.85065080849999997,0.); + const C2 = new THREE.Vector3(-0.044902797600000002,-0.027751455099999999,0.085410196499999994); + + const normalVec2 = new THREE.Vector3(); + normalVec2.crossVectors(B2.sub(A2), C2.sub(A2)); + normalVec2.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal2 = new THREE.Vector3(0,0,1); + + const quaternionRotation2 = new THREE.Quaternion(); + quaternionRotation2.setFromUnitVectors(initialNormal2, normalVec2); + + ringMesh2.setRotationFromQuaternion(quaternionRotation2); + + return quaternionRotation2; + } + + ringRoot.add(ringMesh2); + + var inradius3 = calulateInradius(getVertex1(), getVertex4(), getVertex5()); + var incenter3 = calulateIncenter(getVertex1(), getVertex4(), getVertex5()); + var ringGeometry3 = new THREE.RingGeometry((inradius3 - 0.005),inradius3, 32); + const ringMaterial3 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh3 = new THREE.Mesh(ringGeometry3, ringMaterial3); + + function setCircleRotation3(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.95105651599999996,0.,0.],[ -0.044902797600000002,-0.027751455099999999,0.085410196499999994],[0.42532540400000002,-0.68819096040000005,-0.49999999979999998]); + + ringMesh3.position.setX(incenter[0]); + ringMesh3.position.setY(incenter[1]); + ringMesh3.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex1(), getVertex4(), getVertex5()); + var relRadius = inradius/inradius3; + + ringMesh3.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A3 = new THREE.Vector3(0.95105651599999996,0.,0.); + const B3 = new THREE.Vector3(-0.044902797600000002,-0.027751455099999999,0.085410196499999994); + const C3 = new THREE.Vector3(0.42532540400000002,-0.68819096040000005,-0.49999999979999998); + + const normalVec3 = new THREE.Vector3(); + normalVec3.crossVectors(B3.sub(A3), C3.sub(A3)); + normalVec3.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal3 = new THREE.Vector3(0,0,1); + + const quaternionRotation3 = new THREE.Quaternion(); + quaternionRotation3.setFromUnitVectors(initialNormal3, normalVec3); + + ringMesh3.setRotationFromQuaternion(quaternionRotation3); + + return quaternionRotation3; + } + + ringRoot.add(ringMesh3); + + var inradius4 = calulateInradius(getVertex1(), getVertex5(), getVertex6()); + var incenter4 = calulateIncenter(getVertex1(), getVertex5(), getVertex6()); + var ringGeometry4 = new THREE.RingGeometry((inradius4 - 0.005),inradius4, 32); + const ringMaterial4 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh4 = new THREE.Mesh(ringGeometry4, ringMaterial4); + + function setCircleRotation4(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.95105651599999996,0.,0.],[ 0.42532540400000002,-0.68819096040000005,-0.49999999979999998],[0.42532540400000002,-0.68819096040000005,0.49999999979999998]); + + ringMesh4.position.setX(incenter[0]); + ringMesh4.position.setY(incenter[1]); + ringMesh4.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex1(), getVertex5(), getVertex6()); + var relRadius = inradius/inradius4; + + ringMesh4.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A4 = new THREE.Vector3(0.95105651599999996,0.,0.); + const B4 = new THREE.Vector3(0.42532540400000002,-0.68819096040000005,-0.49999999979999998); + const C4 = new THREE.Vector3(0.42532540400000002,-0.68819096040000005,0.49999999979999998); + + const normalVec4 = new THREE.Vector3(); + normalVec4.crossVectors(B4.sub(A4), C4.sub(A4)); + normalVec4.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal4 = new THREE.Vector3(0,0,1); + + const quaternionRotation4 = new THREE.Quaternion(); + quaternionRotation4.setFromUnitVectors(initialNormal4, normalVec4); + + ringMesh4.setRotationFromQuaternion(quaternionRotation4); + + return quaternionRotation4; + } + + ringRoot.add(ringMesh4); + + var inradius5 = calulateInradius(getVertex1(), getVertex3(), getVertex6()); + var incenter5 = calulateIncenter(getVertex1(), getVertex3(), getVertex6()); + var ringGeometry5 = new THREE.RingGeometry((inradius5 - 0.005),inradius5, 32); + const ringMaterial5 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh5 = new THREE.Mesh(ringGeometry5, ringMaterial5); + + function setCircleRotation5(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.95105651599999996,0.,0.],[ 0.42532540400000002,0.262865556,0.80901699400000004],[0.42532540400000002,-0.68819096040000005,0.49999999979999998]); + + ringMesh5.position.setX(incenter[0]); + ringMesh5.position.setY(incenter[1]); + ringMesh5.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex1(), getVertex3(), getVertex6()); + var relRadius = inradius/inradius5; + + ringMesh5.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A5 = new THREE.Vector3(0.95105651599999996,0.,0.); + const B5 = new THREE.Vector3(0.42532540400000002,0.262865556,0.80901699400000004); + const C5 = new THREE.Vector3(0.42532540400000002,-0.68819096040000005,0.49999999979999998); + + const normalVec5 = new THREE.Vector3(); + normalVec5.crossVectors(B5.sub(A5), C5.sub(A5)); + normalVec5.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal5 = new THREE.Vector3(0,0,1); + + const quaternionRotation5 = new THREE.Quaternion(); + quaternionRotation5.setFromUnitVectors(initialNormal5, normalVec5); + + ringMesh5.setRotationFromQuaternion(quaternionRotation5); + + return quaternionRotation5; + } + + ringRoot.add(ringMesh5); + + var inradius6 = calulateInradius(getVertex2(), getVertex3(), getVertex7()); + var incenter6 = calulateIncenter(getVertex2(), getVertex3(), getVertex7()); + var ringGeometry6 = new THREE.RingGeometry((inradius6 - 0.005),inradius6, 32); + const ringMaterial6 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh6 = new THREE.Mesh(ringGeometry6, ringMaterial6); + + function setCircleRotation6(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.42532540400000002,0.85065080849999997,0.],[ 0.42532540400000002,0.262865556,0.80901699400000004],[-0.42532540400000002,0.68819096040000005,0.49999999979999998]); + + ringMesh6.position.setX(incenter[0]); + ringMesh6.position.setY(incenter[1]); + ringMesh6.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex2(), getVertex3(), getVertex7()); + var relRadius = inradius/inradius6; + + ringMesh6.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A6 = new THREE.Vector3(0.42532540400000002,0.85065080849999997,0.); + const B6 = new THREE.Vector3(0.42532540400000002,0.262865556,0.80901699400000004); + const C6 = new THREE.Vector3(-0.42532540400000002,0.68819096040000005,0.49999999979999998); + + const normalVec6 = new THREE.Vector3(); + normalVec6.crossVectors(B6.sub(A6), C6.sub(A6)); + normalVec6.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal6 = new THREE.Vector3(0,0,1); + + const quaternionRotation6 = new THREE.Quaternion(); + quaternionRotation6.setFromUnitVectors(initialNormal6, normalVec6); + + ringMesh6.setRotationFromQuaternion(quaternionRotation6); + + return quaternionRotation6; + } + + ringRoot.add(ringMesh6); + + var inradius7 = calulateInradius(getVertex2(), getVertex4(), getVertex8()); + var incenter7 = calulateIncenter(getVertex2(), getVertex4(), getVertex8()); + var ringGeometry7 = new THREE.RingGeometry((inradius7 - 0.005),inradius7, 32); + const ringMaterial7 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh7 = new THREE.Mesh(ringGeometry7, ringMaterial7); + + function setCircleRotation7(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.42532540400000002,0.85065080849999997,0.],[ -0.044902797600000002,-0.027751455099999999,0.085410196499999994],[-0.42532540400000002,0.68819096040000005,-0.49999999979999998]); + + ringMesh7.position.setX(incenter[0]); + ringMesh7.position.setY(incenter[1]); + ringMesh7.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex2(), getVertex4(), getVertex8()); + var relRadius = inradius/inradius7; + + ringMesh7.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A7 = new THREE.Vector3(0.42532540400000002,0.85065080849999997,0.); + const B7 = new THREE.Vector3(-0.044902797600000002,-0.027751455099999999,0.085410196499999994); + const C7 = new THREE.Vector3(-0.42532540400000002,0.68819096040000005,-0.49999999979999998); + + const normalVec7 = new THREE.Vector3(); + normalVec7.crossVectors(B7.sub(A7), C7.sub(A7)); + normalVec7.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal7 = new THREE.Vector3(0,0,1); + + const quaternionRotation7 = new THREE.Quaternion(); + quaternionRotation7.setFromUnitVectors(initialNormal7, normalVec7); + + ringMesh7.setRotationFromQuaternion(quaternionRotation7); + + return quaternionRotation7; + } + + ringRoot.add(ringMesh7); + + var inradius8 = calulateInradius(getVertex4(), getVertex5(), getVertex9()); + var incenter8 = calulateIncenter(getVertex4(), getVertex5(), getVertex9()); + var ringGeometry8 = new THREE.RingGeometry((inradius8 - 0.005),inradius8, 32); + const ringMaterial8 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh8 = new THREE.Mesh(ringGeometry8, ringMaterial8); + + function setCircleRotation8(){ + + //translate ring to incenter + var incenter = calulateIncenter([-0.044902797600000002,-0.027751455099999999,0.085410196499999994],[ 0.42532540400000002,-0.68819096040000005,-0.49999999979999998],[-0.42532540400000002,-0.262865556,-0.80901699400000004]); + + ringMesh8.position.setX(incenter[0]); + ringMesh8.position.setY(incenter[1]); + ringMesh8.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex4(), getVertex5(), getVertex9()); + var relRadius = inradius/inradius8; + + ringMesh8.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A8 = new THREE.Vector3(-0.044902797600000002,-0.027751455099999999,0.085410196499999994); + const B8 = new THREE.Vector3(0.42532540400000002,-0.68819096040000005,-0.49999999979999998); + const C8 = new THREE.Vector3(-0.42532540400000002,-0.262865556,-0.80901699400000004); + + const normalVec8 = new THREE.Vector3(); + normalVec8.crossVectors(B8.sub(A8), C8.sub(A8)); + normalVec8.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal8 = new THREE.Vector3(0,0,1); + + const quaternionRotation8 = new THREE.Quaternion(); + quaternionRotation8.setFromUnitVectors(initialNormal8, normalVec8); + + ringMesh8.setRotationFromQuaternion(quaternionRotation8); + + return quaternionRotation8; + } + + ringRoot.add(ringMesh8); + + var inradius9 = calulateInradius(getVertex5(), getVertex6(), getVertex10()); + var incenter9 = calulateIncenter(getVertex5(), getVertex6(), getVertex10()); + var ringGeometry9 = new THREE.RingGeometry((inradius9 - 0.005),inradius9, 32); + const ringMaterial9 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh9 = new THREE.Mesh(ringGeometry9, ringMaterial9); + + function setCircleRotation9(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.42532540400000002,-0.68819096040000005,-0.49999999979999998],[ 0.42532540400000002,-0.68819096040000005,0.49999999979999998],[-0.42532540400000002,-0.85065080849999997,0.]); + + ringMesh9.position.setX(incenter[0]); + ringMesh9.position.setY(incenter[1]); + ringMesh9.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex5(), getVertex6(), getVertex10()); + var relRadius = inradius/inradius9; + + ringMesh9.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A9 = new THREE.Vector3(0.42532540400000002,-0.68819096040000005,-0.49999999979999998); + const B9 = new THREE.Vector3(0.42532540400000002,-0.68819096040000005,0.49999999979999998); + const C9 = new THREE.Vector3(-0.42532540400000002,-0.85065080849999997,0.); + + const normalVec9 = new THREE.Vector3(); + normalVec9.crossVectors(B9.sub(A9), C9.sub(A9)); + normalVec9.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal9 = new THREE.Vector3(0,0,1); + + const quaternionRotation9 = new THREE.Quaternion(); + quaternionRotation9.setFromUnitVectors(initialNormal9, normalVec9); + + ringMesh9.setRotationFromQuaternion(quaternionRotation9); + + return quaternionRotation9; + } + + ringRoot.add(ringMesh9); + + var inradius10 = calulateInradius(getVertex3(), getVertex6(), getVertex11()); + var incenter10 = calulateIncenter(getVertex3(), getVertex6(), getVertex11()); + var ringGeometry10 = new THREE.RingGeometry((inradius10 - 0.005),inradius10, 32); + const ringMaterial10 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh10 = new THREE.Mesh(ringGeometry10, ringMaterial10); + + function setCircleRotation10(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.42532540400000002,0.262865556,0.80901699400000004],[ 0.42532540400000002,-0.68819096040000005,0.49999999979999998],[0.044902797600000002,0.027751455099999999,-0.085410196499999994]); + + ringMesh10.position.setX(incenter[0]); + ringMesh10.position.setY(incenter[1]); + ringMesh10.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex3(), getVertex6(), getVertex11()); + var relRadius = inradius/inradius10; + + ringMesh10.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A10 = new THREE.Vector3(0.42532540400000002,0.262865556,0.80901699400000004); + const B10 = new THREE.Vector3(0.42532540400000002,-0.68819096040000005,0.49999999979999998); + const C10 = new THREE.Vector3(0.044902797600000002,0.027751455099999999,-0.085410196499999994); + + const normalVec10 = new THREE.Vector3(); + normalVec10.crossVectors(B10.sub(A10), C10.sub(A10)); + normalVec10.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal10 = new THREE.Vector3(0,0,1); + + const quaternionRotation10 = new THREE.Quaternion(); + quaternionRotation10.setFromUnitVectors(initialNormal10, normalVec10); + + ringMesh10.setRotationFromQuaternion(quaternionRotation10); + + return quaternionRotation10; + } + + ringRoot.add(ringMesh10); + + var inradius11 = calulateInradius(getVertex2(), getVertex7(), getVertex8()); + var incenter11 = calulateIncenter(getVertex2(), getVertex7(), getVertex8()); + var ringGeometry11 = new THREE.RingGeometry((inradius11 - 0.005),inradius11, 32); + const ringMaterial11 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh11 = new THREE.Mesh(ringGeometry11, ringMaterial11); + + function setCircleRotation11(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.42532540400000002,0.85065080849999997,0.],[ -0.42532540400000002,0.68819096040000005,0.49999999979999998],[-0.42532540400000002,0.68819096040000005,-0.49999999979999998]); + + ringMesh11.position.setX(incenter[0]); + ringMesh11.position.setY(incenter[1]); + ringMesh11.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex2(), getVertex7(), getVertex8()); + var relRadius = inradius/inradius11; + + ringMesh11.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A11 = new THREE.Vector3(0.42532540400000002,0.85065080849999997,0.); + const B11 = new THREE.Vector3(-0.42532540400000002,0.68819096040000005,0.49999999979999998); + const C11 = new THREE.Vector3(-0.42532540400000002,0.68819096040000005,-0.49999999979999998); + + const normalVec11 = new THREE.Vector3(); + normalVec11.crossVectors(B11.sub(A11), C11.sub(A11)); + normalVec11.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal11 = new THREE.Vector3(0,0,1); + + const quaternionRotation11 = new THREE.Quaternion(); + quaternionRotation11.setFromUnitVectors(initialNormal11, normalVec11); + + ringMesh11.setRotationFromQuaternion(quaternionRotation11); + + return quaternionRotation11; + } + + ringRoot.add(ringMesh11); + + var inradius12 = calulateInradius(getVertex4(), getVertex8(), getVertex9()); + var incenter12 = calulateIncenter(getVertex4(), getVertex8(), getVertex9()); + var ringGeometry12 = new THREE.RingGeometry((inradius12 - 0.005),inradius12, 32); + const ringMaterial12 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh12 = new THREE.Mesh(ringGeometry12, ringMaterial12); + + function setCircleRotation12(){ + + //translate ring to incenter + var incenter = calulateIncenter([-0.044902797600000002,-0.027751455099999999,0.085410196499999994],[ -0.42532540400000002,0.68819096040000005,-0.49999999979999998],[-0.42532540400000002,-0.262865556,-0.80901699400000004]); + + ringMesh12.position.setX(incenter[0]); + ringMesh12.position.setY(incenter[1]); + ringMesh12.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex4(), getVertex8(), getVertex9()); + var relRadius = inradius/inradius12; + + ringMesh12.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A12 = new THREE.Vector3(-0.044902797600000002,-0.027751455099999999,0.085410196499999994); + const B12 = new THREE.Vector3(-0.42532540400000002,0.68819096040000005,-0.49999999979999998); + const C12 = new THREE.Vector3(-0.42532540400000002,-0.262865556,-0.80901699400000004); + + const normalVec12 = new THREE.Vector3(); + normalVec12.crossVectors(B12.sub(A12), C12.sub(A12)); + normalVec12.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal12 = new THREE.Vector3(0,0,1); + + const quaternionRotation12 = new THREE.Quaternion(); + quaternionRotation12.setFromUnitVectors(initialNormal12, normalVec12); + + ringMesh12.setRotationFromQuaternion(quaternionRotation12); + + return quaternionRotation12; + } + + ringRoot.add(ringMesh12); + + var inradius13 = calulateInradius(getVertex5(), getVertex9(), getVertex10()); + var incenter13 = calulateIncenter(getVertex5(), getVertex9(), getVertex10()); + var ringGeometry13 = new THREE.RingGeometry((inradius13 - 0.005),inradius13, 32); + const ringMaterial13 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh13 = new THREE.Mesh(ringGeometry13, ringMaterial13); + + function setCircleRotation13(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.42532540400000002,-0.68819096040000005,-0.49999999979999998],[ -0.42532540400000002,-0.262865556,-0.80901699400000004],[-0.42532540400000002,-0.85065080849999997,0.]); + + ringMesh13.position.setX(incenter[0]); + ringMesh13.position.setY(incenter[1]); + ringMesh13.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex5(), getVertex9(), getVertex10()); + var relRadius = inradius/inradius13; + + ringMesh13.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A13 = new THREE.Vector3(0.42532540400000002,-0.68819096040000005,-0.49999999979999998); + const B13 = new THREE.Vector3(-0.42532540400000002,-0.262865556,-0.80901699400000004); + const C13 = new THREE.Vector3(-0.42532540400000002,-0.85065080849999997,0.); + + const normalVec13 = new THREE.Vector3(); + normalVec13.crossVectors(B13.sub(A13), C13.sub(A13)); + normalVec13.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal13 = new THREE.Vector3(0,0,1); + + const quaternionRotation13 = new THREE.Quaternion(); + quaternionRotation13.setFromUnitVectors(initialNormal13, normalVec13); + + ringMesh13.setRotationFromQuaternion(quaternionRotation13); + + return quaternionRotation13; + } + + ringRoot.add(ringMesh13); + + var inradius14 = calulateInradius(getVertex6(), getVertex10(), getVertex11()); + var incenter14 = calulateIncenter(getVertex6(), getVertex10(), getVertex11()); + var ringGeometry14 = new THREE.RingGeometry((inradius14 - 0.005),inradius14, 32); + const ringMaterial14 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh14 = new THREE.Mesh(ringGeometry14, ringMaterial14); + + function setCircleRotation14(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.42532540400000002,-0.68819096040000005,0.49999999979999998],[ -0.42532540400000002,-0.85065080849999997,0.],[0.044902797600000002,0.027751455099999999,-0.085410196499999994]); + + ringMesh14.position.setX(incenter[0]); + ringMesh14.position.setY(incenter[1]); + ringMesh14.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex6(), getVertex10(), getVertex11()); + var relRadius = inradius/inradius14; + + ringMesh14.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A14 = new THREE.Vector3(0.42532540400000002,-0.68819096040000005,0.49999999979999998); + const B14 = new THREE.Vector3(-0.42532540400000002,-0.85065080849999997,0.); + const C14 = new THREE.Vector3(0.044902797600000002,0.027751455099999999,-0.085410196499999994); + + const normalVec14 = new THREE.Vector3(); + normalVec14.crossVectors(B14.sub(A14), C14.sub(A14)); + normalVec14.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal14 = new THREE.Vector3(0,0,1); + + const quaternionRotation14 = new THREE.Quaternion(); + quaternionRotation14.setFromUnitVectors(initialNormal14, normalVec14); + + ringMesh14.setRotationFromQuaternion(quaternionRotation14); + + return quaternionRotation14; + } + + ringRoot.add(ringMesh14); + + var inradius15 = calulateInradius(getVertex3(), getVertex7(), getVertex11()); + var incenter15 = calulateIncenter(getVertex3(), getVertex7(), getVertex11()); + var ringGeometry15 = new THREE.RingGeometry((inradius15 - 0.005),inradius15, 32); + const ringMaterial15 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh15 = new THREE.Mesh(ringGeometry15, ringMaterial15); + + function setCircleRotation15(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.42532540400000002,0.262865556,0.80901699400000004],[ -0.42532540400000002,0.68819096040000005,0.49999999979999998],[0.044902797600000002,0.027751455099999999,-0.085410196499999994]); + + ringMesh15.position.setX(incenter[0]); + ringMesh15.position.setY(incenter[1]); + ringMesh15.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex3(), getVertex7(), getVertex11()); + var relRadius = inradius/inradius15; + + ringMesh15.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A15 = new THREE.Vector3(0.42532540400000002,0.262865556,0.80901699400000004); + const B15 = new THREE.Vector3(-0.42532540400000002,0.68819096040000005,0.49999999979999998); + const C15 = new THREE.Vector3(0.044902797600000002,0.027751455099999999,-0.085410196499999994); + + const normalVec15 = new THREE.Vector3(); + normalVec15.crossVectors(B15.sub(A15), C15.sub(A15)); + normalVec15.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal15 = new THREE.Vector3(0,0,1); + + const quaternionRotation15 = new THREE.Quaternion(); + quaternionRotation15.setFromUnitVectors(initialNormal15, normalVec15); + + ringMesh15.setRotationFromQuaternion(quaternionRotation15); + + return quaternionRotation15; + } + + ringRoot.add(ringMesh15); + + var inradius16 = calulateInradius(getVertex7(), getVertex8(), getVertex12()); + var incenter16 = calulateIncenter(getVertex7(), getVertex8(), getVertex12()); + var ringGeometry16 = new THREE.RingGeometry((inradius16 - 0.005),inradius16, 32); + const ringMaterial16 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh16 = new THREE.Mesh(ringGeometry16, ringMaterial16); + + function setCircleRotation16(){ + + //translate ring to incenter + var incenter = calulateIncenter([-0.42532540400000002,0.68819096040000005,0.49999999979999998],[ -0.42532540400000002,0.68819096040000005,-0.49999999979999998],[-0.95105651599999996,0.,0.]); + + ringMesh16.position.setX(incenter[0]); + ringMesh16.position.setY(incenter[1]); + ringMesh16.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex7(), getVertex8(), getVertex12()); + var relRadius = inradius/inradius16; + + ringMesh16.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A16 = new THREE.Vector3(-0.42532540400000002,0.68819096040000005,0.49999999979999998); + const B16 = new THREE.Vector3(-0.42532540400000002,0.68819096040000005,-0.49999999979999998); + const C16 = new THREE.Vector3(-0.95105651599999996,0.,0.); + + const normalVec16 = new THREE.Vector3(); + normalVec16.crossVectors(B16.sub(A16), C16.sub(A16)); + normalVec16.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal16 = new THREE.Vector3(0,0,1); + + const quaternionRotation16 = new THREE.Quaternion(); + quaternionRotation16.setFromUnitVectors(initialNormal16, normalVec16); + + ringMesh16.setRotationFromQuaternion(quaternionRotation16); + + return quaternionRotation16; + } + + ringRoot.add(ringMesh16); + + var inradius17 = calulateInradius(getVertex8(), getVertex9(), getVertex12()); + var incenter17 = calulateIncenter(getVertex8(), getVertex9(), getVertex12()); + var ringGeometry17 = new THREE.RingGeometry((inradius17 - 0.005),inradius17, 32); + const ringMaterial17 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh17 = new THREE.Mesh(ringGeometry17, ringMaterial17); + + function setCircleRotation17(){ + + //translate ring to incenter + var incenter = calulateIncenter([-0.42532540400000002,0.68819096040000005,-0.49999999979999998],[ -0.42532540400000002,-0.262865556,-0.80901699400000004],[-0.95105651599999996,0.,0.]); + + ringMesh17.position.setX(incenter[0]); + ringMesh17.position.setY(incenter[1]); + ringMesh17.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex8(), getVertex9(), getVertex12()); + var relRadius = inradius/inradius17; + + ringMesh17.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A17 = new THREE.Vector3(-0.42532540400000002,0.68819096040000005,-0.49999999979999998); + const B17 = new THREE.Vector3(-0.42532540400000002,-0.262865556,-0.80901699400000004); + const C17 = new THREE.Vector3(-0.95105651599999996,0.,0.); + + const normalVec17 = new THREE.Vector3(); + normalVec17.crossVectors(B17.sub(A17), C17.sub(A17)); + normalVec17.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal17 = new THREE.Vector3(0,0,1); + + const quaternionRotation17 = new THREE.Quaternion(); + quaternionRotation17.setFromUnitVectors(initialNormal17, normalVec17); + + ringMesh17.setRotationFromQuaternion(quaternionRotation17); + + return quaternionRotation17; + } + + ringRoot.add(ringMesh17); + + var inradius18 = calulateInradius(getVertex9(), getVertex10(), getVertex12()); + var incenter18 = calulateIncenter(getVertex9(), getVertex10(), getVertex12()); + var ringGeometry18 = new THREE.RingGeometry((inradius18 - 0.005),inradius18, 32); + const ringMaterial18 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh18 = new THREE.Mesh(ringGeometry18, ringMaterial18); + + function setCircleRotation18(){ + + //translate ring to incenter + var incenter = calulateIncenter([-0.42532540400000002,-0.262865556,-0.80901699400000004],[ -0.42532540400000002,-0.85065080849999997,0.],[-0.95105651599999996,0.,0.]); + + ringMesh18.position.setX(incenter[0]); + ringMesh18.position.setY(incenter[1]); + ringMesh18.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex9(), getVertex10(), getVertex12()); + var relRadius = inradius/inradius18; + + ringMesh18.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A18 = new THREE.Vector3(-0.42532540400000002,-0.262865556,-0.80901699400000004); + const B18 = new THREE.Vector3(-0.42532540400000002,-0.85065080849999997,0.); + const C18 = new THREE.Vector3(-0.95105651599999996,0.,0.); + + const normalVec18 = new THREE.Vector3(); + normalVec18.crossVectors(B18.sub(A18), C18.sub(A18)); + normalVec18.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal18 = new THREE.Vector3(0,0,1); + + const quaternionRotation18 = new THREE.Quaternion(); + quaternionRotation18.setFromUnitVectors(initialNormal18, normalVec18); + + ringMesh18.setRotationFromQuaternion(quaternionRotation18); + + return quaternionRotation18; + } + + ringRoot.add(ringMesh18); + + var inradius19 = calulateInradius(getVertex10(), getVertex11(), getVertex12()); + var incenter19 = calulateIncenter(getVertex10(), getVertex11(), getVertex12()); + var ringGeometry19 = new THREE.RingGeometry((inradius19 - 0.005),inradius19, 32); + const ringMaterial19 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh19 = new THREE.Mesh(ringGeometry19, ringMaterial19); + + function setCircleRotation19(){ + + //translate ring to incenter + var incenter = calulateIncenter([-0.42532540400000002,-0.85065080849999997,0.],[ 0.044902797600000002,0.027751455099999999,-0.085410196499999994],[-0.95105651599999996,0.,0.]); + + ringMesh19.position.setX(incenter[0]); + ringMesh19.position.setY(incenter[1]); + ringMesh19.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex10(), getVertex11(), getVertex12()); + var relRadius = inradius/inradius19; + + ringMesh19.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A19 = new THREE.Vector3(-0.42532540400000002,-0.85065080849999997,0.); + const B19 = new THREE.Vector3(0.044902797600000002,0.027751455099999999,-0.085410196499999994); + const C19 = new THREE.Vector3(-0.95105651599999996,0.,0.); + + const normalVec19 = new THREE.Vector3(); + normalVec19.crossVectors(B19.sub(A19), C19.sub(A19)); + normalVec19.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal19 = new THREE.Vector3(0,0,1); + + const quaternionRotation19 = new THREE.Quaternion(); + quaternionRotation19.setFromUnitVectors(initialNormal19, normalVec19); + + ringMesh19.setRotationFromQuaternion(quaternionRotation19); + + return quaternionRotation19; + } + + ringRoot.add(ringMesh19); + + var inradius20 = calulateInradius(getVertex7(), getVertex11(), getVertex12()); + var incenter20 = calulateIncenter(getVertex7(), getVertex11(), getVertex12()); + var ringGeometry20 = new THREE.RingGeometry((inradius20 - 0.005),inradius20, 32); + const ringMaterial20 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh20 = new THREE.Mesh(ringGeometry20, ringMaterial20); + + function setCircleRotation20(){ + + //translate ring to incenter + var incenter = calulateIncenter([-0.42532540400000002,0.68819096040000005,0.49999999979999998],[ 0.044902797600000002,0.027751455099999999,-0.085410196499999994],[-0.95105651599999996,0.,0.]); + + ringMesh20.position.setX(incenter[0]); + ringMesh20.position.setY(incenter[1]); + ringMesh20.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex7(), getVertex11(), getVertex12()); + var relRadius = inradius/inradius20; + + ringMesh20.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A20 = new THREE.Vector3(-0.42532540400000002,0.68819096040000005,0.49999999979999998); + const B20 = new THREE.Vector3(0.044902797600000002,0.027751455099999999,-0.085410196499999994); + const C20 = new THREE.Vector3(-0.95105651599999996,0.,0.); + + const normalVec20 = new THREE.Vector3(); + normalVec20.crossVectors(B20.sub(A20), C20.sub(A20)); + normalVec20.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal20 = new THREE.Vector3(0,0,1); + + const quaternionRotation20 = new THREE.Quaternion(); + quaternionRotation20.setFromUnitVectors(initialNormal20, normalVec20); + + ringMesh20.setRotationFromQuaternion(quaternionRotation20); + + return quaternionRotation20; + } + + ringRoot.add(ringMesh20); + // function to update the circles every frame + function updateCircles(){ + setCircleRotation1(); + setCircleRotation2(); + setCircleRotation3(); + setCircleRotation4(); + setCircleRotation5(); + setCircleRotation6(); + setCircleRotation7(); + setCircleRotation8(); + setCircleRotation9(); + setCircleRotation10(); + setCircleRotation11(); + setCircleRotation12(); + setCircleRotation13(); + setCircleRotation14(); + setCircleRotation15(); + setCircleRotation16(); + setCircleRotation17(); + setCircleRotation18(); + setCircleRotation19(); + setCircleRotation20(); + } + + // needs to be called once to be initialized + updateCircles(); + + // function to update the circles width, that is called every frame even if the surface is not parameterized + function updateCircleWidth(){ + ringGeometry1.dispose(); + ringGeometry1 = new THREE.RingGeometry((inradius1 - guiParameters.circleWidth),inradius1, 32); + ringMesh1.geometry = ringGeometry1; + ringGeometry2.dispose(); + ringGeometry2 = new THREE.RingGeometry((inradius2 - guiParameters.circleWidth),inradius2, 32); + ringMesh2.geometry = ringGeometry2; + ringGeometry3.dispose(); + ringGeometry3 = new THREE.RingGeometry((inradius3 - guiParameters.circleWidth),inradius3, 32); + ringMesh3.geometry = ringGeometry3; + ringGeometry4.dispose(); + ringGeometry4 = new THREE.RingGeometry((inradius4 - guiParameters.circleWidth),inradius4, 32); + ringMesh4.geometry = ringGeometry4; + ringGeometry5.dispose(); + ringGeometry5 = new THREE.RingGeometry((inradius5 - guiParameters.circleWidth),inradius5, 32); + ringMesh5.geometry = ringGeometry5; + ringGeometry6.dispose(); + ringGeometry6 = new THREE.RingGeometry((inradius6 - guiParameters.circleWidth),inradius6, 32); + ringMesh6.geometry = ringGeometry6; + ringGeometry7.dispose(); + ringGeometry7 = new THREE.RingGeometry((inradius7 - guiParameters.circleWidth),inradius7, 32); + ringMesh7.geometry = ringGeometry7; + ringGeometry8.dispose(); + ringGeometry8 = new THREE.RingGeometry((inradius8 - guiParameters.circleWidth),inradius8, 32); + ringMesh8.geometry = ringGeometry8; + ringGeometry9.dispose(); + ringGeometry9 = new THREE.RingGeometry((inradius9 - guiParameters.circleWidth),inradius9, 32); + ringMesh9.geometry = ringGeometry9; + ringGeometry10.dispose(); + ringGeometry10 = new THREE.RingGeometry((inradius10 - guiParameters.circleWidth),inradius10, 32); + ringMesh10.geometry = ringGeometry10; + ringGeometry11.dispose(); + ringGeometry11 = new THREE.RingGeometry((inradius11 - guiParameters.circleWidth),inradius11, 32); + ringMesh11.geometry = ringGeometry11; + ringGeometry12.dispose(); + ringGeometry12 = new THREE.RingGeometry((inradius12 - guiParameters.circleWidth),inradius12, 32); + ringMesh12.geometry = ringGeometry12; + ringGeometry13.dispose(); + ringGeometry13 = new THREE.RingGeometry((inradius13 - guiParameters.circleWidth),inradius13, 32); + ringMesh13.geometry = ringGeometry13; + ringGeometry14.dispose(); + ringGeometry14 = new THREE.RingGeometry((inradius14 - guiParameters.circleWidth),inradius14, 32); + ringMesh14.geometry = ringGeometry14; + ringGeometry15.dispose(); + ringGeometry15 = new THREE.RingGeometry((inradius15 - guiParameters.circleWidth),inradius15, 32); + ringMesh15.geometry = ringGeometry15; + ringGeometry16.dispose(); + ringGeometry16 = new THREE.RingGeometry((inradius16 - guiParameters.circleWidth),inradius16, 32); + ringMesh16.geometry = ringGeometry16; + ringGeometry17.dispose(); + ringGeometry17 = new THREE.RingGeometry((inradius17 - guiParameters.circleWidth),inradius17, 32); + ringMesh17.geometry = ringGeometry17; + ringGeometry18.dispose(); + ringGeometry18 = new THREE.RingGeometry((inradius18 - guiParameters.circleWidth),inradius18, 32); + ringMesh18.geometry = ringGeometry18; + ringGeometry19.dispose(); + ringGeometry19 = new THREE.RingGeometry((inradius19 - guiParameters.circleWidth),inradius19, 32); + ringMesh19.geometry = ringGeometry19; + ringGeometry20.dispose(); + ringGeometry20 = new THREE.RingGeometry((inradius20 - guiParameters.circleWidth),inradius20, 32); + ringMesh20.geometry = ringGeometry20; + } + + updateCircleWidth(); + + // generate the normals trough the incenter orthogonal to the face + // getNormalsVectors generates the coordinates for the current values of the parameterized surface + function getNormalsVectors(){ + var vector1; + var vector2; + + var normals = []; + vector1 = []; + vector2 = []; + vector1[0] = (0.425325404)-(0.951056516); + vector1[1] = (0.8506508085)-(0.); + vector1[2] = (0.)-(0.); + + vector2[0] = (0.425325404)-(0.951056516); + vector2[1] = (0.262865556)-(0.); + vector2[2] = (0.809016994)-(0.); + + var incenter = calulateIncenter([0.95105651599999996,0.,0.],[ 0.42532540400000002,0.85065080849999997,0.],[0.42532540400000002,0.262865556,0.80901699400000004]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.425325404)-(0.951056516); + vector1[1] = (0.8506508085)-(0.); + vector1[2] = (0.)-(0.); + + vector2[0] = (-0.0449027976)-(0.951056516); + vector2[1] = (-0.0277514551)-(0.); + vector2[2] = (0.08541019649999999)-(0.); + + var incenter = calulateIncenter([0.95105651599999996,0.,0.],[ 0.42532540400000002,0.85065080849999997,0.],[-0.044902797600000002,-0.027751455099999999,0.085410196499999994]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (-0.0449027976)-(0.951056516); + vector1[1] = (-0.0277514551)-(0.); + vector1[2] = (0.08541019649999999)-(0.); + + vector2[0] = (0.425325404)-(0.951056516); + vector2[1] = (-0.6881909604000001)-(0.); + vector2[2] = (-0.4999999998)-(0.); + + var incenter = calulateIncenter([0.95105651599999996,0.,0.],[ -0.044902797600000002,-0.027751455099999999,0.085410196499999994],[0.42532540400000002,-0.68819096040000005,-0.49999999979999998]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.425325404)-(0.951056516); + vector1[1] = (-0.6881909604000001)-(0.); + vector1[2] = (-0.4999999998)-(0.); + + vector2[0] = (0.425325404)-(0.951056516); + vector2[1] = (-0.6881909604000001)-(0.); + vector2[2] = (0.4999999998)-(0.); + + var incenter = calulateIncenter([0.95105651599999996,0.,0.],[ 0.42532540400000002,-0.68819096040000005,-0.49999999979999998],[0.42532540400000002,-0.68819096040000005,0.49999999979999998]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.425325404)-(0.951056516); + vector1[1] = (0.262865556)-(0.); + vector1[2] = (0.809016994)-(0.); + + vector2[0] = (0.425325404)-(0.951056516); + vector2[1] = (-0.6881909604000001)-(0.); + vector2[2] = (0.4999999998)-(0.); + + var incenter = calulateIncenter([0.95105651599999996,0.,0.],[ 0.42532540400000002,0.262865556,0.80901699400000004],[0.42532540400000002,-0.68819096040000005,0.49999999979999998]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.425325404)-(0.425325404); + vector1[1] = (0.262865556)-(0.8506508085); + vector1[2] = (0.809016994)-(0.); + + vector2[0] = (-0.425325404)-(0.425325404); + vector2[1] = (0.6881909604000001)-(0.8506508085); + vector2[2] = (0.4999999998)-(0.); + + var incenter = calulateIncenter([0.42532540400000002,0.85065080849999997,0.],[ 0.42532540400000002,0.262865556,0.80901699400000004],[-0.42532540400000002,0.68819096040000005,0.49999999979999998]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (-0.0449027976)-(0.425325404); + vector1[1] = (-0.0277514551)-(0.8506508085); + vector1[2] = (0.08541019649999999)-(0.); + + vector2[0] = (-0.425325404)-(0.425325404); + vector2[1] = (0.6881909604000001)-(0.8506508085); + vector2[2] = (-0.4999999998)-(0.); + + var incenter = calulateIncenter([0.42532540400000002,0.85065080849999997,0.],[ -0.044902797600000002,-0.027751455099999999,0.085410196499999994],[-0.42532540400000002,0.68819096040000005,-0.49999999979999998]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.425325404)-(-0.0449027976); + vector1[1] = (-0.6881909604000001)-(-0.0277514551); + vector1[2] = (-0.4999999998)-(0.08541019649999999); + + vector2[0] = (-0.425325404)-(-0.0449027976); + vector2[1] = (-0.262865556)-(-0.0277514551); + vector2[2] = (-0.809016994)-(0.08541019649999999); + + var incenter = calulateIncenter([-0.044902797600000002,-0.027751455099999999,0.085410196499999994],[ 0.42532540400000002,-0.68819096040000005,-0.49999999979999998],[-0.42532540400000002,-0.262865556,-0.80901699400000004]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.425325404)-(0.425325404); + vector1[1] = (-0.6881909604000001)-(-0.6881909604000001); + vector1[2] = (0.4999999998)-(-0.4999999998); + + vector2[0] = (-0.425325404)-(0.425325404); + vector2[1] = (-0.8506508085)-(-0.6881909604000001); + vector2[2] = (0.)-(-0.4999999998); + + var incenter = calulateIncenter([0.42532540400000002,-0.68819096040000005,-0.49999999979999998],[ 0.42532540400000002,-0.68819096040000005,0.49999999979999998],[-0.42532540400000002,-0.85065080849999997,0.]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.425325404)-(0.425325404); + vector1[1] = (-0.6881909604000001)-(0.262865556); + vector1[2] = (0.4999999998)-(0.809016994); + + vector2[0] = (0.0449027976)-(0.425325404); + vector2[1] = (0.0277514551)-(0.262865556); + vector2[2] = (-0.08541019649999999)-(0.809016994); + + var incenter = calulateIncenter([0.42532540400000002,0.262865556,0.80901699400000004],[ 0.42532540400000002,-0.68819096040000005,0.49999999979999998],[0.044902797600000002,0.027751455099999999,-0.085410196499999994]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (-0.425325404)-(0.425325404); + vector1[1] = (0.6881909604000001)-(0.8506508085); + vector1[2] = (0.4999999998)-(0.); + + vector2[0] = (-0.425325404)-(0.425325404); + vector2[1] = (0.6881909604000001)-(0.8506508085); + vector2[2] = (-0.4999999998)-(0.); + + var incenter = calulateIncenter([0.42532540400000002,0.85065080849999997,0.],[ -0.42532540400000002,0.68819096040000005,0.49999999979999998],[-0.42532540400000002,0.68819096040000005,-0.49999999979999998]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (-0.425325404)-(-0.0449027976); + vector1[1] = (0.6881909604000001)-(-0.0277514551); + vector1[2] = (-0.4999999998)-(0.08541019649999999); + + vector2[0] = (-0.425325404)-(-0.0449027976); + vector2[1] = (-0.262865556)-(-0.0277514551); + vector2[2] = (-0.809016994)-(0.08541019649999999); + + var incenter = calulateIncenter([-0.044902797600000002,-0.027751455099999999,0.085410196499999994],[ -0.42532540400000002,0.68819096040000005,-0.49999999979999998],[-0.42532540400000002,-0.262865556,-0.80901699400000004]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (-0.425325404)-(0.425325404); + vector1[1] = (-0.262865556)-(-0.6881909604000001); + vector1[2] = (-0.809016994)-(-0.4999999998); + + vector2[0] = (-0.425325404)-(0.425325404); + vector2[1] = (-0.8506508085)-(-0.6881909604000001); + vector2[2] = (0.)-(-0.4999999998); + + var incenter = calulateIncenter([0.42532540400000002,-0.68819096040000005,-0.49999999979999998],[ -0.42532540400000002,-0.262865556,-0.80901699400000004],[-0.42532540400000002,-0.85065080849999997,0.]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (-0.425325404)-(0.425325404); + vector1[1] = (-0.8506508085)-(-0.6881909604000001); + vector1[2] = (0.)-(0.4999999998); + + vector2[0] = (0.0449027976)-(0.425325404); + vector2[1] = (0.0277514551)-(-0.6881909604000001); + vector2[2] = (-0.08541019649999999)-(0.4999999998); + + var incenter = calulateIncenter([0.42532540400000002,-0.68819096040000005,0.49999999979999998],[ -0.42532540400000002,-0.85065080849999997,0.],[0.044902797600000002,0.027751455099999999,-0.085410196499999994]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (-0.425325404)-(0.425325404); + vector1[1] = (0.6881909604000001)-(0.262865556); + vector1[2] = (0.4999999998)-(0.809016994); + + vector2[0] = (0.0449027976)-(0.425325404); + vector2[1] = (0.0277514551)-(0.262865556); + vector2[2] = (-0.08541019649999999)-(0.809016994); + + var incenter = calulateIncenter([0.42532540400000002,0.262865556,0.80901699400000004],[ -0.42532540400000002,0.68819096040000005,0.49999999979999998],[0.044902797600000002,0.027751455099999999,-0.085410196499999994]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (-0.425325404)-(-0.425325404); + vector1[1] = (0.6881909604000001)-(0.6881909604000001); + vector1[2] = (-0.4999999998)-(0.4999999998); + + vector2[0] = (-0.951056516)-(-0.425325404); + vector2[1] = (0.)-(0.6881909604000001); + vector2[2] = (0.)-(0.4999999998); + + var incenter = calulateIncenter([-0.42532540400000002,0.68819096040000005,0.49999999979999998],[ -0.42532540400000002,0.68819096040000005,-0.49999999979999998],[-0.95105651599999996,0.,0.]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (-0.425325404)-(-0.425325404); + vector1[1] = (-0.262865556)-(0.6881909604000001); + vector1[2] = (-0.809016994)-(-0.4999999998); + + vector2[0] = (-0.951056516)-(-0.425325404); + vector2[1] = (0.)-(0.6881909604000001); + vector2[2] = (0.)-(-0.4999999998); + + var incenter = calulateIncenter([-0.42532540400000002,0.68819096040000005,-0.49999999979999998],[ -0.42532540400000002,-0.262865556,-0.80901699400000004],[-0.95105651599999996,0.,0.]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (-0.425325404)-(-0.425325404); + vector1[1] = (-0.8506508085)-(-0.262865556); + vector1[2] = (0.)-(-0.809016994); + + vector2[0] = (-0.951056516)-(-0.425325404); + vector2[1] = (0.)-(-0.262865556); + vector2[2] = (0.)-(-0.809016994); + + var incenter = calulateIncenter([-0.42532540400000002,-0.262865556,-0.80901699400000004],[ -0.42532540400000002,-0.85065080849999997,0.],[-0.95105651599999996,0.,0.]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.0449027976)-(-0.425325404); + vector1[1] = (0.0277514551)-(-0.8506508085); + vector1[2] = (-0.08541019649999999)-(0.); + + vector2[0] = (-0.951056516)-(-0.425325404); + vector2[1] = (0.)-(-0.8506508085); + vector2[2] = (0.)-(0.); + + var incenter = calulateIncenter([-0.42532540400000002,-0.85065080849999997,0.],[ 0.044902797600000002,0.027751455099999999,-0.085410196499999994],[-0.95105651599999996,0.,0.]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.0449027976)-(-0.425325404); + vector1[1] = (0.0277514551)-(0.6881909604000001); + vector1[2] = (-0.08541019649999999)-(0.4999999998); + + vector2[0] = (-0.951056516)-(-0.425325404); + vector2[1] = (0.)-(0.6881909604000001); + vector2[2] = (0.)-(0.4999999998); + + var incenter = calulateIncenter([-0.42532540400000002,0.68819096040000005,0.49999999979999998],[ 0.044902797600000002,0.027751455099999999,-0.085410196499999994],[-0.95105651599999996,0.,0.]); + normals.push([vector1, vector2, incenter]); + + return normals; + } + // getNormalsCoordinates calculates the right coordinates for the ortogonality and fitting values from the gui + function getNormalsCoordinates(){ + var res = []; + var normals = getNormalsVectors(); + for(var i = 0; i < normals.length; i++){ + var plus = []; + var minus = []; + + minus[0] = normals[i][2][0] - (1/2)*guiParameters.normalsLength*(normals[i][0][1]*normals[i][1][2] - normals[i][0][2]*normals[i][1][1]); + minus[1] = normals[i][2][1] - (1/2)*guiParameters.normalsLength*(normals[i][0][2]*normals[i][1][0] - normals[i][0][0]*normals[i][1][2]); + minus[2] = normals[i][2][2] - (1/2)*guiParameters.normalsLength*(normals[i][0][0]*normals[i][1][1] - normals[i][0][1]*normals[i][1][0]); + + plus[0] = normals[i][2][0] + (1/2)*guiParameters.normalsLength*(normals[i][0][1]*normals[i][1][2] - normals[i][0][2]*normals[i][1][1]); + plus[1] = normals[i][2][1] + (1/2)*guiParameters.normalsLength*(normals[i][0][2]*normals[i][1][0] - normals[i][0][0]*normals[i][1][2]); + plus[2] = normals[i][2][2] + (1/2)*guiParameters.normalsLength*(normals[i][0][0]*normals[i][1][1] - normals[i][0][1]*normals[i][1][0]); + + res.push(minus[0]); + res.push(minus[1]); + res.push(minus[2]); + res.push(plus[0]); + res.push(plus[1]); + res.push(plus[2]); + } + res = Float32Array.from(res); + + + return res; + } + + + const normalsMaterial = new THREE.LineBasicMaterial( { + color: 0x000000, + } ); + + const normalsGeometry = new THREE.BufferGeometry(); + normalsGeometry.setAttribute( 'position', new THREE.BufferAttribute( getNormalsCoordinates(), 3 ) ); + var normalsLine = new THREE.LineSegments( normalsGeometry, normalsMaterial ); + + function updateNormals(){ + normalsGeometry.setAttribute( 'position', new THREE.BufferAttribute( getNormalsCoordinates(), 3 ) ); + normalsLine = new THREE.LineSegments( normalsGeometry, normalsMaterial ); + } + + normalsRoot.add(normalsLine); + + + // generate automatic ranges for the intersections if the surface is not parameterized + guiParameters.maxX = 0.951056516; + guiParameters.maxY = 0.8506508085; + guiParameters.maxZ = 0.809016994; + guiParameters.minX = -0.951056516; + guiParameters.minY = -0.8506508085; + guiParameters.minZ = -0.809016994; + + guiParameters.planeX = 0.; + guiParameters.planeY = 0.; + guiParameters.planeZ = 0.; + // --- end of generated output --- // + + const planeFolder = gui.addFolder("Intersection Planes"); + planeFolder.add(guiParameters, 'planeXactive'); + planeFolder.add(guiParameters, 'planeX', guiParameters.minX*1.1, guiParameters.maxX*1.1); + planeFolder.add(guiParameters, 'planeYactive'); + planeFolder.add(guiParameters, 'planeY', guiParameters.minY*1.1, guiParameters.maxY*1.1); + planeFolder.add(guiParameters, 'planeZactive'); + planeFolder.add(guiParameters, 'planeZ', guiParameters.minZ*1.1, guiParameters.maxZ*1.1); + + camera.position.z = Math.max((1.5)*guiParameters.minZ, 1) + camera.lookAt(0,0,-1); + + scene.background = new THREE.Color( 'white' ); + + // add both roots to the scene + scene.add( meshRoot ); + scene.add( wireRoot ); + scene.add( vertexRoot ); + scene.add( vertexlabelRoot ); + scene.add( edgeRoot ); + scene.add( ringRoot ); + scene.add( normalsRoot ); + scene.add( normalMeshRoot ); + + //presave some current gui parameters to only update if they change + var currentCircleWidth = guiParameters.circleWidth; + + function animate() { + requestAnimationFrame( animate ); + meshRoot.rotation.x += guiParameters.speedX/100; + meshRoot.rotation.y += guiParameters.speedY/100; + meshRoot.rotation.z += guiParameters.speedZ/100; + + wireRoot.rotation.x += guiParameters.speedX/100; + wireRoot.rotation.y += guiParameters.speedY/100; + wireRoot.rotation.z += guiParameters.speedZ/100; + + vertexRoot.rotation.x += guiParameters.speedX/100; + vertexRoot.rotation.y += guiParameters.speedY/100; + vertexRoot.rotation.z += guiParameters.speedZ/100; + + vertexlabelRoot.rotation.x += guiParameters.speedX/100; + vertexlabelRoot.rotation.y += guiParameters.speedY/100; + vertexlabelRoot.rotation.z += guiParameters.speedZ/100; + + edgeRoot.rotation.x += guiParameters.speedX/100; + edgeRoot.rotation.y += guiParameters.speedY/100; + edgeRoot.rotation.z += guiParameters.speedZ/100; + + ringRoot.rotation.x += guiParameters.speedX/100; + ringRoot.rotation.y += guiParameters.speedY/100; + ringRoot.rotation.z += guiParameters.speedZ/100; + + normalsRoot.rotation.x += guiParameters.speedX/100; + normalsRoot.rotation.y += guiParameters.speedY/100; + normalsRoot.rotation.z += guiParameters.speedZ/100; + + normalMeshRoot.rotation.x += guiParameters.speedX/100; + normalMeshRoot.rotation.y += guiParameters.speedY/100; + normalMeshRoot.rotation.z += guiParameters.speedZ/100; + + //update the light when the camera moves (with orbitcontrols) + light.position.set(camera.position.x, camera.position.y, camera.position.z); + + planeX.constant = guiParameters.planeX; + planeY.constant = guiParameters.planeY; + planeZ.constant = guiParameters.planeZ; + + activePlanes = []; + if(guiParameters.planeXactive){ + activePlanes.push(planeX); + } + if(guiParameters.planeYactive){ + activePlanes.push(planeY); + } + if(guiParameters.planeZactive){ + activePlanes.push(planeZ); + } + + if(vertexParametriziation){ + updateFaceCoordinates(); + if(guiParameters.edgeVisibility){ + updateEdgeCoordinates(); + } + if(guiParameters.vertexlabelVisibility || guiParameters.vertexVisibility){ + updateVertexCoordinates(); + } + if(guiParameters.circleVisibility){ + updateCircles(); + } + } + + //update stuff that changes from the gui + meshRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.opacity = guiParameters.transparency; + node.material.clippingPlanes = activePlanes; + if(guiParameters.normalsMaterial){ + node.material.opacity = 0; + } + } + } ); + + normalMeshRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.opacity = guiParameters.transparency; + node.material.clippingPlanes = activePlanes; + if(!guiParameters.normalsMaterial){ + node.material.opacity = 0; + } + } + } ); + + edgeRoot.traverse( function( node ) { + if ( node instanceof Line2 ) { + node.material.visible = guiParameters.edgeVisibility; + node.material.linewidth = guiParameters.edgeWidth/100; + } + if ( node instanceof THREE.LineSegments ) { + node.material.visible = guiParameters.edgeVisibility; + } + } ); + + vertexRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.visible = guiParameters.vertexVisibility; + node.scale.setScalar(guiParameters.vertexSize); + } + } ); + + vertexlabelRoot.traverse( function( node ) { + if( node instanceof CSS2DObject) { + node.visible = guiParameters.vertexlabelVisibility; + } + } ); + + ringRoot.traverse( function( node ) { + if( node instanceof THREE.Mesh) { + node.visible = guiParameters.circleVisibility; + } + } ); + + normalsRoot.traverse( function( node ) { + if( node instanceof THREE.LineSegments) { + node.visible = guiParameters.normalsVisibility; + } + } ); + + // update the circle width + if(guiParameters.circleVisibility && currentCircleWidth != guiParameters.circleWidth){ + updateCircleWidth(); + currentCircleWidth = guiParameters.circleWidth; + } + + //update the normals length + if(guiParameters.normalsVisibility){ + updateNormals(); + } + + controls.update(); + + renderer.localClippingEnabled = true; + + renderer.render( scene, camera ); + labelRenderer.render( scene, camera ); + } + animate(); + + //resize of window size changes + window.addEventListener( 'resize', onWindowResize ); + function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + labelRenderer.setSize( window.innerWidth, window.innerHeight ); + } +</script> + +</body> +</html> \ No newline at end of file diff --git a/htmls/ramified1.html b/htmls/ramified1.html new file mode 100644 index 0000000000000000000000000000000000000000..8f6197e8536a97c2e8fff9f1efbcfb171129d36b --- /dev/null +++ b/htmls/ramified1.html @@ -0,0 +1,919 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>SimplicialSurface</title> + <style> + body { margin: 0; } + </style> + + + </head> + <body> + +<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> + + +<script type="importmap"> + { + "imports": { + "three": "https://unpkg.com/three@0.148.0/build/three.module.js", + "three/addons/": "https://unpkg.com/three@0.148.0/examples/jsm/", + "gui": "https://unpkg.com/dat.gui@0.7.9/build/dat.gui.module.js" + } + } +</script> + + +<script type="module"> + import * as THREE from 'three'; + import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + import { GUI } from 'gui'; + import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js'; + import { Line2 } from 'three/addons/lines/Line2.js'; + import { LineMaterial } from 'three/addons/lines/LineMaterial.js'; + import { LineGeometry } from 'three/addons/lines/LineGeometry.js'; + + //start scene and camera + const scene = new THREE.Scene(); + const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 100 ); + + const renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setSize( window.innerWidth, window.innerHeight ); + document.body.appendChild( renderer.domElement ); + + //Lights + const skyColor = 0xFFFFFF; + const skyIntensity = 0.3; + const skyLight = new THREE.AmbientLight(skyColor, skyIntensity); + scene.add(skyLight); + + const color = 0xFFFFFF; + const intensity = 1; + const light = new THREE.PointLight(color, intensity); + light.position.set(0, 3, -5); + scene.add(light); + + //create groups to add everything to + const meshRoot = new THREE.Group(); + const wireRoot = new THREE.Group(); + const vertexRoot = new THREE.Group(); + const vertexlabelRoot = new THREE.Group(); + const edgeRoot = new THREE.Group(); + const ringRoot = new THREE.Group(); + const normalsRoot = new THREE.Group(); + const normalMeshRoot = new THREE.Group(); + + //parameters for the controls on the top right + var guiParameters = new function() { + this.speedX = 0.0; + this.speedY = 0.0; + this.speedZ = 0.0; + this.transparency = 1; + this.edgeVisibility = false; + this.edgeWidth = 0.2; + + this.vertexVisibility = true; + this.vertexlabelVisibility = false; + this.vertexSize = 1; + this.planeX = 0.0; + this.minX = -1.5; + this.maxX = 1.5; + this.planeXactive = false; + this.planeY = 0.0; + this.minY = -1.5; + + this.maxY = 1.5; + this.planeYactive = false; + this.planeZ = 0.0; + this.minZ = -1.5; + this.maxZ = 1.5; + this.planeZactive = false; + this.normalsMaterial = false; + this.circleVisibility = false; + this.circleWidth = 0.005; + this.normalsVisibility = false; + this.normalsLength = 1; + } ; + + //generate the plane for intersections + const planeX = new THREE.Plane( new THREE.Vector3( -1, 0, 0 ), guiParameters.planeX ); + const planeY = new THREE.Plane( new THREE.Vector3( 0, -1, 0 ), guiParameters.planeY ); + const planeZ = new THREE.Plane( new THREE.Vector3( 0, 0, -1 ), guiParameters.planeZ ); + + // the array which ones are currently active + var activePlanes = []; + + //rederer for lables + const labelRenderer = new CSS2DRenderer(); + labelRenderer.setSize( window.innerWidth, window.innerHeight ); + labelRenderer.domElement.style.position = 'absolute'; + labelRenderer.domElement.style.top = '0px'; + document.body.appendChild( labelRenderer.domElement ); + + //controls for mouse + const controls = new OrbitControls( camera, labelRenderer.domElement ); + + //controls in the top right corner + var gui = new GUI(); + + const animationFolder = gui.addFolder("Animations"); + animationFolder.add(guiParameters, 'speedX', 0, 5); + animationFolder.add(guiParameters, 'speedY', 0, 5); + animationFolder.add(guiParameters, 'speedZ', 0, 5); + animationFolder.open(); + + const controlFolder = gui.addFolder("Controls"); + controlFolder.add(guiParameters, "transparency", 0, 1); + controlFolder.add(guiParameters, "edgeVisibility"); + var edgeWidthGUI = controlFolder.add(guiParameters, "edgeWidth", 0.01, 2); + controlFolder.add(guiParameters, "vertexVisibility"); + controlFolder.add(guiParameters, "vertexlabelVisibility"); + controlFolder.add(guiParameters, "vertexSize", 0.1, 3); + controlFolder.add(guiParameters, "normalsMaterial"); + controlFolder.add(guiParameters, "circleVisibility"); + controlFolder.add(guiParameters, "circleWidth", 0.0001, 0.1); + controlFolder.add(guiParameters, "normalsVisibility"); + controlFolder.add(guiParameters, "normalsLength", 0, 2); + controlFolder.open(); + + //generate a sphere geometry for the vertices + const sphereGeometry = new THREE.SphereGeometry( 0.02, 32, 16 ); + sphereGeometry.transparent = guiParameters.vertexVisibility; + + //functions for later calculations + + function calulateIncenter(A, B, C){ + //we follow the math and variable names from here: https://math.stackexchange.com/questions/740111/incenter-of-triangle-in-3d + var a = Math.sqrt((B[0]-C[0])**2 + (B[1]-C[1])**2 + (B[2]-C[2])**2); + var b = Math.sqrt((C[0]-A[0])**2 + (C[1]-A[1])**2 + (C[2]-A[2])**2); + var c = Math.sqrt((A[0]-B[0])**2 + (A[1]-B[1])**2 + (A[2]-B[2])**2); + + var res = []; + res[0] = a/(a+b+c)*A[0] + b/(a+b+c)*B[0] + c/(a+b+c)*C[0]; + res[1] = a/(a+b+c)*A[1] + b/(a+b+c)*B[1] + c/(a+b+c)*C[1]; + res[2] = a/(a+b+c)*A[2] + b/(a+b+c)*B[2] + c/(a+b+c)*C[2]; + + return res; + } + + function calulateInradius(A, B, C){ + var a = Math.sqrt((B[0]-C[0])**2 + (B[1]-C[1])**2 + (B[2]-C[2])**2); + var b = Math.sqrt((C[0]-A[0])**2 + (C[1]-A[1])**2 + (C[2]-A[2])**2); + var c = Math.sqrt((A[0]-B[0])**2 + (A[1]-B[1])**2 + (A[2]-B[2])**2); + + var s = (a+b+c)/2; + var inradius = Math.sqrt(((s-a)*(s-b)*(s-c)) / s ); + + return inradius; + } + + // --- start of generated output --- // + + // preperations for parameterized vertex coordinates + const vertexParametriziation = false; + // generate the faces color by color + const geometry1 = new THREE.BufferGeometry(); + function setVertices1(){ + var vertices1 = new Float32Array( [ + 0.,-1.,0., + 0.,1.,0., + 0.5,1.,0.5, + + 0.,-1.,0., + 0.,1.,0., + 0.5,1.,-0.5, + + 0.,-1.,0., + 0.,1.,0., + -0.5,1.,0.5, + + 0.,-1.,0., + 0.,1.,0., + -0.5,1.,-0.5, + + ] ); + + return vertices1; + } + + geometry1.setAttribute( 'position', new THREE.BufferAttribute( setVertices1(), 3 ) ); + + // generate materials in the given color and normals material for the faces + + const materialNormal1 = new THREE.MeshNormalMaterial({ + flatShading: true, + }); + materialNormal1.transparent = true; + materialNormal1.side = THREE.DoubleSide; + + const material1 = new THREE.MeshPhongMaterial({ + color: 0x049EF4, + flatShading: true, + }); + material1.transparent = true; + material1.side = THREE.DoubleSide; + + // generate meshes for the faces from the materials with the vertex coordinates from before + + const mesh1 = new THREE.Mesh( geometry1, material1 ); + mesh1.castShadow = true; + mesh1.receiveShadow = true; + + meshRoot.add(mesh1); + + const meshNormal1 = new THREE.Mesh( geometry1, materialNormal1 ); + mesh1.castShadow = true; + mesh1.receiveShadow = true; + + normalMeshRoot.add(meshNormal1); + + // generate the edges grouped by color + + const edgeMaterial1 = new LineMaterial( { + color: 0xFF0000, + linewidth: 3., + } ); + + function getEdges1(){ + const edges1 = new Float32Array( [ + 0.,-1.,0., + 0.,1.,0., + + ]); + return edges1; + } + + + // generate geometries and lines for the edges + + const edgeGeometry1 = new LineGeometry(); + edgeGeometry1.setPositions(getEdges1() ); + + const edgeLine1 = new Line2( edgeGeometry1, edgeMaterial1 ); + edgeRoot.add(edgeLine1); + + // update function to be called every frame + + const edgeMaterial2 = new LineMaterial( { + color: 0x000000, + linewidth: 3., + } ); + + function getEdges2(){ + const edges2 = new Float32Array( [ + 0.,-1.,0., + 0.5,1.,0.5, + + 0.,-1.,0., + 0.5,1.,-0.5, + + 0.,-1.,0., + -0.5,1.,0.5, + + 0.,-1.,0., + -0.5,1.,-0.5, + + 0.,1.,0., + 0.5,1.,0.5, + + 0.,1.,0., + 0.5,1.,-0.5, + + 0.,1.,0., + -0.5,1.,0.5, + + 0.,1.,0., + -0.5,1.,-0.5, + + ]); + return edges2; + } + + + // generate geometries and lines for the edges + + const edgeGeometry2 = new LineGeometry(); + edgeGeometry2.setPositions(getEdges2() ); + + const edgeLine2 = new Line2( edgeGeometry2, edgeMaterial2 ); + edgeRoot.add(edgeLine2); + + // update function to be called every frame + // generate labels and spheres for the vertices + + + function getVertex1(){ + return [0.,-1.,0.,]; + } + const sphereMaterial1 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere1 = new THREE.Mesh( sphereGeometry, sphereMaterial1 ); + vertexRoot.add(sphere1); + sphere1.position.set(getVertex1()[0],getVertex1()[1],getVertex1()[2]); + + const lableDiv1 = document.createElement( 'div' ); + lableDiv1.className = 'label'; + lableDiv1.textContent = '1'; + lableDiv1.style.marginTop = '-1em'; + + const vertexLabel1 = new CSS2DObject( lableDiv1 ); + vertexLabel1.position.set(getVertex1()[0],getVertex1()[1],getVertex1()[2]); + vertexlabelRoot.add( vertexLabel1 ); + + + + function getVertex2(){ + return [0.,1.,0.,]; + } + const sphereMaterial2 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere2 = new THREE.Mesh( sphereGeometry, sphereMaterial2 ); + vertexRoot.add(sphere2); + sphere2.position.set(getVertex2()[0],getVertex2()[1],getVertex2()[2]); + + const lableDiv2 = document.createElement( 'div' ); + lableDiv2.className = 'label'; + lableDiv2.textContent = '2'; + lableDiv2.style.marginTop = '-1em'; + + const vertexLabel2 = new CSS2DObject( lableDiv2 ); + vertexLabel2.position.set(getVertex2()[0],getVertex2()[1],getVertex2()[2]); + vertexlabelRoot.add( vertexLabel2 ); + + + + function getVertex3(){ + return [0.5,1.,0.5,]; + } + const sphereMaterial3 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere3 = new THREE.Mesh( sphereGeometry, sphereMaterial3 ); + vertexRoot.add(sphere3); + sphere3.position.set(getVertex3()[0],getVertex3()[1],getVertex3()[2]); + + const lableDiv3 = document.createElement( 'div' ); + lableDiv3.className = 'label'; + lableDiv3.textContent = '3'; + lableDiv3.style.marginTop = '-1em'; + + const vertexLabel3 = new CSS2DObject( lableDiv3 ); + vertexLabel3.position.set(getVertex3()[0],getVertex3()[1],getVertex3()[2]); + vertexlabelRoot.add( vertexLabel3 ); + + + + function getVertex4(){ + return [0.5,1.,-0.5,]; + } + const sphereMaterial4 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere4 = new THREE.Mesh( sphereGeometry, sphereMaterial4 ); + vertexRoot.add(sphere4); + sphere4.position.set(getVertex4()[0],getVertex4()[1],getVertex4()[2]); + + const lableDiv4 = document.createElement( 'div' ); + lableDiv4.className = 'label'; + lableDiv4.textContent = '4'; + lableDiv4.style.marginTop = '-1em'; + + const vertexLabel4 = new CSS2DObject( lableDiv4 ); + vertexLabel4.position.set(getVertex4()[0],getVertex4()[1],getVertex4()[2]); + vertexlabelRoot.add( vertexLabel4 ); + + + + function getVertex5(){ + return [-0.5,1.,0.5,]; + } + const sphereMaterial5 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere5 = new THREE.Mesh( sphereGeometry, sphereMaterial5 ); + vertexRoot.add(sphere5); + sphere5.position.set(getVertex5()[0],getVertex5()[1],getVertex5()[2]); + + const lableDiv5 = document.createElement( 'div' ); + lableDiv5.className = 'label'; + lableDiv5.textContent = '5'; + lableDiv5.style.marginTop = '-1em'; + + const vertexLabel5 = new CSS2DObject( lableDiv5 ); + vertexLabel5.position.set(getVertex5()[0],getVertex5()[1],getVertex5()[2]); + vertexlabelRoot.add( vertexLabel5 ); + + + + function getVertex6(){ + return [-0.5,1.,-0.5,]; + } + const sphereMaterial6 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere6 = new THREE.Mesh( sphereGeometry, sphereMaterial6 ); + vertexRoot.add(sphere6); + sphere6.position.set(getVertex6()[0],getVertex6()[1],getVertex6()[2]); + + const lableDiv6 = document.createElement( 'div' ); + lableDiv6.className = 'label'; + lableDiv6.textContent = '6'; + lableDiv6.style.marginTop = '-1em'; + + const vertexLabel6 = new CSS2DObject( lableDiv6 ); + vertexLabel6.position.set(getVertex6()[0],getVertex6()[1],getVertex6()[2]); + vertexlabelRoot.add( vertexLabel6 ); + + // generate the rings for the incircles + + var inradius1 = calulateInradius(getVertex1(), getVertex2(), getVertex3()); + var incenter1 = calulateIncenter(getVertex1(), getVertex2(), getVertex3()); + var ringGeometry1 = new THREE.RingGeometry((inradius1 - 0.005),inradius1, 32); + const ringMaterial1 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh1 = new THREE.Mesh(ringGeometry1, ringMaterial1); + + function setCircleRotation1(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.,-1.,0.],[ 0.,1.,0.],[0.5,1.,0.5]); + + ringMesh1.position.setX(incenter[0]); + ringMesh1.position.setY(incenter[1]); + ringMesh1.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex1(), getVertex2(), getVertex3()); + var relRadius = inradius/inradius1; + + ringMesh1.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A1 = new THREE.Vector3(0.,-1.,0.); + const B1 = new THREE.Vector3(0.,1.,0.); + const C1 = new THREE.Vector3(0.5,1.,0.5); + + const normalVec1 = new THREE.Vector3(); + normalVec1.crossVectors(B1.sub(A1), C1.sub(A1)); + normalVec1.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal1 = new THREE.Vector3(0,0,1); + + const quaternionRotation1 = new THREE.Quaternion(); + quaternionRotation1.setFromUnitVectors(initialNormal1, normalVec1); + + ringMesh1.setRotationFromQuaternion(quaternionRotation1); + + return quaternionRotation1; + } + + ringRoot.add(ringMesh1); + + var inradius2 = calulateInradius(getVertex1(), getVertex2(), getVertex4()); + var incenter2 = calulateIncenter(getVertex1(), getVertex2(), getVertex4()); + var ringGeometry2 = new THREE.RingGeometry((inradius2 - 0.005),inradius2, 32); + const ringMaterial2 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh2 = new THREE.Mesh(ringGeometry2, ringMaterial2); + + function setCircleRotation2(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.,-1.,0.],[ 0.,1.,0.],[0.5,1.,-0.5]); + + ringMesh2.position.setX(incenter[0]); + ringMesh2.position.setY(incenter[1]); + ringMesh2.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex1(), getVertex2(), getVertex4()); + var relRadius = inradius/inradius2; + + ringMesh2.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A2 = new THREE.Vector3(0.,-1.,0.); + const B2 = new THREE.Vector3(0.,1.,0.); + const C2 = new THREE.Vector3(0.5,1.,-0.5); + + const normalVec2 = new THREE.Vector3(); + normalVec2.crossVectors(B2.sub(A2), C2.sub(A2)); + normalVec2.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal2 = new THREE.Vector3(0,0,1); + + const quaternionRotation2 = new THREE.Quaternion(); + quaternionRotation2.setFromUnitVectors(initialNormal2, normalVec2); + + ringMesh2.setRotationFromQuaternion(quaternionRotation2); + + return quaternionRotation2; + } + + ringRoot.add(ringMesh2); + + var inradius3 = calulateInradius(getVertex1(), getVertex2(), getVertex5()); + var incenter3 = calulateIncenter(getVertex1(), getVertex2(), getVertex5()); + var ringGeometry3 = new THREE.RingGeometry((inradius3 - 0.005),inradius3, 32); + const ringMaterial3 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh3 = new THREE.Mesh(ringGeometry3, ringMaterial3); + + function setCircleRotation3(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.,-1.,0.],[ 0.,1.,0.],[-0.5,1.,0.5]); + + ringMesh3.position.setX(incenter[0]); + ringMesh3.position.setY(incenter[1]); + ringMesh3.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex1(), getVertex2(), getVertex5()); + var relRadius = inradius/inradius3; + + ringMesh3.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A3 = new THREE.Vector3(0.,-1.,0.); + const B3 = new THREE.Vector3(0.,1.,0.); + const C3 = new THREE.Vector3(-0.5,1.,0.5); + + const normalVec3 = new THREE.Vector3(); + normalVec3.crossVectors(B3.sub(A3), C3.sub(A3)); + normalVec3.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal3 = new THREE.Vector3(0,0,1); + + const quaternionRotation3 = new THREE.Quaternion(); + quaternionRotation3.setFromUnitVectors(initialNormal3, normalVec3); + + ringMesh3.setRotationFromQuaternion(quaternionRotation3); + + return quaternionRotation3; + } + + ringRoot.add(ringMesh3); + + var inradius4 = calulateInradius(getVertex1(), getVertex2(), getVertex6()); + var incenter4 = calulateIncenter(getVertex1(), getVertex2(), getVertex6()); + var ringGeometry4 = new THREE.RingGeometry((inradius4 - 0.005),inradius4, 32); + const ringMaterial4 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh4 = new THREE.Mesh(ringGeometry4, ringMaterial4); + + function setCircleRotation4(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.,-1.,0.],[ 0.,1.,0.],[-0.5,1.,-0.5]); + + ringMesh4.position.setX(incenter[0]); + ringMesh4.position.setY(incenter[1]); + ringMesh4.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex1(), getVertex2(), getVertex6()); + var relRadius = inradius/inradius4; + + ringMesh4.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A4 = new THREE.Vector3(0.,-1.,0.); + const B4 = new THREE.Vector3(0.,1.,0.); + const C4 = new THREE.Vector3(-0.5,1.,-0.5); + + const normalVec4 = new THREE.Vector3(); + normalVec4.crossVectors(B4.sub(A4), C4.sub(A4)); + normalVec4.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal4 = new THREE.Vector3(0,0,1); + + const quaternionRotation4 = new THREE.Quaternion(); + quaternionRotation4.setFromUnitVectors(initialNormal4, normalVec4); + + ringMesh4.setRotationFromQuaternion(quaternionRotation4); + + return quaternionRotation4; + } + + ringRoot.add(ringMesh4); + // function to update the circles every frame + function updateCircles(){ + setCircleRotation1(); + setCircleRotation2(); + setCircleRotation3(); + setCircleRotation4(); + } + + // needs to be called once to be initialized + updateCircles(); + + // function to update the circles width, that is called every frame even if the surface is not parameterized + function updateCircleWidth(){ + ringGeometry1.dispose(); + ringGeometry1 = new THREE.RingGeometry((inradius1 - guiParameters.circleWidth),inradius1, 32); + ringMesh1.geometry = ringGeometry1; + ringGeometry2.dispose(); + ringGeometry2 = new THREE.RingGeometry((inradius2 - guiParameters.circleWidth),inradius2, 32); + ringMesh2.geometry = ringGeometry2; + ringGeometry3.dispose(); + ringGeometry3 = new THREE.RingGeometry((inradius3 - guiParameters.circleWidth),inradius3, 32); + ringMesh3.geometry = ringGeometry3; + ringGeometry4.dispose(); + ringGeometry4 = new THREE.RingGeometry((inradius4 - guiParameters.circleWidth),inradius4, 32); + ringMesh4.geometry = ringGeometry4; + } + + updateCircleWidth(); + + // generate the normals trough the incenter orthogonal to the face + // getNormalsVectors generates the coordinates for the current values of the parameterized surface + function getNormalsVectors(){ + var vector1; + var vector2; + + var normals = []; + vector1 = []; + vector2 = []; + vector1[0] = (0.)-(0.); + vector1[1] = (1.)-(-1.); + vector1[2] = (0.)-(0.); + + vector2[0] = (0.5)-(0.); + vector2[1] = (1.)-(-1.); + vector2[2] = (0.5)-(0.); + + var incenter = calulateIncenter([0.,-1.,0.],[ 0.,1.,0.],[0.5,1.,0.5]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.)-(0.); + vector1[1] = (1.)-(-1.); + vector1[2] = (0.)-(0.); + + vector2[0] = (0.5)-(0.); + vector2[1] = (1.)-(-1.); + vector2[2] = (-0.5)-(0.); + + var incenter = calulateIncenter([0.,-1.,0.],[ 0.,1.,0.],[0.5,1.,-0.5]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.)-(0.); + vector1[1] = (1.)-(-1.); + vector1[2] = (0.)-(0.); + + vector2[0] = (-0.5)-(0.); + vector2[1] = (1.)-(-1.); + vector2[2] = (0.5)-(0.); + + var incenter = calulateIncenter([0.,-1.,0.],[ 0.,1.,0.],[-0.5,1.,0.5]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.)-(0.); + vector1[1] = (1.)-(-1.); + vector1[2] = (0.)-(0.); + + vector2[0] = (-0.5)-(0.); + vector2[1] = (1.)-(-1.); + vector2[2] = (-0.5)-(0.); + + var incenter = calulateIncenter([0.,-1.,0.],[ 0.,1.,0.],[-0.5,1.,-0.5]); + normals.push([vector1, vector2, incenter]); + + return normals; + } + // getNormalsCoordinates calculates the right coordinates for the ortogonality and fitting values from the gui + function getNormalsCoordinates(){ + var res = []; + var normals = getNormalsVectors(); + for(var i = 0; i < normals.length; i++){ + var plus = []; + var minus = []; + + minus[0] = normals[i][2][0] - (1/2)*guiParameters.normalsLength*(normals[i][0][1]*normals[i][1][2] - normals[i][0][2]*normals[i][1][1]); + minus[1] = normals[i][2][1] - (1/2)*guiParameters.normalsLength*(normals[i][0][2]*normals[i][1][0] - normals[i][0][0]*normals[i][1][2]); + minus[2] = normals[i][2][2] - (1/2)*guiParameters.normalsLength*(normals[i][0][0]*normals[i][1][1] - normals[i][0][1]*normals[i][1][0]); + + plus[0] = normals[i][2][0] + (1/2)*guiParameters.normalsLength*(normals[i][0][1]*normals[i][1][2] - normals[i][0][2]*normals[i][1][1]); + plus[1] = normals[i][2][1] + (1/2)*guiParameters.normalsLength*(normals[i][0][2]*normals[i][1][0] - normals[i][0][0]*normals[i][1][2]); + plus[2] = normals[i][2][2] + (1/2)*guiParameters.normalsLength*(normals[i][0][0]*normals[i][1][1] - normals[i][0][1]*normals[i][1][0]); + + res.push(minus[0]); + res.push(minus[1]); + res.push(minus[2]); + res.push(plus[0]); + res.push(plus[1]); + res.push(plus[2]); + } + res = Float32Array.from(res); + + + return res; + } + + + const normalsMaterial = new THREE.LineBasicMaterial( { + color: 0x000000, + } ); + + const normalsGeometry = new THREE.BufferGeometry(); + normalsGeometry.setAttribute( 'position', new THREE.BufferAttribute( getNormalsCoordinates(), 3 ) ); + var normalsLine = new THREE.LineSegments( normalsGeometry, normalsMaterial ); + + function updateNormals(){ + normalsGeometry.setAttribute( 'position', new THREE.BufferAttribute( getNormalsCoordinates(), 3 ) ); + normalsLine = new THREE.LineSegments( normalsGeometry, normalsMaterial ); + } + + normalsRoot.add(normalsLine); + + + // generate automatic ranges for the intersections if the surface is not parameterized + guiParameters.maxX = 0.5; + guiParameters.maxY = 1.; + guiParameters.maxZ = 0.5; + guiParameters.minX = -0.5; + guiParameters.minY = -1.; + guiParameters.minZ = -0.5; + + guiParameters.planeX = 0.; + guiParameters.planeY = 0.; + guiParameters.planeZ = 0.; + // --- end of generated output --- // + + const planeFolder = gui.addFolder("Intersection Planes"); + planeFolder.add(guiParameters, 'planeXactive'); + planeFolder.add(guiParameters, 'planeX', guiParameters.minX*1.1, guiParameters.maxX*1.1); + planeFolder.add(guiParameters, 'planeYactive'); + planeFolder.add(guiParameters, 'planeY', guiParameters.minY*1.1, guiParameters.maxY*1.1); + planeFolder.add(guiParameters, 'planeZactive'); + planeFolder.add(guiParameters, 'planeZ', guiParameters.minZ*1.1, guiParameters.maxZ*1.1); + + camera.position.z = Math.max((1.5)*guiParameters.minZ, 1) + camera.lookAt(0,0,-1); + + scene.background = new THREE.Color( 'white' ); + + // add both roots to the scene + scene.add( meshRoot ); + scene.add( wireRoot ); + scene.add( vertexRoot ); + scene.add( vertexlabelRoot ); + scene.add( edgeRoot ); + scene.add( ringRoot ); + scene.add( normalsRoot ); + scene.add( normalMeshRoot ); + + //presave some current gui parameters to only update if they change + var currentCircleWidth = guiParameters.circleWidth; + + function animate() { + requestAnimationFrame( animate ); + meshRoot.rotation.x += guiParameters.speedX/100; + meshRoot.rotation.y += guiParameters.speedY/100; + meshRoot.rotation.z += guiParameters.speedZ/100; + + wireRoot.rotation.x += guiParameters.speedX/100; + wireRoot.rotation.y += guiParameters.speedY/100; + wireRoot.rotation.z += guiParameters.speedZ/100; + + vertexRoot.rotation.x += guiParameters.speedX/100; + vertexRoot.rotation.y += guiParameters.speedY/100; + vertexRoot.rotation.z += guiParameters.speedZ/100; + + vertexlabelRoot.rotation.x += guiParameters.speedX/100; + vertexlabelRoot.rotation.y += guiParameters.speedY/100; + vertexlabelRoot.rotation.z += guiParameters.speedZ/100; + + edgeRoot.rotation.x += guiParameters.speedX/100; + edgeRoot.rotation.y += guiParameters.speedY/100; + edgeRoot.rotation.z += guiParameters.speedZ/100; + + ringRoot.rotation.x += guiParameters.speedX/100; + ringRoot.rotation.y += guiParameters.speedY/100; + ringRoot.rotation.z += guiParameters.speedZ/100; + + normalsRoot.rotation.x += guiParameters.speedX/100; + normalsRoot.rotation.y += guiParameters.speedY/100; + normalsRoot.rotation.z += guiParameters.speedZ/100; + + normalMeshRoot.rotation.x += guiParameters.speedX/100; + normalMeshRoot.rotation.y += guiParameters.speedY/100; + normalMeshRoot.rotation.z += guiParameters.speedZ/100; + + //update the light when the camera moves (with orbitcontrols) + light.position.set(camera.position.x, camera.position.y, camera.position.z); + + planeX.constant = guiParameters.planeX; + planeY.constant = guiParameters.planeY; + planeZ.constant = guiParameters.planeZ; + + activePlanes = []; + if(guiParameters.planeXactive){ + activePlanes.push(planeX); + } + if(guiParameters.planeYactive){ + activePlanes.push(planeY); + } + if(guiParameters.planeZactive){ + activePlanes.push(planeZ); + } + + if(vertexParametriziation){ + updateFaceCoordinates(); + if(guiParameters.edgeVisibility){ + updateEdgeCoordinates(); + } + if(guiParameters.vertexlabelVisibility || guiParameters.vertexVisibility){ + updateVertexCoordinates(); + } + if(guiParameters.circleVisibility){ + updateCircles(); + } + } + + //update stuff that changes from the gui + meshRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.opacity = guiParameters.transparency; + node.material.clippingPlanes = activePlanes; + if(guiParameters.normalsMaterial){ + node.material.opacity = 0; + } + } + } ); + + normalMeshRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.opacity = guiParameters.transparency; + node.material.clippingPlanes = activePlanes; + if(!guiParameters.normalsMaterial){ + node.material.opacity = 0; + } + } + } ); + + edgeRoot.traverse( function( node ) { + if ( node instanceof Line2 ) { + node.material.visible = guiParameters.edgeVisibility; + node.material.linewidth = guiParameters.edgeWidth/100; + } + if ( node instanceof THREE.LineSegments ) { + node.material.visible = guiParameters.edgeVisibility; + } + } ); + + vertexRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.visible = guiParameters.vertexVisibility; + node.scale.setScalar(guiParameters.vertexSize); + } + } ); + + vertexlabelRoot.traverse( function( node ) { + if( node instanceof CSS2DObject) { + node.visible = guiParameters.vertexlabelVisibility; + } + } ); + + ringRoot.traverse( function( node ) { + if( node instanceof THREE.Mesh) { + node.visible = guiParameters.circleVisibility; + } + } ); + + normalsRoot.traverse( function( node ) { + if( node instanceof THREE.LineSegments) { + node.visible = guiParameters.normalsVisibility; + } + } ); + + // update the circle width + if(guiParameters.circleVisibility && currentCircleWidth != guiParameters.circleWidth){ + updateCircleWidth(); + currentCircleWidth = guiParameters.circleWidth; + } + + //update the normals length + if(guiParameters.normalsVisibility){ + updateNormals(); + } + + controls.update(); + + renderer.localClippingEnabled = true; + + renderer.render( scene, camera ); + labelRenderer.render( scene, camera ); + } + animate(); + + //resize of window size changes + window.addEventListener( 'resize', onWindowResize ); + function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + labelRenderer.setSize( window.innerWidth, window.innerHeight ); + } +</script> + +</body> +</html> \ No newline at end of file diff --git a/test.stl b/test.stl new file mode 100644 index 0000000000000000000000000000000000000000..8e9e1b52231e5eeef59798045057f02e1a6fced8 --- /dev/null +++ b/test.stl @@ -0,0 +1,16 @@ +solid test + facet normal -0.40824829046386307 0.40824829046386307 -0.81649658092772615 + outer loop + vertex 2. 0. 0. + vertex 1. -1. 0. + vertex -1. -1. 1. + endloop + endfacet + facet normal -0.6616216370868464 0.74983785536509251 0. + outer loop + vertex 2. 0. 0. + vertex 0.29999999999999999 -1.5 0.5 + vertex 0.29999999999999999 -1.5 1. + endloop + endfacet +endsolid test \ No newline at end of file diff --git a/test_split2.stl b/test_split2.stl new file mode 100644 index 0000000000000000000000000000000000000000..aadc3936c9ca3c149718350d76f0a38ee2a28fa6 --- /dev/null +++ b/test_split2.stl @@ -0,0 +1,58 @@ +solid test_split2 + facet normal 0. 0. -1. + outer loop + vertex 2. 0. 0. + vertex 1. -1. 0. + vertex 0.20000000000000001 -1.5 0. + endloop + endfacet + facet normal 0. 0. 1. + outer loop + vertex 2. 0. 0. + vertex 0.20000000000000001 -1.5 0. + vertex 0.5 -1.5 0. + endloop + endfacet + facet normal -0.70534561585859823 0.70534561585859823 -0.070534561585859995 + outer loop + vertex 2. 0. 0. + vertex 0.5 -1.5 0. + vertex 0.40000000000000002 -1.5 1. + endloop + endfacet + facet normal -0.1534291029830539 -0.42960148835255091 -0.88988879730171255 + outer loop + vertex 2. 0. 0. + vertex 0.40000000000000002 -1.5 1. + vertex -1. -1. 1. + endloop + endfacet + facet normal -0.40824829046386307 0.40824829046386307 -0.81649658092772615 + outer loop + vertex 2. 0. 0. + vertex 1. -1. 0. + vertex -1. -1. 1. + endloop + endfacet + facet normal -0.36369648372665397 0.58191437396264634 -0.72739296745330795 + outer loop + vertex 1. -1. 0. + vertex 0.20000000000000001 -1.5 0. + vertex -1. -1. 1. + endloop + endfacet + facet normal -0.33557802760701216 -0.93961847729963399 0.06711560552140243 + outer loop + vertex 0.20000000000000001 -1.5 0. + vertex 0.40000000000000002 -1.5 1. + vertex -1. -1. 1. + endloop + endfacet + facet normal 0. -1. 0. + outer loop + vertex 0.20000000000000001 -1.5 0. + vertex 0.5 -1.5 0. + vertex 0.40000000000000002 -1.5 1. + endloop + endfacet +endsolid test_split2 \ No newline at end of file diff --git a/un_ramified1.html b/un_ramified1.html new file mode 100644 index 0000000000000000000000000000000000000000..d8ab75a07d42500403e0440e535162834ec58d78 --- /dev/null +++ b/un_ramified1.html @@ -0,0 +1,960 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>SimplicialSurface</title> + <style> + body { margin: 0; } + </style> + + + </head> + <body> + +<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> + + +<script type="importmap"> + { + "imports": { + "three": "https://unpkg.com/three@0.148.0/build/three.module.js", + "three/addons/": "https://unpkg.com/three@0.148.0/examples/jsm/", + "gui": "https://unpkg.com/dat.gui@0.7.9/build/dat.gui.module.js" + } + } +</script> + + +<script type="module"> + import * as THREE from 'three'; + import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + import { GUI } from 'gui'; + import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js'; + import { Line2 } from 'three/addons/lines/Line2.js'; + import { LineMaterial } from 'three/addons/lines/LineMaterial.js'; + import { LineSegmentsGeometry } from 'three/addons/lines/LineSegmentsGeometry.js'; + + //start scene and camera + const scene = new THREE.Scene(); + const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 100 ); + + const renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setSize( window.innerWidth, window.innerHeight ); + document.body.appendChild( renderer.domElement ); + + //Lights + const skyColor = 0xFFFFFF; + const skyIntensity = 0.3; + const skyLight = new THREE.AmbientLight(skyColor, skyIntensity); + scene.add(skyLight); + + const color = 0xFFFFFF; + const intensity = 1; + const light = new THREE.PointLight(color, intensity); + light.position.set(0, 3, -5); + scene.add(light); + + //create groups to add everything to + const meshRoot = new THREE.Group(); + const wireRoot = new THREE.Group(); + const vertexRoot = new THREE.Group(); + const vertexlabelRoot = new THREE.Group(); + const edgeRoot = new THREE.Group(); + const ringRoot = new THREE.Group(); + const normalsRoot = new THREE.Group(); + const normalMeshRoot = new THREE.Group(); + + //parameters for the controls on the top right + var guiParameters = new function() { + this.speedX = 0.0; + this.speedY = 0.0; + this.speedZ = 0.0; + this.transparency = 1; + this.edgeVisibility = false; + this.edgeWidth = 0.2; + + this.vertexVisibility = true; + this.vertexlabelVisibility = false; + this.vertexSize = 1; + this.planeX = 0.0; + this.minX = -1.5; + this.maxX = 1.5; + this.planeXactive = false; + this.planeY = 0.0; + this.minY = -1.5; + + this.maxY = 1.5; + this.planeYactive = false; + this.planeZ = 0.0; + this.minZ = -1.5; + this.maxZ = 1.5; + this.planeZactive = false; + this.normalsMaterial = false; + this.circleVisibility = false; + this.circleWidth = 0.005; + this.normalsVisibility = false; + this.normalsLength = 1; + } ; + + //generate the plane for intersections + const planeX = new THREE.Plane( new THREE.Vector3( -1, 0, 0 ), guiParameters.planeX ); + const planeY = new THREE.Plane( new THREE.Vector3( 0, -1, 0 ), guiParameters.planeY ); + const planeZ = new THREE.Plane( new THREE.Vector3( 0, 0, -1 ), guiParameters.planeZ ); + + // the array which ones are currently active + var activePlanes = []; + + //rederer for lables + const labelRenderer = new CSS2DRenderer(); + labelRenderer.setSize( window.innerWidth, window.innerHeight ); + labelRenderer.domElement.style.position = 'absolute'; + labelRenderer.domElement.style.top = '0px'; + document.body.appendChild( labelRenderer.domElement ); + + //controls for mouse + const controls = new OrbitControls( camera, labelRenderer.domElement ); + + //controls in the top right corner + var gui = new GUI(); + + const animationFolder = gui.addFolder("Animations"); + animationFolder.add(guiParameters, 'speedX', 0, 5); + animationFolder.add(guiParameters, 'speedY', 0, 5); + animationFolder.add(guiParameters, 'speedZ', 0, 5); + animationFolder.open(); + + const controlFolder = gui.addFolder("Controls"); + controlFolder.add(guiParameters, "transparency", 0, 1); + controlFolder.add(guiParameters, "edgeVisibility"); + var edgeWidthGUI = controlFolder.add(guiParameters, "edgeWidth", 0.01, 2); + controlFolder.add(guiParameters, "vertexVisibility"); + controlFolder.add(guiParameters, "vertexlabelVisibility"); + controlFolder.add(guiParameters, "vertexSize", 0.1, 3); + controlFolder.add(guiParameters, "normalsMaterial"); + controlFolder.add(guiParameters, "circleVisibility"); + controlFolder.add(guiParameters, "circleWidth", 0.0001, 0.1); + controlFolder.add(guiParameters, "normalsVisibility"); + controlFolder.add(guiParameters, "normalsLength", 0, 2); + controlFolder.open(); + + //generate a sphere geometry for the vertices + const sphereGeometry = new THREE.SphereGeometry( 0.02, 32, 16 ); + sphereGeometry.transparent = guiParameters.vertexVisibility; + + //functions for later calculations + + function calulateIncenter(A, B, C){ + //we follow the math and variable names from here: https://math.stackexchange.com/questions/740111/incenter-of-triangle-in-3d + var a = Math.sqrt((B[0]-C[0])**2 + (B[1]-C[1])**2 + (B[2]-C[2])**2); + var b = Math.sqrt((C[0]-A[0])**2 + (C[1]-A[1])**2 + (C[2]-A[2])**2); + var c = Math.sqrt((A[0]-B[0])**2 + (A[1]-B[1])**2 + (A[2]-B[2])**2); + + var res = []; + res[0] = a/(a+b+c)*A[0] + b/(a+b+c)*B[0] + c/(a+b+c)*C[0]; + res[1] = a/(a+b+c)*A[1] + b/(a+b+c)*B[1] + c/(a+b+c)*C[1]; + res[2] = a/(a+b+c)*A[2] + b/(a+b+c)*B[2] + c/(a+b+c)*C[2]; + + return res; + } + + function calulateInradius(A, B, C){ + var a = Math.sqrt((B[0]-C[0])**2 + (B[1]-C[1])**2 + (B[2]-C[2])**2); + var b = Math.sqrt((C[0]-A[0])**2 + (C[1]-A[1])**2 + (C[2]-A[2])**2); + var c = Math.sqrt((A[0]-B[0])**2 + (A[1]-B[1])**2 + (A[2]-B[2])**2); + + var s = (a+b+c)/2; + var inradius = Math.sqrt(((s-a)*(s-b)*(s-c)) / s ); + + return inradius; + } + + // --- start of generated output --- // + + // preperations for parameterized vertex coordinates + const vertexParametriziation = false; + // generate the faces color by color + const geometry1 = new THREE.BufferGeometry(); + function setVertices1(){ + var vertices1 = new Float32Array( [ + 0.,-1.,0.1, + 0.,1.,0.1, + 0.5,1.,0.5, + + 0.,-1.,-0.1, + 0.,1.,-0.1, + 0.5,1.,-0.5, + + 0.,-1.,0.1, + 0.,1.,0.1, + -0.5,1.,0.5, + + 0.,-1.,-0.1, + 0.,1.,-0.1, + -0.5,1.,-0.5, + + ] ); + + return vertices1; + } + + geometry1.setAttribute( 'position', new THREE.BufferAttribute( setVertices1(), 3 ) ); + + // generate materials in the given color and normals material for the faces + + const materialNormal1 = new THREE.MeshNormalMaterial({ + flatShading: true, + }); + materialNormal1.transparent = true; + materialNormal1.side = THREE.DoubleSide; + + const material1 = new THREE.MeshPhongMaterial({ + color: 0x049EF4, + flatShading: true, + }); + material1.transparent = true; + material1.side = THREE.DoubleSide; + + // generate meshes for the faces from the materials with the vertex coordinates from before + + const mesh1 = new THREE.Mesh( geometry1, material1 ); + mesh1.castShadow = true; + mesh1.receiveShadow = true; + + meshRoot.add(mesh1); + + const meshNormal1 = new THREE.Mesh( geometry1, materialNormal1 ); + mesh1.castShadow = true; + mesh1.receiveShadow = true; + + normalMeshRoot.add(meshNormal1); + + // generate the edges grouped by color + + const edgeMaterial1 = new LineMaterial( { + color: 0xFF0000, + linewidth: 3., + } ); + + function getEdges1(){ + const edges1 = new Float32Array( [ + 0.,-1.,-0.10000000000000001, + 0.,1.,-0.10000000000000001, + + 0.,-1.,0.10000000000000001, + 0.,1.,0.10000000000000001, + + ]); + return edges1; + } + + + // generate geometries and lines for the edges + + const edgeGeometry1 = new LineSegmentsGeometry(); + edgeGeometry1.setPositions(getEdges1() ); + + const edgeLine1 = new Line2( edgeGeometry1, edgeMaterial1 ); + edgeRoot.add(edgeLine1); + + // update function to be called every frame + + const edgeMaterial2 = new LineMaterial( { + color: 0x000000, + linewidth: 3., + } ); + + function getEdges2(){ + const edges2 = new Float32Array( [ + 0.,-1.,-0.10000000000000001, + 0.5,1.,-0.5, + + 0.,-1.,-0.10000000000000001, + -0.5,1.,-0.5, + + 0.,1.,-0.10000000000000001, + 0.5,1.,-0.5, + + 0.,1.,-0.10000000000000001, + -0.5,1.,-0.5, + + 0.,-1.,0.10000000000000001, + 0.5,1.,0.5, + + 0.,-1.,0.10000000000000001, + -0.5,1.,0.5, + + 0.,1.,0.10000000000000001, + 0.5,1.,0.5, + + 0.,1.,0.10000000000000001, + -0.5,1.,0.5, + + ]); + return edges2; + } + + + // generate geometries and lines for the edges + + const edgeGeometry1 = new LineSegmentsGeometry(); + edgeGeometry2.setPositions(getEdges2() ); + + const edgeLine2 = new Line2( edgeGeometry2, edgeMaterial2 ); + edgeRoot.add(edgeLine2); + + // update function to be called every frame + // generate labels and spheres for the vertices + + + function getVertex1(){ + return [0.,-1.,-0.10000000000000001,]; + } + const sphereMaterial1 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere1 = new THREE.Mesh( sphereGeometry, sphereMaterial1 ); + vertexRoot.add(sphere1); + sphere1.position.set(getVertex1()[0],getVertex1()[1],getVertex1()[2]); + + const lableDiv1 = document.createElement( 'div' ); + lableDiv1.className = 'label'; + lableDiv1.textContent = '1'; + lableDiv1.style.marginTop = '-1em'; + + const vertexLabel1 = new CSS2DObject( lableDiv1 ); + vertexLabel1.position.set(getVertex1()[0],getVertex1()[1],getVertex1()[2]); + vertexlabelRoot.add( vertexLabel1 ); + + + + function getVertex2(){ + return [0.,1.,-0.10000000000000001,]; + } + const sphereMaterial2 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere2 = new THREE.Mesh( sphereGeometry, sphereMaterial2 ); + vertexRoot.add(sphere2); + sphere2.position.set(getVertex2()[0],getVertex2()[1],getVertex2()[2]); + + const lableDiv2 = document.createElement( 'div' ); + lableDiv2.className = 'label'; + lableDiv2.textContent = '2'; + lableDiv2.style.marginTop = '-1em'; + + const vertexLabel2 = new CSS2DObject( lableDiv2 ); + vertexLabel2.position.set(getVertex2()[0],getVertex2()[1],getVertex2()[2]); + vertexlabelRoot.add( vertexLabel2 ); + + + + function getVertex3(){ + return [0.,-1.,0.10000000000000001,]; + } + const sphereMaterial3 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere3 = new THREE.Mesh( sphereGeometry, sphereMaterial3 ); + vertexRoot.add(sphere3); + sphere3.position.set(getVertex3()[0],getVertex3()[1],getVertex3()[2]); + + const lableDiv3 = document.createElement( 'div' ); + lableDiv3.className = 'label'; + lableDiv3.textContent = '3'; + lableDiv3.style.marginTop = '-1em'; + + const vertexLabel3 = new CSS2DObject( lableDiv3 ); + vertexLabel3.position.set(getVertex3()[0],getVertex3()[1],getVertex3()[2]); + vertexlabelRoot.add( vertexLabel3 ); + + + + function getVertex4(){ + return [0.,1.,0.10000000000000001,]; + } + const sphereMaterial4 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere4 = new THREE.Mesh( sphereGeometry, sphereMaterial4 ); + vertexRoot.add(sphere4); + sphere4.position.set(getVertex4()[0],getVertex4()[1],getVertex4()[2]); + + const lableDiv4 = document.createElement( 'div' ); + lableDiv4.className = 'label'; + lableDiv4.textContent = '4'; + lableDiv4.style.marginTop = '-1em'; + + const vertexLabel4 = new CSS2DObject( lableDiv4 ); + vertexLabel4.position.set(getVertex4()[0],getVertex4()[1],getVertex4()[2]); + vertexlabelRoot.add( vertexLabel4 ); + + + + function getVertex5(){ + return [0.5,1.,0.5,]; + } + const sphereMaterial5 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere5 = new THREE.Mesh( sphereGeometry, sphereMaterial5 ); + vertexRoot.add(sphere5); + sphere5.position.set(getVertex5()[0],getVertex5()[1],getVertex5()[2]); + + const lableDiv5 = document.createElement( 'div' ); + lableDiv5.className = 'label'; + lableDiv5.textContent = '5'; + lableDiv5.style.marginTop = '-1em'; + + const vertexLabel5 = new CSS2DObject( lableDiv5 ); + vertexLabel5.position.set(getVertex5()[0],getVertex5()[1],getVertex5()[2]); + vertexlabelRoot.add( vertexLabel5 ); + + + + function getVertex6(){ + return [0.5,1.,-0.5,]; + } + const sphereMaterial6 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere6 = new THREE.Mesh( sphereGeometry, sphereMaterial6 ); + vertexRoot.add(sphere6); + sphere6.position.set(getVertex6()[0],getVertex6()[1],getVertex6()[2]); + + const lableDiv6 = document.createElement( 'div' ); + lableDiv6.className = 'label'; + lableDiv6.textContent = '6'; + lableDiv6.style.marginTop = '-1em'; + + const vertexLabel6 = new CSS2DObject( lableDiv6 ); + vertexLabel6.position.set(getVertex6()[0],getVertex6()[1],getVertex6()[2]); + vertexlabelRoot.add( vertexLabel6 ); + + + + function getVertex7(){ + return [-0.5,1.,0.5,]; + } + const sphereMaterial7 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere7 = new THREE.Mesh( sphereGeometry, sphereMaterial7 ); + vertexRoot.add(sphere7); + sphere7.position.set(getVertex7()[0],getVertex7()[1],getVertex7()[2]); + + const lableDiv7 = document.createElement( 'div' ); + lableDiv7.className = 'label'; + lableDiv7.textContent = '7'; + lableDiv7.style.marginTop = '-1em'; + + const vertexLabel7 = new CSS2DObject( lableDiv7 ); + vertexLabel7.position.set(getVertex7()[0],getVertex7()[1],getVertex7()[2]); + vertexlabelRoot.add( vertexLabel7 ); + + + + function getVertex8(){ + return [-0.5,1.,-0.5,]; + } + const sphereMaterial8 = new THREE.MeshBasicMaterial( { color: 0xF58137 } ); + const sphere8 = new THREE.Mesh( sphereGeometry, sphereMaterial8 ); + vertexRoot.add(sphere8); + sphere8.position.set(getVertex8()[0],getVertex8()[1],getVertex8()[2]); + + const lableDiv8 = document.createElement( 'div' ); + lableDiv8.className = 'label'; + lableDiv8.textContent = '8'; + lableDiv8.style.marginTop = '-1em'; + + const vertexLabel8 = new CSS2DObject( lableDiv8 ); + vertexLabel8.position.set(getVertex8()[0],getVertex8()[1],getVertex8()[2]); + vertexlabelRoot.add( vertexLabel8 ); + + // generate the rings for the incircles + + var inradius1 = calulateInradius(getVertex3(), getVertex4(), getVertex5()); + var incenter1 = calulateIncenter(getVertex3(), getVertex4(), getVertex5()); + var ringGeometry1 = new THREE.RingGeometry((inradius1 - 0.005),inradius1, 32); + const ringMaterial1 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh1 = new THREE.Mesh(ringGeometry1, ringMaterial1); + + function setCircleRotation1(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.,-1.,0.10000000000000001],[ 0.,1.,0.10000000000000001],[0.5,1.,0.5]); + + ringMesh1.position.setX(incenter[0]); + ringMesh1.position.setY(incenter[1]); + ringMesh1.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex3(), getVertex4(), getVertex5()); + var relRadius = inradius/inradius1; + + ringMesh1.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A1 = new THREE.Vector3(0.,-1.,0.10000000000000001); + const B1 = new THREE.Vector3(0.,1.,0.10000000000000001); + const C1 = new THREE.Vector3(0.5,1.,0.5); + + const normalVec1 = new THREE.Vector3(); + normalVec1.crossVectors(B1.sub(A1), C1.sub(A1)); + normalVec1.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal1 = new THREE.Vector3(0,0,1); + + const quaternionRotation1 = new THREE.Quaternion(); + quaternionRotation1.setFromUnitVectors(initialNormal1, normalVec1); + + ringMesh1.setRotationFromQuaternion(quaternionRotation1); + + return quaternionRotation1; + } + + ringRoot.add(ringMesh1); + + var inradius2 = calulateInradius(getVertex1(), getVertex2(), getVertex6()); + var incenter2 = calulateIncenter(getVertex1(), getVertex2(), getVertex6()); + var ringGeometry2 = new THREE.RingGeometry((inradius2 - 0.005),inradius2, 32); + const ringMaterial2 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh2 = new THREE.Mesh(ringGeometry2, ringMaterial2); + + function setCircleRotation2(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.,-1.,-0.10000000000000001],[ 0.,1.,-0.10000000000000001],[0.5,1.,-0.5]); + + ringMesh2.position.setX(incenter[0]); + ringMesh2.position.setY(incenter[1]); + ringMesh2.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex1(), getVertex2(), getVertex6()); + var relRadius = inradius/inradius2; + + ringMesh2.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A2 = new THREE.Vector3(0.,-1.,-0.10000000000000001); + const B2 = new THREE.Vector3(0.,1.,-0.10000000000000001); + const C2 = new THREE.Vector3(0.5,1.,-0.5); + + const normalVec2 = new THREE.Vector3(); + normalVec2.crossVectors(B2.sub(A2), C2.sub(A2)); + normalVec2.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal2 = new THREE.Vector3(0,0,1); + + const quaternionRotation2 = new THREE.Quaternion(); + quaternionRotation2.setFromUnitVectors(initialNormal2, normalVec2); + + ringMesh2.setRotationFromQuaternion(quaternionRotation2); + + return quaternionRotation2; + } + + ringRoot.add(ringMesh2); + + var inradius3 = calulateInradius(getVertex3(), getVertex4(), getVertex7()); + var incenter3 = calulateIncenter(getVertex3(), getVertex4(), getVertex7()); + var ringGeometry3 = new THREE.RingGeometry((inradius3 - 0.005),inradius3, 32); + const ringMaterial3 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh3 = new THREE.Mesh(ringGeometry3, ringMaterial3); + + function setCircleRotation3(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.,-1.,0.10000000000000001],[ 0.,1.,0.10000000000000001],[-0.5,1.,0.5]); + + ringMesh3.position.setX(incenter[0]); + ringMesh3.position.setY(incenter[1]); + ringMesh3.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex3(), getVertex4(), getVertex7()); + var relRadius = inradius/inradius3; + + ringMesh3.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A3 = new THREE.Vector3(0.,-1.,0.10000000000000001); + const B3 = new THREE.Vector3(0.,1.,0.10000000000000001); + const C3 = new THREE.Vector3(-0.5,1.,0.5); + + const normalVec3 = new THREE.Vector3(); + normalVec3.crossVectors(B3.sub(A3), C3.sub(A3)); + normalVec3.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal3 = new THREE.Vector3(0,0,1); + + const quaternionRotation3 = new THREE.Quaternion(); + quaternionRotation3.setFromUnitVectors(initialNormal3, normalVec3); + + ringMesh3.setRotationFromQuaternion(quaternionRotation3); + + return quaternionRotation3; + } + + ringRoot.add(ringMesh3); + + var inradius4 = calulateInradius(getVertex1(), getVertex2(), getVertex8()); + var incenter4 = calulateIncenter(getVertex1(), getVertex2(), getVertex8()); + var ringGeometry4 = new THREE.RingGeometry((inradius4 - 0.005),inradius4, 32); + const ringMaterial4 = new THREE.LineBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); + const ringMesh4 = new THREE.Mesh(ringGeometry4, ringMaterial4); + + function setCircleRotation4(){ + + //translate ring to incenter + var incenter = calulateIncenter([0.,-1.,-0.10000000000000001],[ 0.,1.,-0.10000000000000001],[-0.5,1.,-0.5]); + + ringMesh4.position.setX(incenter[0]); + ringMesh4.position.setY(incenter[1]); + ringMesh4.position.setZ(incenter[2]); + + // set the size right. Is done relative to the initial value, as we can only scale the mesh + var inradius = calulateInradius(getVertex1(), getVertex2(), getVertex8()); + var relRadius = inradius/inradius4; + + ringMesh4.scale.set(relRadius, relRadius, relRadius); + + // rotate ring to right angle + const A4 = new THREE.Vector3(0.,-1.,-0.10000000000000001); + const B4 = new THREE.Vector3(0.,1.,-0.10000000000000001); + const C4 = new THREE.Vector3(-0.5,1.,-0.5); + + const normalVec4 = new THREE.Vector3(); + normalVec4.crossVectors(B4.sub(A4), C4.sub(A4)); + normalVec4.normalize(); + + //initial normal vector of ringGeometry is (0,0,1), so we use that + const initialNormal4 = new THREE.Vector3(0,0,1); + + const quaternionRotation4 = new THREE.Quaternion(); + quaternionRotation4.setFromUnitVectors(initialNormal4, normalVec4); + + ringMesh4.setRotationFromQuaternion(quaternionRotation4); + + return quaternionRotation4; + } + + ringRoot.add(ringMesh4); + // function to update the circles every frame + function updateCircles(){ + setCircleRotation1(); + setCircleRotation2(); + setCircleRotation3(); + setCircleRotation4(); + } + + // needs to be called once to be initialized + updateCircles(); + + // function to update the circles width, that is called every frame even if the surface is not parameterized + function updateCircleWidth(){ + ringGeometry1.dispose(); + ringGeometry1 = new THREE.RingGeometry((inradius1 - guiParameters.circleWidth),inradius1, 32); + ringMesh1.geometry = ringGeometry1; + ringGeometry2.dispose(); + ringGeometry2 = new THREE.RingGeometry((inradius2 - guiParameters.circleWidth),inradius2, 32); + ringMesh2.geometry = ringGeometry2; + ringGeometry3.dispose(); + ringGeometry3 = new THREE.RingGeometry((inradius3 - guiParameters.circleWidth),inradius3, 32); + ringMesh3.geometry = ringGeometry3; + ringGeometry4.dispose(); + ringGeometry4 = new THREE.RingGeometry((inradius4 - guiParameters.circleWidth),inradius4, 32); + ringMesh4.geometry = ringGeometry4; + } + + updateCircleWidth(); + + // generate the normals trough the incenter orthogonal to the face + // getNormalsVectors generates the coordinates for the current values of the parameterized surface + function getNormalsVectors(){ + var vector1; + var vector2; + + var normals = []; + vector1 = []; + vector2 = []; + vector1[0] = (0.)-(0.); + vector1[1] = (1.)-(-1.); + vector1[2] = (0.1)-(0.1); + + vector2[0] = (0.5)-(0.); + vector2[1] = (1.)-(-1.); + vector2[2] = (0.5)-(0.1); + + var incenter = calulateIncenter([0.,-1.,0.10000000000000001],[ 0.,1.,0.10000000000000001],[0.5,1.,0.5]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.)-(0.); + vector1[1] = (1.)-(-1.); + vector1[2] = (-0.1)-(-0.1); + + vector2[0] = (0.5)-(0.); + vector2[1] = (1.)-(-1.); + vector2[2] = (-0.5)-(-0.1); + + var incenter = calulateIncenter([0.,-1.,-0.10000000000000001],[ 0.,1.,-0.10000000000000001],[0.5,1.,-0.5]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.)-(0.); + vector1[1] = (1.)-(-1.); + vector1[2] = (0.1)-(0.1); + + vector2[0] = (-0.5)-(0.); + vector2[1] = (1.)-(-1.); + vector2[2] = (0.5)-(0.1); + + var incenter = calulateIncenter([0.,-1.,0.10000000000000001],[ 0.,1.,0.10000000000000001],[-0.5,1.,0.5]); + normals.push([vector1, vector2, incenter]); + + vector1 = []; + vector2 = []; + vector1[0] = (0.)-(0.); + vector1[1] = (1.)-(-1.); + vector1[2] = (-0.1)-(-0.1); + + vector2[0] = (-0.5)-(0.); + vector2[1] = (1.)-(-1.); + vector2[2] = (-0.5)-(-0.1); + + var incenter = calulateIncenter([0.,-1.,-0.10000000000000001],[ 0.,1.,-0.10000000000000001],[-0.5,1.,-0.5]); + normals.push([vector1, vector2, incenter]); + + return normals; + } + // getNormalsCoordinates calculates the right coordinates for the ortogonality and fitting values from the gui + function getNormalsCoordinates(){ + var res = []; + var normals = getNormalsVectors(); + for(var i = 0; i < normals.length; i++){ + var plus = []; + var minus = []; + + minus[0] = normals[i][2][0] - (1/2)*guiParameters.normalsLength*(normals[i][0][1]*normals[i][1][2] - normals[i][0][2]*normals[i][1][1]); + minus[1] = normals[i][2][1] - (1/2)*guiParameters.normalsLength*(normals[i][0][2]*normals[i][1][0] - normals[i][0][0]*normals[i][1][2]); + minus[2] = normals[i][2][2] - (1/2)*guiParameters.normalsLength*(normals[i][0][0]*normals[i][1][1] - normals[i][0][1]*normals[i][1][0]); + + plus[0] = normals[i][2][0] + (1/2)*guiParameters.normalsLength*(normals[i][0][1]*normals[i][1][2] - normals[i][0][2]*normals[i][1][1]); + plus[1] = normals[i][2][1] + (1/2)*guiParameters.normalsLength*(normals[i][0][2]*normals[i][1][0] - normals[i][0][0]*normals[i][1][2]); + plus[2] = normals[i][2][2] + (1/2)*guiParameters.normalsLength*(normals[i][0][0]*normals[i][1][1] - normals[i][0][1]*normals[i][1][0]); + + res.push(minus[0]); + res.push(minus[1]); + res.push(minus[2]); + res.push(plus[0]); + res.push(plus[1]); + res.push(plus[2]); + } + res = Float32Array.from(res); + + + return res; + } + + + const normalsMaterial = new THREE.LineBasicMaterial( { + color: 0x000000, + } ); + + const normalsGeometry = new THREE.BufferGeometry(); + normalsGeometry.setAttribute( 'position', new THREE.BufferAttribute( getNormalsCoordinates(), 3 ) ); + var normalsLine = new THREE.LineSegments( normalsGeometry, normalsMaterial ); + + function updateNormals(){ + normalsGeometry.setAttribute( 'position', new THREE.BufferAttribute( getNormalsCoordinates(), 3 ) ); + normalsLine = new THREE.LineSegments( normalsGeometry, normalsMaterial ); + } + + normalsRoot.add(normalsLine); + + + // generate automatic ranges for the intersections if the surface is not parameterized + guiParameters.maxX = 0.5; + guiParameters.maxY = 1.; + guiParameters.maxZ = 0.5; + guiParameters.minX = -0.5; + guiParameters.minY = -1.; + guiParameters.minZ = -0.5; + + guiParameters.planeX = 0.; + guiParameters.planeY = 0.; + guiParameters.planeZ = 0.; + // --- end of generated output --- // + + const planeFolder = gui.addFolder("Intersection Planes"); + planeFolder.add(guiParameters, 'planeXactive'); + planeFolder.add(guiParameters, 'planeX', guiParameters.minX*1.1, guiParameters.maxX*1.1); + planeFolder.add(guiParameters, 'planeYactive'); + planeFolder.add(guiParameters, 'planeY', guiParameters.minY*1.1, guiParameters.maxY*1.1); + planeFolder.add(guiParameters, 'planeZactive'); + planeFolder.add(guiParameters, 'planeZ', guiParameters.minZ*1.1, guiParameters.maxZ*1.1); + + camera.position.z = Math.min((1.5)*guiParameters.minZ, -1) + camera.lookAt(0,0,-1); + + scene.background = new THREE.Color( 'white' ); + + // add both roots to the scene + scene.add( meshRoot ); + scene.add( wireRoot ); + scene.add( vertexRoot ); + scene.add( vertexlabelRoot ); + scene.add( edgeRoot ); + scene.add( ringRoot ); + scene.add( normalsRoot ); + scene.add( normalMeshRoot ); + + //presave some current gui parameters to only update if they change + var currentCircleWidth = guiParameters.circleWidth; + + function animate() { + requestAnimationFrame( animate ); + meshRoot.rotation.x += guiParameters.speedX/100; + meshRoot.rotation.y += guiParameters.speedY/100; + meshRoot.rotation.z += guiParameters.speedZ/100; + + wireRoot.rotation.x += guiParameters.speedX/100; + wireRoot.rotation.y += guiParameters.speedY/100; + wireRoot.rotation.z += guiParameters.speedZ/100; + + vertexRoot.rotation.x += guiParameters.speedX/100; + vertexRoot.rotation.y += guiParameters.speedY/100; + vertexRoot.rotation.z += guiParameters.speedZ/100; + + vertexlabelRoot.rotation.x += guiParameters.speedX/100; + vertexlabelRoot.rotation.y += guiParameters.speedY/100; + vertexlabelRoot.rotation.z += guiParameters.speedZ/100; + + edgeRoot.rotation.x += guiParameters.speedX/100; + edgeRoot.rotation.y += guiParameters.speedY/100; + edgeRoot.rotation.z += guiParameters.speedZ/100; + + ringRoot.rotation.x += guiParameters.speedX/100; + ringRoot.rotation.y += guiParameters.speedY/100; + ringRoot.rotation.z += guiParameters.speedZ/100; + + normalsRoot.rotation.x += guiParameters.speedX/100; + normalsRoot.rotation.y += guiParameters.speedY/100; + normalsRoot.rotation.z += guiParameters.speedZ/100; + + normalMeshRoot.rotation.x += guiParameters.speedX/100; + normalMeshRoot.rotation.y += guiParameters.speedY/100; + normalMeshRoot.rotation.z += guiParameters.speedZ/100; + + //update the light when the camera moves (with orbitcontrols) + light.position.set(camera.position.x, camera.position.y, camera.position.z); + + planeX.constant = guiParameters.planeX; + planeY.constant = guiParameters.planeY; + planeZ.constant = guiParameters.planeZ; + + activePlanes = []; + if(guiParameters.planeXactive){ + activePlanes.push(planeX); + } + if(guiParameters.planeYactive){ + activePlanes.push(planeY); + } + if(guiParameters.planeZactive){ + activePlanes.push(planeZ); + } + + if(vertexParametriziation){ + updateFaceCoordinates(); + if(guiParameters.edgeVisibility){ + updateEdgeCoordinates(); + } + if(guiParameters.vertexlabelVisibility || guiParameters.vertexVisibility){ + updateVertexCoordinates(); + } + if(guiParameters.circleVisibility){ + updateCircles(); + } + } + + //update stuff that changes from the gui + meshRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.opacity = guiParameters.transparency; + node.material.clippingPlanes = activePlanes; + if(guiParameters.normalsMaterial){ + node.material.opacity = 0; + } + } + } ); + + normalMeshRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.opacity = guiParameters.transparency; + node.material.clippingPlanes = activePlanes; + if(!guiParameters.normalsMaterial){ + node.material.opacity = 0; + } + } + } ); + + edgeRoot.traverse( function( node ) { + if ( node instanceof Line2 ) { + node.material.visible = guiParameters.edgeVisibility; + node.material.linewidth = guiParameters.edgeWidth/100; + } + if ( node instanceof THREE.LineSegments ) { + node.material.visible = guiParameters.edgeVisibility; + } + } ); + + vertexRoot.traverse( function( node ) { + if ( node instanceof THREE.Mesh ) { + node.material.visible = guiParameters.vertexVisibility; + node.scale.setScalar(guiParameters.vertexSize); + } + } ); + + vertexlabelRoot.traverse( function( node ) { + if( node instanceof CSS2DObject) { + node.visible = guiParameters.vertexlabelVisibility; + } + } ); + + ringRoot.traverse( function( node ) { + if( node instanceof THREE.Mesh) { + node.visible = guiParameters.circleVisibility; + } + } ); + + normalsRoot.traverse( function( node ) { + if( node instanceof THREE.LineSegments) { + node.visible = guiParameters.normalsVisibility; + } + } ); + + // update the circle width + if(guiParameters.circleVisibility && currentCircleWidth != guiParameters.circleWidth){ + updateCircleWidth(); + currentCircleWidth = guiParameters.circleWidth; + } + + //update the normals length + if(guiParameters.normalsVisibility){ + updateNormals(); + } + + controls.update(); + + renderer.localClippingEnabled = true; + + renderer.render( scene, camera ); + labelRenderer.render( scene, camera ); + } + animate(); + + //resize of window size changes + window.addEventListener( 'resize', onWindowResize ); + function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + labelRenderer.setSize( window.innerWidth, window.innerHeight ); + } +</script> + +</body> +</html> \ No newline at end of file