Differences
This shows you the differences between two versions of the page.
— | user_guide:tutorials:latest:visual_tutorial [2023/11/06 10:57] (current) – created - external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Tutorial for Visualization ====== | ||
+ | |||
+ | This tutorial contains some examples for the visualization of the different objects dealt with in polymake. | ||
+ | |||
+ | ===== Intro ===== | ||
+ | |||
+ | The most straightforward way of visualizing things in '' | ||
+ | |||
+ | <code perl> | ||
+ | > simplex(3)-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Tue Mar 29 16:03:37 2022 | ||
+ | unnamed | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <meta charset=utf-8> | ||
+ | < | ||
+ | < | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | */ | ||
+ | html {overflow: scroll;} | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | # | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_END | ||
+ | */ | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | <div id=' | ||
+ | <div class=group id=' | ||
+ | < | ||
+ | < | ||
+ | <div class=indented>< | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | <div class=suboption> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | <div class=suboption> | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | <select id=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <img id=' | ||
+ | <img id=' | ||
+ | <div id=" | ||
+ | </ | ||
+ | < | ||
+ | requirejs.config({ | ||
+ | paths: { | ||
+ | three: '/ | ||
+ | TrackballControls: | ||
+ | OrbitControls: | ||
+ | Projector: '/ | ||
+ | SVGRenderer: | ||
+ | WEBGL: '/ | ||
+ | }, | ||
+ | shim: { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | }); | ||
+ | | ||
+ | require([' | ||
+ | window.THREE = THREE; | ||
+ | require([' | ||
+ | | ||
+ | THREE.TrackballControls = TrackballControls; | ||
+ | THREE.OrbitControls = OrbitControls; | ||
+ | THREE.Projector = Projector; | ||
+ | THREE.SVGRenderer = SVGRenderer; | ||
+ | THREE.WEBGL = WEBGL; | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | |||
+ | const intervalLength = 25; // for automatic animations | ||
+ | const explodableModel = false; | ||
+ | const modelContains = { points: false, pointlabels: | ||
+ | const foldables = []; | ||
+ | |||
+ | var three = document.getElementById(" | ||
+ | var scene = new THREE.Scene(); | ||
+ | var renderer = new THREE.WebGLRenderer( { antialias: true } ); | ||
+ | var svgRenderer = new THREE.SVGRenderer( { antialias: true } ); | ||
+ | renderer.setPixelRatio( window.devicePixelRatio ); | ||
+ | renderer.setClearColor(0xFFFFFF, | ||
+ | svgRenderer.setClearColor(0xFFFFFF, | ||
+ | three.appendChild(renderer.domElement); | ||
+ | |||
+ | var frustumSize = 4; | ||
+ | var cameras = [new THREE.PerspectiveCamera(75, | ||
+ | cameras.forEach(function(cam) { | ||
+ | cam.position.set(0, | ||
+ | cam.lookAt(0, | ||
+ | cam.up.set(0, | ||
+ | }); | ||
+ | var controls = [new THREE.TrackballControls(cameras[0], | ||
+ | var camera, control; | ||
+ | |||
+ | controls[0].zoomSpeed = 0.2; | ||
+ | controls[0].rotateSpeed = 4; | ||
+ | |||
+ | |||
+ | // class to allow move points together with labels and spheres | ||
+ | var PMPoint = function (x,y,z) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addLabel = function(labelsprite) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addSphere = function(spheremesh) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.set = function(x, | ||
+ | | ||
+ | if (this.sprite) { | ||
+ | this.sprite.position.copy(this.vector); | ||
+ | } | ||
+ | if (this.sphere) { | ||
+ | this.sphere.position.copy(this.vector); | ||
+ | } | ||
+ | } | ||
+ | PMPoint.prototype.radius = function() { | ||
+ | if (this.sphere) { | ||
+ | return this.sphere.geometry.parameters.radius; | ||
+ | } else { | ||
+ | return 0; | ||
+ | } | ||
+ | }; | ||
+ | // select the target node | ||
+ | var target = document.querySelector('# | ||
+ | |||
+ | // create an observer instance | ||
+ | var observer = new MutationObserver(function(mutations) { | ||
+ | | ||
+ | if (mutation.removedNodes && mutation.removedNodes.length > 0) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | // configuration of the observer: | ||
+ | var config = { childList: true, characterData: | ||
+ | |||
+ | // pass in the target node, as well as the observer options | ||
+ | while (target) { | ||
+ | if (target.className==" | ||
+ | observer.observe(target, | ||
+ | break; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | var obj0 = new THREE.Object3D(); | ||
+ | obj0.name = " | ||
+ | obj0.userData.explodable = 1; | ||
+ | obj0.userData.points = []; | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 1)); | ||
+ | |||
+ | obj0.userData.pointradii = 0.02; | ||
+ | < | ||
+ | obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | obj0.userData.pointlabels = [" | ||
+ | obj0.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[2, 3, 1], [0, 3, 2], [1, 3, 0], [2, 1, 0]]; | ||
+ | < | ||
+ | obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj0); | ||
+ | scene.add(obj0); | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | function textSpriteMaterial(message, | ||
+ | if ( parameters === undefined ) parameters = {}; | ||
+ | var fontface = " | ||
+ | var fontsize = parameters.hasOwnProperty(" | ||
+ | fontsize = fontsize*10; | ||
+ | var lines = message.split(' | ||
+ | var size = 512; | ||
+ | for(var i = 0; i< | ||
+ | var tmp = lines[i].length; | ||
+ | while(tmp*fontsize > size){ | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | var canvas = document.createElement(' | ||
+ | canvas.width = size; | ||
+ | canvas.height = size; | ||
+ | var context = canvas.getContext(' | ||
+ | context.fillStyle = " | ||
+ | context.fill(); | ||
+ | context.font = fontsize + "px " + fontface; | ||
+ | | ||
+ | // text color | ||
+ | context.fillStyle = " | ||
+ | | ||
+ | context.fillText(lines[i], | ||
+ | } | ||
+ | | ||
+ | // canvas contents will be used for a texture | ||
+ | var texture = new THREE.Texture(canvas); | ||
+ | texture.needsUpdate = true; | ||
+ | | ||
+ | var spriteMaterial = new THREE.SpriteMaterial({map: | ||
+ | return spriteMaterial; | ||
+ | } | ||
+ | |||
+ | |||
+ | // ---------------------- INITIALIZING OBJECTS-------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function init_object(obj) { | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_points(obj); | ||
+ | modelContains.points = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_pointlabels(obj); | ||
+ | modelContains.pointlabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_lines(obj); | ||
+ | modelContains.lines = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_edgelabels(obj); | ||
+ | modelContains.edgelabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_arrowheads(obj); | ||
+ | modelContains.arrowheads = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_faces(obj); | ||
+ | modelContains.faces = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function init_points(obj) { | ||
+ | var pointgroup = new THREE.Group(); | ||
+ | pointgroup.name = " | ||
+ | var points = obj.userData.points; | ||
+ | var radii = obj.userData.pointradii; | ||
+ | var materials = obj.userData.pointmaterial; | ||
+ | var geometry, | ||
+ | if (!Array.isArray(radii)) { | ||
+ | geometry = new THREE.SphereBufferGeometry(radii); | ||
+ | } | ||
+ | if (!Array.isArray(materials)) { | ||
+ | material = materials; | ||
+ | } | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | if (Array.isArray(radii)) { | ||
+ | if (radii[i] == 0) { | ||
+ | continue; | ||
+ | } | ||
+ | geometry = new THREE.SphereBufferGeometry(radii[i]); | ||
+ | } | ||
+ | if (Array.isArray(materials)) { | ||
+ | material = materials[i]; | ||
+ | } | ||
+ | var sphere = new THREE.Mesh(geometry, | ||
+ | point.addSphere(sphere); | ||
+ | pointgroup.add(sphere); | ||
+ | } | ||
+ | obj.add(pointgroup); | ||
+ | } | ||
+ | |||
+ | function init_pointlabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var labels = obj.userData.pointlabels; | ||
+ | var pointlabels = new THREE.Group(); | ||
+ | pointlabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(pointlabels); | ||
+ | } | ||
+ | |||
+ | function init_lines(obj) { | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var points = obj.userData.points; | ||
+ | var materials = obj.userData.edgematerial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 ); | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | for (var i=0; i< | ||
+ | geometry.addGroup(2*i, | ||
+ | } | ||
+ | } | ||
+ | var lines = new THREE.LineSegments(geometry, | ||
+ | lines.name = " | ||
+ | obj.add(lines); | ||
+ | updateEdgesPosition(obj); | ||
+ | } | ||
+ | |||
+ | function init_edgelabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var labels = obj.userData.edgelabels; | ||
+ | var edgelabels = new THREE.Group(); | ||
+ | edgelabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(edgelabels); | ||
+ | } | ||
+ | |||
+ | function init_arrowheads(obj) { | ||
+ | var arrowheads = new THREE.Group(); | ||
+ | arrowheads.name = " | ||
+ | var arrowstyle = obj.userData.arrowstyle; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var edgematerials = obj.userData.edgematerial; | ||
+ | var points = obj.userData.points; | ||
+ | var material; | ||
+ | if (!Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials.color} ); | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var start = points[edgeindices[i]]; | ||
+ | var end = points[edgeindices[i+1]]; | ||
+ | var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius(); | ||
+ | if (dist <= 0) { | ||
+ | continue; | ||
+ | } | ||
+ | var dir = new THREE.Vector3().subVectors(end.vector, | ||
+ | dir.normalize(); | ||
+ | var axis = new THREE.Vector3().set(dir.z, | ||
+ | axis.normalize(); | ||
+ | var radians = Math.acos( dir.y ); | ||
+ | var radius = dist/25; | ||
+ | var height = dist/5; | ||
+ | var geometry = new THREE.ConeBufferGeometry(radius, | ||
+ | var position = new THREE.Vector3().addVectors(start.vector, | ||
+ | if (Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} ); | ||
+ | } | ||
+ | var cone = new THREE.Mesh( geometry, material ); | ||
+ | cone.quaternion.setFromAxisAngle(axis, | ||
+ | cone.position.copy(position);; | ||
+ | arrowheads.add(cone); | ||
+ | } | ||
+ | obj.add(arrowheads); | ||
+ | } | ||
+ | |||
+ | function init_faces(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var facets = obj.userData.facets; | ||
+ | obj.userData.triangleindices = []; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | for (var t=0; t< | ||
+ | obj.userData.triangleindices.push(facet[0], | ||
+ | } | ||
+ | } | ||
+ | var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute(bufarr, | ||
+ | | ||
+ | var materials = obj.userData.facetmaterial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var frontmaterials = []; | ||
+ | var backmaterials = []; | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | var tricount = 0; | ||
+ | var facet; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | geometry.addGroup(tricount, | ||
+ | tricount += (facet.length-2)*3; | ||
+ | } | ||
+ | for (var j=0; j< | ||
+ | var fmat = materials[j].clone() | ||
+ | fmat.side = THREE.FrontSide; | ||
+ | frontmaterials.push(fmat); | ||
+ | var bmat = materials[j].clone() | ||
+ | bmat.side = THREE.BackSide; | ||
+ | backmaterials.push(bmat); | ||
+ | obj.userData.facetmaterial = frontmaterials.concat(backmaterials); | ||
+ | } | ||
+ | } else if (materials instanceof THREE.Material) { | ||
+ | frontmaterials = materials.clone() | ||
+ | frontmaterials.side = THREE.FrontSide; | ||
+ | backmaterials = materials.clone() | ||
+ | backmaterials.side = THREE.BackSide; | ||
+ | obj.userData.facetmaterial = [frontmaterials, | ||
+ | } | ||
+ | // duplicating the object with front and back should avoid transparency issues | ||
+ | var backmesh = new THREE.Mesh(geometry, | ||
+ | // meshname is used to show/hide objects | ||
+ | backmesh.name = " | ||
+ | obj.add(backmesh); | ||
+ | var frontmesh = new THREE.Mesh(geometry, | ||
+ | frontmesh.name = " | ||
+ | obj.add(frontmesh); | ||
+ | updateFacesPosition(obj); | ||
+ | } | ||
+ | // // | ||
+ | |||
+ | |||
+ | function updateFacesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.triangleindices; | ||
+ | var faces = obj.getObjectByName(" | ||
+ | var ba = faces.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | faces.geometry.attributes.position.needsUpdate = true; | ||
+ | | ||
+ | } | ||
+ | |||
+ | function updateEdgesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.edgeindices; | ||
+ | var lines = obj.getObjectByName(" | ||
+ | var ba = lines.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | lines.geometry.attributes.position.needsUpdate = true; | ||
+ | } | ||
+ | |||
+ | function onWindowResize() { | ||
+ | renderer.setSize( three.clientWidth, | ||
+ | svgRenderer.setSize( three.clientWidth, | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | function updateCamera() { | ||
+ | var width = three.clientWidth; | ||
+ | var height = three.clientHeight; | ||
+ | var aspect = width / height; | ||
+ | if (camera.type == " | ||
+ | camera.left = frustumSize * aspect / - 2; | ||
+ | camera.right = frustumSize * aspect / 2; | ||
+ | camera.top = frustumSize / 2; | ||
+ | camera.bottom = - frustumSize / 2; | ||
+ | } else if (camera.type == " | ||
+ | camera.aspect = aspect; | ||
+ | } | ||
+ | camera.updateProjectionMatrix(); | ||
+ | } | ||
+ | |||
+ | function changeCamera(event) { | ||
+ | var selindex = event.currentTarget.selectedIndex; | ||
+ | camera = cameras[selindex]; | ||
+ | control = controls[selindex]; | ||
+ | control.enabled = true; | ||
+ | for (var i=0; i< | ||
+ | if (i!=selindex) { | ||
+ | controls[i].enabled = false; | ||
+ | } | ||
+ | } | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | var camtypenode = document.getElementById(' | ||
+ | camtypenode.onchange = changeCamera; | ||
+ | camtypenode.dispatchEvent(new Event(' | ||
+ | |||
+ | onWindowResize(); | ||
+ | window.addEventListener(' | ||
+ | |||
+ | |||
+ | var xRotationEnabled = false; | ||
+ | var yRotationEnabled = false; | ||
+ | var zRotationEnabled = false; | ||
+ | var rotationSpeedFactor = 1; | ||
+ | var settingsShown = false; | ||
+ | var labelsShown = true; | ||
+ | var intervals = []; | ||
+ | var timeouts = []; | ||
+ | var explodingSpeed = 0.05; | ||
+ | var explodeScale = 0.000001; | ||
+ | var XMLS = new XMLSerializer(); | ||
+ | var svgElement; | ||
+ | var renderId; | ||
+ | |||
+ | var render = function () { | ||
+ | |||
+ | renderId = requestAnimationFrame(render); | ||
+ | |||
+ | // comment in for automatic explosion | ||
+ | // | ||
+ | |||
+ | var phi = 0.02 * rotationSpeedFactor; | ||
+ | |||
+ | if (xRotationEnabled) { | ||
+ | scene.rotation.x += phi; | ||
+ | } | ||
+ | if (yRotationEnabled) { | ||
+ | scene.rotation.y += phi; | ||
+ | } | ||
+ | if (zRotationEnabled) { | ||
+ | scene.rotation.z += phi; | ||
+ | } | ||
+ | |||
+ | control.update(); | ||
+ | renderer.render(scene, | ||
+ | }; | ||
+ | |||
+ | if ( THREE.WEBGL.isWebGLAvailable() ) { | ||
+ | render(); | ||
+ | } else { | ||
+ | var warning = WEBGL.getWebGLErrorMessage(); | ||
+ | three.appendChild( warning ); | ||
+ | } | ||
+ | | ||
+ | function changeTransparency() { | ||
+ | var opacity = 1-Number(event.currentTarget.value); | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].opacity = opacity; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.opacity = opacity; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleDepthWrite(event) { | ||
+ | depthwrite = event.currentTarget.checked; | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].depthWrite = depthwrite; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.depthWrite = depthWrite; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function changeRotationX(event){ | ||
+ | xRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationY(event){ | ||
+ | yRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationZ(event){ | ||
+ | zRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | |||
+ | function changeRotationSpeedFactor(event){ | ||
+ | rotationSpeedFactor = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function resetScene(){ | ||
+ | scene.rotation.set(0, | ||
+ | camera.position.set(0, | ||
+ | camera.up.set(0, | ||
+ | } | ||
+ | |||
+ | function showSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = true; | ||
+ | } | ||
+ | |||
+ | function hideSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = false; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | var pos = 150* Math.PI; | ||
+ | |||
+ | function updateFactor() { | ||
+ | pos++; | ||
+ | return Math.sin(.01*pos)+1; | ||
+ | } | ||
+ | |||
+ | // ------------------------ FOLDING ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | // rotate point p around axis defined by points p1 and p2 by given angle | ||
+ | function rotate(p, p1, p2, angle ){ | ||
+ | angle = -angle; | ||
+ | var x = p.x, y = p.y, z = p.z, | ||
+ | a = p1.x, b = p1.y, c = p1.z, | ||
+ | u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z; | ||
+ | var result = []; | ||
+ | var L = u*u + v*v + w*w; | ||
+ | var sqrt = Math.sqrt; | ||
+ | var cos = Math.cos; | ||
+ | var sin = Math.sin; | ||
+ | |||
+ | result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/ | ||
+ | result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/ | ||
+ | result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/ | ||
+ | |||
+ | return result; | ||
+ | } | ||
+ | |||
+ | var fold = function(event){ | ||
+ | var obj = foldables[Number(event.currentTarget.name)]; | ||
+ | var foldvalue = Number(event.currentTarget.value); | ||
+ | var scale = foldvalue - obj.userData.oldscale; | ||
+ | |||
+ | for (var j=0; j< | ||
+ | rotateVertices(obj, | ||
+ | } | ||
+ | update(obj); | ||
+ | obj.userData.oldscale += scale; | ||
+ | lookAtBarycenter(obj); | ||
+ | } | ||
+ | |||
+ | function lookAtBarycenter(obj){ | ||
+ | control.target = barycenter(obj); | ||
+ | } | ||
+ | |||
+ | function barycenter(obj) { | ||
+ | var center = new THREE.Vector3(0, | ||
+ | var points = obj.userData.points; | ||
+ | for (var i=0; i< | ||
+ | center.add(points[i].vector); | ||
+ | } | ||
+ | center.divideScalar(points.length); | ||
+ | return center; | ||
+ | } | ||
+ | |||
+ | function rotateVertices(obj, | ||
+ | var axes = obj.userData.axes; | ||
+ | var subtrees = obj.userData.subtrees; | ||
+ | var points = obj.userData.points; | ||
+ | var angles = obj.userData.angles; | ||
+ | if (edge < axes.length){ | ||
+ | for (var j=0; j< | ||
+ | var rotP = rotate(points[subtrees[edge][j]].vector, | ||
+ | points[subtrees[edge][j]].set(rotP[0], | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function update(obj) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | if (foldables.length) { | ||
+ | var settings = document.getElementById(' | ||
+ | var foldDiv = document.createElement(' | ||
+ | foldDiv.id = ' | ||
+ | var title = document.createElement(' | ||
+ | title.innerHTML = ' | ||
+ | foldDiv.appendChild(title); | ||
+ | foldDiv.className = ' | ||
+ | for (var i=0; i< | ||
+ | var range = document.createElement(' | ||
+ | range.type = ' | ||
+ | range.min = 0; | ||
+ | range.max = 1; | ||
+ | range.value = 0; | ||
+ | range.step = 0.001; | ||
+ | range.name = String(i); | ||
+ | range.oninput = fold; | ||
+ | foldDiv.appendChild(range); | ||
+ | } | ||
+ | lookAtBarycenter(foldables[0]); | ||
+ | settings.insertBefore(foldDiv, | ||
+ | } | ||
+ | |||
+ | | ||
+ | // ---------------------- EXPLOSION ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | if (explodableModel) { | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | if ( obj.userData.explodable ) { | ||
+ | computeCentroid(obj); | ||
+ | } | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | explode(0.000001); | ||
+ | } | ||
+ | |||
+ | function computeCentroid(obj) { | ||
+ | centroid = new THREE.Vector3(); | ||
+ | obj.userData.points.forEach(function(pmpoint) { | ||
+ | centroid.add(pmpoint.vector); | ||
+ | }); | ||
+ | centroid.divideScalar(obj.userData.points.length); | ||
+ | obj.userData.centroid = centroid; | ||
+ | } | ||
+ | |||
+ | function explode(factor) { | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i]; | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | var c = obj.userData.centroid; | ||
+ | obj.position.set(c.x*factor, | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function triggerExplode(event){ | ||
+ | explodeScale = Number(event.currentTarget.value); | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | |||
+ | function setExplodingSpeed(event){ | ||
+ | explodingSpeed = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function triggerAutomaticExplode(event){ | ||
+ | if (event.currentTarget.checked){ | ||
+ | startExploding(); | ||
+ | } else { | ||
+ | clearIntervals(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function startExploding(){ | ||
+ | intervals.push(setInterval(explodingInterval, | ||
+ | } | ||
+ | |||
+ | |||
+ | function explodingInterval(){ | ||
+ | explodeScale += explodingSpeed; | ||
+ | if (explodeScale <= 6){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else{ | ||
+ | explode(6); | ||
+ | explodeScale = 6; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startUnexploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | |||
+ | function startUnexploding(){ | ||
+ | intervals.push(setInterval(unexplodingInterval, | ||
+ | } | ||
+ | |||
+ | function unexplodingInterval(){ | ||
+ | explodeScale -= explodingSpeed; | ||
+ | if (explodeScale >= 0){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else { | ||
+ | explode(0); | ||
+ | explodeScale = 0; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startExploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | function clearIntervals(){ | ||
+ | intervals.forEach(function(interval){ | ||
+ | clearInterval(interval); | ||
+ | }); | ||
+ | intervals = []; | ||
+ | timeouts.forEach(function(timeout){ | ||
+ | clearTimeout(timeout); | ||
+ | }); | ||
+ | timeouts = []; | ||
+ | } | ||
+ | |||
+ | // ---------------------- DISPLAY -------------------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | const objectTypeInnerHTMLs = { points: " | ||
+ | const objectTypeVisible = {}; | ||
+ | Object.assign(objectTypeVisible, | ||
+ | const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort(); | ||
+ | const shownObjectTypesList = document.getElementById(' | ||
+ | |||
+ | function setVisibility(bool, | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i].getObjectByName(objname); | ||
+ | if (obj) { | ||
+ | obj.visible = bool; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleObjectTypeVisibility(event){ | ||
+ | var name = event.currentTarget.name; | ||
+ | var checked = event.currentTarget.checked; | ||
+ | objectTypeVisible[name] = checked; | ||
+ | if (name == " | ||
+ | setVisibility(checked," | ||
+ | setVisibility(checked," | ||
+ | } else { | ||
+ | setVisibility(checked, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var key = sortedObjectTypeKeys[i]; | ||
+ | if (modelContains[key]) { | ||
+ | var objTypeNode = document.createElement(' | ||
+ | objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = key; | ||
+ | checkbox.onchange = toggleObjectTypeVisibility; | ||
+ | shownObjectTypesList.appendChild(checkbox); | ||
+ | shownObjectTypesList.appendChild(objTypeNode); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // ------------------------------------------------------ | ||
+ | |||
+ | function toggleObjectVisibility(event){ | ||
+ | var nr = Number(event.currentTarget.name); | ||
+ | scene.children[nr].visible = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | // append checkboxes for displaying or hiding objects | ||
+ | var shownObjectsList = document.getElementById(' | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | var objNode = document.createElement(' | ||
+ | objNode.innerHTML = obj.name + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = String(i); | ||
+ | checkbox.onchange = toggleObjectVisibility; | ||
+ | shownObjectsList.appendChild(checkbox); | ||
+ | shownObjectsList.appendChild(objNode); | ||
+ | } | ||
+ | |||
+ | // ---------------------- SVG ------------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function takeSvgScreenshot() { | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | svgRenderer.render(scene, | ||
+ | svgElement = XMLS.serializeToString(svgRenderer.domElement); | ||
+ | | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | |||
+ | if (document.getElementById(' | ||
+ | //show in new tab | ||
+ | var myWindow = window.open("","" | ||
+ | myWindow.document.body.innerHTML = svgElement; | ||
+ | } else{ | ||
+ | // download svg file | ||
+ | download(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function download(filename, | ||
+ | var element = document.createElement(' | ||
+ | element.setAttribute(' | ||
+ | element.setAttribute(' | ||
+ | |||
+ | element.style.display = ' | ||
+ | document.body.appendChild(element); | ||
+ | |||
+ | element.click(); | ||
+ | |||
+ | document.body.removeChild(element); | ||
+ | } | ||
+ | |||
+ | |||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | |||
+ | |||
+ | // ------------------ SHORTCUTS -------------------------------------------- | ||
+ | // ------------------------------------------------------------------------- | ||
+ | |||
+ | /** | ||
+ | * http:// | ||
+ | * Version : 2.01.B | ||
+ | * By Binny V A | ||
+ | * License : BSD | ||
+ | */ | ||
+ | shortcut = { | ||
+ | ' | ||
+ | ' | ||
+ | //Provide a set of default options | ||
+ | var default_options = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | if(!opt) opt = default_options; | ||
+ | else { | ||
+ | for(var dfo in default_options) { | ||
+ | if(typeof opt[dfo] == ' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var ele = opt.target; | ||
+ | if(typeof opt.target == ' | ||
+ | var ths = this; | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | |||
+ | //The function to be called at keypress | ||
+ | var func = function(e) { | ||
+ | e = e || window.event; | ||
+ | |||
+ | if(opt[' | ||
+ | var element; | ||
+ | if(e.target) element=e.target; | ||
+ | else if(e.srcElement) element=e.srcElement; | ||
+ | if(element.nodeType==3) element=element.parentNode; | ||
+ | |||
+ | if(element.tagName == ' | ||
+ | } | ||
+ | |||
+ | //Find Which key is pressed | ||
+ | if (e.keyCode) code = e.keyCode; | ||
+ | else if (e.which) code = e.which; | ||
+ | var character = String.fromCharCode(code).toLowerCase(); | ||
+ | |||
+ | if(code == 188) character=","; | ||
+ | if(code == 190) character=" | ||
+ | |||
+ | var keys = shortcut_combination.split(" | ||
+ | //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked | ||
+ | var kp = 0; | ||
+ | |||
+ | //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken | ||
+ | var shift_nums = { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | ";":":", | ||
+ | "'":" | ||
+ | ",":"<", | ||
+ | " | ||
+ | "/":"?", | ||
+ | " | ||
+ | } | ||
+ | // | ||
+ | var special_keys = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | |||
+ | var modifiers = { | ||
+ | shift: { wanted: | ||
+ | ctrl : { wanted: | ||
+ | alt | ||
+ | meta : { wanted: | ||
+ | }; | ||
+ | | ||
+ | if(e.ctrlKey) modifiers.ctrl.pressed = true; | ||
+ | if(e.shiftKey) modifiers.shift.pressed = true; | ||
+ | if(e.altKey) modifiers.alt.pressed = true; | ||
+ | if(e.metaKey) | ||
+ | | ||
+ | for(var i=0; k=keys[i], | ||
+ | // | ||
+ | if(k == ' | ||
+ | kp++; | ||
+ | modifiers.ctrl.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.shift.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.alt.wanted = true; | ||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.meta.wanted = true; | ||
+ | } else if(k.length > 1) { //If it is a special key | ||
+ | if(special_keys[k] == code) kp++; | ||
+ | |||
+ | } else if(opt[' | ||
+ | if(opt[' | ||
+ | |||
+ | } else { //The special keys did not match | ||
+ | if(character == k) kp++; | ||
+ | else { | ||
+ | if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase | ||
+ | character = shift_nums[character]; | ||
+ | if(character == k) kp++; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if(kp == keys.length && | ||
+ | modifiers.ctrl.pressed == modifiers.ctrl.wanted && | ||
+ | modifiers.shift.pressed == modifiers.shift.wanted && | ||
+ | modifiers.alt.pressed == modifiers.alt.wanted && | ||
+ | modifiers.meta.pressed == modifiers.meta.wanted) { | ||
+ | callback(e); | ||
+ | |||
+ | if(!opt[' | ||
+ | // | ||
+ | e.cancelBubble = true; | ||
+ | e.returnValue = false; | ||
+ | |||
+ | // | ||
+ | if (e.stopPropagation) { | ||
+ | e.stopPropagation(); | ||
+ | e.preventDefault(); | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | this.all_shortcuts[shortcut_combination] = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }; | ||
+ | //Attach the function with the event | ||
+ | if(ele.addEventListener) ele.addEventListener(opt[' | ||
+ | else if(ele.attachEvent) ele.attachEvent(' | ||
+ | else ele[' | ||
+ | }, | ||
+ | |||
+ | //Remove the shortcut - just specify the shortcut and I will remove the binding | ||
+ | ' | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | var binding = this.all_shortcuts[shortcut_combination]; | ||
+ | delete(this.all_shortcuts[shortcut_combination]) | ||
+ | if(!binding) return; | ||
+ | var type = binding[' | ||
+ | var ele = binding[' | ||
+ | var callback = binding[' | ||
+ | |||
+ | if(ele.detachEvent) ele.detachEvent(' | ||
+ | else if(ele.removeEventListener) ele.removeEventListener(type, | ||
+ | else ele[' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | shortcut.add(" | ||
+ | var event = new Event(' | ||
+ | if (settingsShown){ | ||
+ | document.getElementById(' | ||
+ | } else { | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | By default, this will open '' | ||
+ | |||
+ | To get a list of visualization methods available, you can use the build-in help system. To obtain the visualization possibilities for, e.g., Polytopes in application '' | ||
+ | |||
+ | <code perl> | ||
+ | > help ' | ||
+ | These methods are for visualization. | ||
+ | |||
+ | ------------------- | ||
+ | Subtopics of polytope/ | ||
+ | GALE, SCHLEGEL, VISUAL, VISUAL_BOUNDED_GRAPH, | ||
+ | Subtopics of objects/ | ||
+ | GALE, SCHLEGEL, VISUAL, VISUAL_BOUNDED_GRAPH, | ||
+ | VISUAL_DUAL_GRAPH, | ||
+ | </ | ||
+ | Most visualization methods provide a variety of parameters. Get a list for the method of yout choice (here: '' | ||
+ | |||
+ | <code perl> | ||
+ | > help ' | ||
+ | VISUAL(Options) -> Visual:: | ||
+ | |||
+ | | ||
+ | or as a Schlegel diagram (4d). | ||
+ | |||
+ | Options: | ||
+ | __FacetColor__ => Flexible< | ||
+ | __FacetTransparency__ => Flexible< | ||
+ | __FacetStyle__ => Flexible< | ||
+ | __FacetLabels__ => String if set to " | ||
+ | __EdgeColor__ => Color color of the boundary lines | ||
+ | __EdgeThickness__ => Float scaling factor for the thickness of the boundary lines | ||
+ | __EdgeStyle__ => String if set to " | ||
+ | __Title__ => String the name of the drawing | ||
+ | __Name__ => String the name of this visual object in the drawing | ||
+ | __Hidden__ => Bool if set to true, the visual object is not rendered | ||
+ | (useful for interactive visualization programs allowing for switching details on and off) | ||
+ | __PointLabels__ => String if set to " | ||
+ | __VertexLabels__ => String alias for PointLabels | ||
+ | __PointColor__ => Flexible< | ||
+ | __VertexColor__ => Flexible< | ||
+ | __PointThickness__ => Flexible< | ||
+ | __VertexThickness__ => Flexible< | ||
+ | __PointBorderColor__ => Flexible< | ||
+ | __VertexBorderColor__ => Flexible< | ||
+ | __PointBorderThickness__ => Flexible< | ||
+ | __VertexBorderThickness__ => Flexible< | ||
+ | __PointStyle__ => Flexible< | ||
+ | __VertexStyle__ => Flexible< | ||
+ | __ViewPoint__ => Vector< | ||
+ | __ViewDirection__ => Vector< | ||
+ | __ViewUp__ => Vector< | ||
+ | __Scale__ => Float scale for Sketch visualization | ||
+ | __LabelAlignment__ => Flexible< | ||
+ | |||
+ | Options: | ||
+ | | ||
+ | __EdgeColor__ => Flexible< | ||
+ | __EdgeThickness__ => Flexible< | ||
+ | __EdgeLabels__ => EdgeMap< | ||
+ | __EdgeStyle__ => Flexible< | ||
+ | __Title__ => String the name of the drawing | ||
+ | __Name__ => String the name of this visual object in the drawing | ||
+ | __Hidden__ => Bool if set to true, the visual object is not rendered | ||
+ | (useful for interactive visualization programs allowing for switching details on and off) | ||
+ | __PointLabels__ => String if set to " | ||
+ | __VertexLabels__ => String alias for PointLabels | ||
+ | __PointColor__ => Flexible< | ||
+ | __VertexColor__ => Flexible< | ||
+ | __PointThickness__ => Flexible< | ||
+ | __VertexThickness__ => Flexible< | ||
+ | __PointBorderColor__ => Flexible< | ||
+ | __VertexBorderColor__ => Flexible< | ||
+ | __PointBorderThickness__ => Flexible< | ||
+ | __VertexBorderThickness__ => Flexible< | ||
+ | __PointStyle__ => Flexible< | ||
+ | __VertexStyle__ => Flexible< | ||
+ | __ViewPoint__ => Vector< | ||
+ | __ViewDirection__ => Vector< | ||
+ | __ViewUp__ => Vector< | ||
+ | __Scale__ => Float scale for Sketch visualization | ||
+ | __LabelAlignment__ => Flexible< | ||
+ | |||
+ | Options: | ||
+ | | ||
+ | | ||
+ | __Title__ => String the name of the drawing | ||
+ | __Name__ => String the name of this visual object in the drawing | ||
+ | __Hidden__ => Bool if set to true, the visual object is not rendered | ||
+ | (useful for interactive visualization programs allowing for switching details on and off) | ||
+ | __PointLabels__ => String if set to " | ||
+ | __VertexLabels__ => String alias for PointLabels | ||
+ | __PointColor__ => Flexible< | ||
+ | __VertexColor__ => Flexible< | ||
+ | __PointThickness__ => Flexible< | ||
+ | __VertexThickness__ => Flexible< | ||
+ | __PointBorderColor__ => Flexible< | ||
+ | __VertexBorderColor__ => Flexible< | ||
+ | __PointBorderThickness__ => Flexible< | ||
+ | __VertexBorderThickness__ => Flexible< | ||
+ | __PointStyle__ => Flexible< | ||
+ | __VertexStyle__ => Flexible< | ||
+ | __ViewPoint__ => Vector< | ||
+ | __ViewDirection__ => Vector< | ||
+ | __ViewUp__ => Vector< | ||
+ | __Scale__ => Float scale for Sketch visualization | ||
+ | __LabelAlignment__ => Flexible< | ||
+ | |||
+ | Options: | ||
+ | __BoundingFacets__ => Matrix useful for unbounded polyhedra | ||
+ | __Transformation__ => Matrix< | ||
+ | __Offset__ => Vector< | ||
+ | |||
+ | Returns Visual:: | ||
+ | |||
+ | </ | ||
+ | The syntax for passing parameters can be seen in this example: | ||
+ | |||
+ | < | ||
+ | simplex(3)-> | ||
+ | </ | ||
+ | It visualizes a tetrahedron with really thick edges. See the section on [[visual_tutorial# | ||
+ | |||
+ | ==== Specifying colors ==== | ||
+ | |||
+ | Some visualization methods requite you to specify colors. There are various ways of doing this in polymake, i.e. the color red may be given by | ||
+ | |||
+ | * the String '' | ||
+ | * the String '' | ||
+ | * the String '' | ||
+ | * an object '' | ||
+ | |||
+ | ===== application polytope ===== | ||
+ | |||
+ | The application ' | ||
+ | |||
+ | ==== Changing vertex attributes ==== | ||
+ | |||
+ | It is possible to change the way the vertices are displayed directly from the command line. In the following we will explain how to change the color, labels, and size of the vertices. | ||
+ | |||
+ | === Colors === | ||
+ | |||
+ | There are different ways to specify the colors of the vertices. You may choose a single color for all vertices or set each vertex color individually. | ||
+ | |||
+ | **Single color**: To specify one color for all vertices use the // | ||
+ | |||
+ | <code perl> | ||
+ | > simplex(3)-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Tue Mar 29 16:03:37 2022 | ||
+ | unnamed | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <meta charset=utf-8> | ||
+ | < | ||
+ | < | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | */ | ||
+ | html {overflow: scroll;} | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | # | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_END | ||
+ | */ | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | <div id=' | ||
+ | <div class=group id=' | ||
+ | < | ||
+ | < | ||
+ | <div class=indented>< | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | <div class=suboption> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | <div class=suboption> | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | <select id=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <img id=' | ||
+ | <img id=' | ||
+ | <div id=" | ||
+ | </ | ||
+ | < | ||
+ | requirejs.config({ | ||
+ | paths: { | ||
+ | three: '/ | ||
+ | TrackballControls: | ||
+ | OrbitControls: | ||
+ | Projector: '/ | ||
+ | SVGRenderer: | ||
+ | WEBGL: '/ | ||
+ | }, | ||
+ | shim: { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | }); | ||
+ | | ||
+ | require([' | ||
+ | window.THREE = THREE; | ||
+ | require([' | ||
+ | | ||
+ | THREE.TrackballControls = TrackballControls; | ||
+ | THREE.OrbitControls = OrbitControls; | ||
+ | THREE.Projector = Projector; | ||
+ | THREE.SVGRenderer = SVGRenderer; | ||
+ | THREE.WEBGL = WEBGL; | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | |||
+ | const intervalLength = 25; // for automatic animations | ||
+ | const explodableModel = false; | ||
+ | const modelContains = { points: false, pointlabels: | ||
+ | const foldables = []; | ||
+ | |||
+ | var three = document.getElementById(" | ||
+ | var scene = new THREE.Scene(); | ||
+ | var renderer = new THREE.WebGLRenderer( { antialias: true } ); | ||
+ | var svgRenderer = new THREE.SVGRenderer( { antialias: true } ); | ||
+ | renderer.setPixelRatio( window.devicePixelRatio ); | ||
+ | renderer.setClearColor(0xFFFFFF, | ||
+ | svgRenderer.setClearColor(0xFFFFFF, | ||
+ | three.appendChild(renderer.domElement); | ||
+ | |||
+ | var frustumSize = 4; | ||
+ | var cameras = [new THREE.PerspectiveCamera(75, | ||
+ | cameras.forEach(function(cam) { | ||
+ | cam.position.set(0, | ||
+ | cam.lookAt(0, | ||
+ | cam.up.set(0, | ||
+ | }); | ||
+ | var controls = [new THREE.TrackballControls(cameras[0], | ||
+ | var camera, control; | ||
+ | |||
+ | controls[0].zoomSpeed = 0.2; | ||
+ | controls[0].rotateSpeed = 4; | ||
+ | |||
+ | |||
+ | // class to allow move points together with labels and spheres | ||
+ | var PMPoint = function (x,y,z) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addLabel = function(labelsprite) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addSphere = function(spheremesh) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.set = function(x, | ||
+ | | ||
+ | if (this.sprite) { | ||
+ | this.sprite.position.copy(this.vector); | ||
+ | } | ||
+ | if (this.sphere) { | ||
+ | this.sphere.position.copy(this.vector); | ||
+ | } | ||
+ | } | ||
+ | PMPoint.prototype.radius = function() { | ||
+ | if (this.sphere) { | ||
+ | return this.sphere.geometry.parameters.radius; | ||
+ | } else { | ||
+ | return 0; | ||
+ | } | ||
+ | }; | ||
+ | // select the target node | ||
+ | var target = document.querySelector('# | ||
+ | |||
+ | // create an observer instance | ||
+ | var observer = new MutationObserver(function(mutations) { | ||
+ | | ||
+ | if (mutation.removedNodes && mutation.removedNodes.length > 0) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | // configuration of the observer: | ||
+ | var config = { childList: true, characterData: | ||
+ | |||
+ | // pass in the target node, as well as the observer options | ||
+ | while (target) { | ||
+ | if (target.className==" | ||
+ | observer.observe(target, | ||
+ | break; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | var obj0 = new THREE.Object3D(); | ||
+ | obj0.name = " | ||
+ | obj0.userData.explodable = 1; | ||
+ | obj0.userData.points = []; | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 1)); | ||
+ | |||
+ | obj0.userData.pointradii = 0.02; | ||
+ | < | ||
+ | obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0x0064C8, side: THREE.DoubleSide, | ||
+ | obj0.userData.pointlabels = [" | ||
+ | obj0.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[2, 3, 1], [0, 3, 2], [1, 3, 0], [2, 1, 0]]; | ||
+ | < | ||
+ | obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj0); | ||
+ | scene.add(obj0); | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | function textSpriteMaterial(message, | ||
+ | if ( parameters === undefined ) parameters = {}; | ||
+ | var fontface = " | ||
+ | var fontsize = parameters.hasOwnProperty(" | ||
+ | fontsize = fontsize*10; | ||
+ | var lines = message.split(' | ||
+ | var size = 512; | ||
+ | for(var i = 0; i< | ||
+ | var tmp = lines[i].length; | ||
+ | while(tmp*fontsize > size){ | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | var canvas = document.createElement(' | ||
+ | canvas.width = size; | ||
+ | canvas.height = size; | ||
+ | var context = canvas.getContext(' | ||
+ | context.fillStyle = " | ||
+ | context.fill(); | ||
+ | context.font = fontsize + "px " + fontface; | ||
+ | | ||
+ | // text color | ||
+ | context.fillStyle = " | ||
+ | | ||
+ | context.fillText(lines[i], | ||
+ | } | ||
+ | | ||
+ | // canvas contents will be used for a texture | ||
+ | var texture = new THREE.Texture(canvas); | ||
+ | texture.needsUpdate = true; | ||
+ | | ||
+ | var spriteMaterial = new THREE.SpriteMaterial({map: | ||
+ | return spriteMaterial; | ||
+ | } | ||
+ | |||
+ | |||
+ | // ---------------------- INITIALIZING OBJECTS-------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function init_object(obj) { | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_points(obj); | ||
+ | modelContains.points = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_pointlabels(obj); | ||
+ | modelContains.pointlabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_lines(obj); | ||
+ | modelContains.lines = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_edgelabels(obj); | ||
+ | modelContains.edgelabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_arrowheads(obj); | ||
+ | modelContains.arrowheads = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_faces(obj); | ||
+ | modelContains.faces = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function init_points(obj) { | ||
+ | var pointgroup = new THREE.Group(); | ||
+ | pointgroup.name = " | ||
+ | var points = obj.userData.points; | ||
+ | var radii = obj.userData.pointradii; | ||
+ | var materials = obj.userData.pointmaterial; | ||
+ | var geometry, | ||
+ | if (!Array.isArray(radii)) { | ||
+ | geometry = new THREE.SphereBufferGeometry(radii); | ||
+ | } | ||
+ | if (!Array.isArray(materials)) { | ||
+ | material = materials; | ||
+ | } | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | if (Array.isArray(radii)) { | ||
+ | if (radii[i] == 0) { | ||
+ | continue; | ||
+ | } | ||
+ | geometry = new THREE.SphereBufferGeometry(radii[i]); | ||
+ | } | ||
+ | if (Array.isArray(materials)) { | ||
+ | material = materials[i]; | ||
+ | } | ||
+ | var sphere = new THREE.Mesh(geometry, | ||
+ | point.addSphere(sphere); | ||
+ | pointgroup.add(sphere); | ||
+ | } | ||
+ | obj.add(pointgroup); | ||
+ | } | ||
+ | |||
+ | function init_pointlabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var labels = obj.userData.pointlabels; | ||
+ | var pointlabels = new THREE.Group(); | ||
+ | pointlabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(pointlabels); | ||
+ | } | ||
+ | |||
+ | function init_lines(obj) { | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var points = obj.userData.points; | ||
+ | var materials = obj.userData.edgematerial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 ); | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | for (var i=0; i< | ||
+ | geometry.addGroup(2*i, | ||
+ | } | ||
+ | } | ||
+ | var lines = new THREE.LineSegments(geometry, | ||
+ | lines.name = " | ||
+ | obj.add(lines); | ||
+ | updateEdgesPosition(obj); | ||
+ | } | ||
+ | |||
+ | function init_edgelabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var labels = obj.userData.edgelabels; | ||
+ | var edgelabels = new THREE.Group(); | ||
+ | edgelabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(edgelabels); | ||
+ | } | ||
+ | |||
+ | function init_arrowheads(obj) { | ||
+ | var arrowheads = new THREE.Group(); | ||
+ | arrowheads.name = " | ||
+ | var arrowstyle = obj.userData.arrowstyle; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var edgematerials = obj.userData.edgematerial; | ||
+ | var points = obj.userData.points; | ||
+ | var material; | ||
+ | if (!Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials.color} ); | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var start = points[edgeindices[i]]; | ||
+ | var end = points[edgeindices[i+1]]; | ||
+ | var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius(); | ||
+ | if (dist <= 0) { | ||
+ | continue; | ||
+ | } | ||
+ | var dir = new THREE.Vector3().subVectors(end.vector, | ||
+ | dir.normalize(); | ||
+ | var axis = new THREE.Vector3().set(dir.z, | ||
+ | axis.normalize(); | ||
+ | var radians = Math.acos( dir.y ); | ||
+ | var radius = dist/25; | ||
+ | var height = dist/5; | ||
+ | var geometry = new THREE.ConeBufferGeometry(radius, | ||
+ | var position = new THREE.Vector3().addVectors(start.vector, | ||
+ | if (Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} ); | ||
+ | } | ||
+ | var cone = new THREE.Mesh( geometry, material ); | ||
+ | cone.quaternion.setFromAxisAngle(axis, | ||
+ | cone.position.copy(position);; | ||
+ | arrowheads.add(cone); | ||
+ | } | ||
+ | obj.add(arrowheads); | ||
+ | } | ||
+ | |||
+ | function init_faces(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var facets = obj.userData.facets; | ||
+ | obj.userData.triangleindices = []; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | for (var t=0; t< | ||
+ | obj.userData.triangleindices.push(facet[0], | ||
+ | } | ||
+ | } | ||
+ | var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute(bufarr, | ||
+ | | ||
+ | var materials = obj.userData.facetmaterial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var frontmaterials = []; | ||
+ | var backmaterials = []; | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | var tricount = 0; | ||
+ | var facet; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | geometry.addGroup(tricount, | ||
+ | tricount += (facet.length-2)*3; | ||
+ | } | ||
+ | for (var j=0; j< | ||
+ | var fmat = materials[j].clone() | ||
+ | fmat.side = THREE.FrontSide; | ||
+ | frontmaterials.push(fmat); | ||
+ | var bmat = materials[j].clone() | ||
+ | bmat.side = THREE.BackSide; | ||
+ | backmaterials.push(bmat); | ||
+ | obj.userData.facetmaterial = frontmaterials.concat(backmaterials); | ||
+ | } | ||
+ | } else if (materials instanceof THREE.Material) { | ||
+ | frontmaterials = materials.clone() | ||
+ | frontmaterials.side = THREE.FrontSide; | ||
+ | backmaterials = materials.clone() | ||
+ | backmaterials.side = THREE.BackSide; | ||
+ | obj.userData.facetmaterial = [frontmaterials, | ||
+ | } | ||
+ | // duplicating the object with front and back should avoid transparency issues | ||
+ | var backmesh = new THREE.Mesh(geometry, | ||
+ | // meshname is used to show/hide objects | ||
+ | backmesh.name = " | ||
+ | obj.add(backmesh); | ||
+ | var frontmesh = new THREE.Mesh(geometry, | ||
+ | frontmesh.name = " | ||
+ | obj.add(frontmesh); | ||
+ | updateFacesPosition(obj); | ||
+ | } | ||
+ | // // | ||
+ | |||
+ | |||
+ | function updateFacesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.triangleindices; | ||
+ | var faces = obj.getObjectByName(" | ||
+ | var ba = faces.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | faces.geometry.attributes.position.needsUpdate = true; | ||
+ | | ||
+ | } | ||
+ | |||
+ | function updateEdgesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.edgeindices; | ||
+ | var lines = obj.getObjectByName(" | ||
+ | var ba = lines.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | lines.geometry.attributes.position.needsUpdate = true; | ||
+ | } | ||
+ | |||
+ | function onWindowResize() { | ||
+ | renderer.setSize( three.clientWidth, | ||
+ | svgRenderer.setSize( three.clientWidth, | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | function updateCamera() { | ||
+ | var width = three.clientWidth; | ||
+ | var height = three.clientHeight; | ||
+ | var aspect = width / height; | ||
+ | if (camera.type == " | ||
+ | camera.left = frustumSize * aspect / - 2; | ||
+ | camera.right = frustumSize * aspect / 2; | ||
+ | camera.top = frustumSize / 2; | ||
+ | camera.bottom = - frustumSize / 2; | ||
+ | } else if (camera.type == " | ||
+ | camera.aspect = aspect; | ||
+ | } | ||
+ | camera.updateProjectionMatrix(); | ||
+ | } | ||
+ | |||
+ | function changeCamera(event) { | ||
+ | var selindex = event.currentTarget.selectedIndex; | ||
+ | camera = cameras[selindex]; | ||
+ | control = controls[selindex]; | ||
+ | control.enabled = true; | ||
+ | for (var i=0; i< | ||
+ | if (i!=selindex) { | ||
+ | controls[i].enabled = false; | ||
+ | } | ||
+ | } | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | var camtypenode = document.getElementById(' | ||
+ | camtypenode.onchange = changeCamera; | ||
+ | camtypenode.dispatchEvent(new Event(' | ||
+ | |||
+ | onWindowResize(); | ||
+ | window.addEventListener(' | ||
+ | |||
+ | |||
+ | var xRotationEnabled = false; | ||
+ | var yRotationEnabled = false; | ||
+ | var zRotationEnabled = false; | ||
+ | var rotationSpeedFactor = 1; | ||
+ | var settingsShown = false; | ||
+ | var labelsShown = true; | ||
+ | var intervals = []; | ||
+ | var timeouts = []; | ||
+ | var explodingSpeed = 0.05; | ||
+ | var explodeScale = 0.000001; | ||
+ | var XMLS = new XMLSerializer(); | ||
+ | var svgElement; | ||
+ | var renderId; | ||
+ | |||
+ | var render = function () { | ||
+ | |||
+ | renderId = requestAnimationFrame(render); | ||
+ | |||
+ | // comment in for automatic explosion | ||
+ | // | ||
+ | |||
+ | var phi = 0.02 * rotationSpeedFactor; | ||
+ | |||
+ | if (xRotationEnabled) { | ||
+ | scene.rotation.x += phi; | ||
+ | } | ||
+ | if (yRotationEnabled) { | ||
+ | scene.rotation.y += phi; | ||
+ | } | ||
+ | if (zRotationEnabled) { | ||
+ | scene.rotation.z += phi; | ||
+ | } | ||
+ | |||
+ | control.update(); | ||
+ | renderer.render(scene, | ||
+ | }; | ||
+ | |||
+ | if ( THREE.WEBGL.isWebGLAvailable() ) { | ||
+ | render(); | ||
+ | } else { | ||
+ | var warning = WEBGL.getWebGLErrorMessage(); | ||
+ | three.appendChild( warning ); | ||
+ | } | ||
+ | | ||
+ | function changeTransparency() { | ||
+ | var opacity = 1-Number(event.currentTarget.value); | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].opacity = opacity; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.opacity = opacity; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleDepthWrite(event) { | ||
+ | depthwrite = event.currentTarget.checked; | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].depthWrite = depthwrite; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.depthWrite = depthWrite; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function changeRotationX(event){ | ||
+ | xRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationY(event){ | ||
+ | yRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationZ(event){ | ||
+ | zRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | |||
+ | function changeRotationSpeedFactor(event){ | ||
+ | rotationSpeedFactor = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function resetScene(){ | ||
+ | scene.rotation.set(0, | ||
+ | camera.position.set(0, | ||
+ | camera.up.set(0, | ||
+ | } | ||
+ | |||
+ | function showSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = true; | ||
+ | } | ||
+ | |||
+ | function hideSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = false; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | var pos = 150* Math.PI; | ||
+ | |||
+ | function updateFactor() { | ||
+ | pos++; | ||
+ | return Math.sin(.01*pos)+1; | ||
+ | } | ||
+ | |||
+ | // ------------------------ FOLDING ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | // rotate point p around axis defined by points p1 and p2 by given angle | ||
+ | function rotate(p, p1, p2, angle ){ | ||
+ | angle = -angle; | ||
+ | var x = p.x, y = p.y, z = p.z, | ||
+ | a = p1.x, b = p1.y, c = p1.z, | ||
+ | u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z; | ||
+ | var result = []; | ||
+ | var L = u*u + v*v + w*w; | ||
+ | var sqrt = Math.sqrt; | ||
+ | var cos = Math.cos; | ||
+ | var sin = Math.sin; | ||
+ | |||
+ | result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/ | ||
+ | result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/ | ||
+ | result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/ | ||
+ | |||
+ | return result; | ||
+ | } | ||
+ | |||
+ | var fold = function(event){ | ||
+ | var obj = foldables[Number(event.currentTarget.name)]; | ||
+ | var foldvalue = Number(event.currentTarget.value); | ||
+ | var scale = foldvalue - obj.userData.oldscale; | ||
+ | |||
+ | for (var j=0; j< | ||
+ | rotateVertices(obj, | ||
+ | } | ||
+ | update(obj); | ||
+ | obj.userData.oldscale += scale; | ||
+ | lookAtBarycenter(obj); | ||
+ | } | ||
+ | |||
+ | function lookAtBarycenter(obj){ | ||
+ | control.target = barycenter(obj); | ||
+ | } | ||
+ | |||
+ | function barycenter(obj) { | ||
+ | var center = new THREE.Vector3(0, | ||
+ | var points = obj.userData.points; | ||
+ | for (var i=0; i< | ||
+ | center.add(points[i].vector); | ||
+ | } | ||
+ | center.divideScalar(points.length); | ||
+ | return center; | ||
+ | } | ||
+ | |||
+ | function rotateVertices(obj, | ||
+ | var axes = obj.userData.axes; | ||
+ | var subtrees = obj.userData.subtrees; | ||
+ | var points = obj.userData.points; | ||
+ | var angles = obj.userData.angles; | ||
+ | if (edge < axes.length){ | ||
+ | for (var j=0; j< | ||
+ | var rotP = rotate(points[subtrees[edge][j]].vector, | ||
+ | points[subtrees[edge][j]].set(rotP[0], | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function update(obj) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | if (foldables.length) { | ||
+ | var settings = document.getElementById(' | ||
+ | var foldDiv = document.createElement(' | ||
+ | foldDiv.id = ' | ||
+ | var title = document.createElement(' | ||
+ | title.innerHTML = ' | ||
+ | foldDiv.appendChild(title); | ||
+ | foldDiv.className = ' | ||
+ | for (var i=0; i< | ||
+ | var range = document.createElement(' | ||
+ | range.type = ' | ||
+ | range.min = 0; | ||
+ | range.max = 1; | ||
+ | range.value = 0; | ||
+ | range.step = 0.001; | ||
+ | range.name = String(i); | ||
+ | range.oninput = fold; | ||
+ | foldDiv.appendChild(range); | ||
+ | } | ||
+ | lookAtBarycenter(foldables[0]); | ||
+ | settings.insertBefore(foldDiv, | ||
+ | } | ||
+ | |||
+ | | ||
+ | // ---------------------- EXPLOSION ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | if (explodableModel) { | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | if ( obj.userData.explodable ) { | ||
+ | computeCentroid(obj); | ||
+ | } | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | explode(0.000001); | ||
+ | } | ||
+ | |||
+ | function computeCentroid(obj) { | ||
+ | centroid = new THREE.Vector3(); | ||
+ | obj.userData.points.forEach(function(pmpoint) { | ||
+ | centroid.add(pmpoint.vector); | ||
+ | }); | ||
+ | centroid.divideScalar(obj.userData.points.length); | ||
+ | obj.userData.centroid = centroid; | ||
+ | } | ||
+ | |||
+ | function explode(factor) { | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i]; | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | var c = obj.userData.centroid; | ||
+ | obj.position.set(c.x*factor, | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function triggerExplode(event){ | ||
+ | explodeScale = Number(event.currentTarget.value); | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | |||
+ | function setExplodingSpeed(event){ | ||
+ | explodingSpeed = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function triggerAutomaticExplode(event){ | ||
+ | if (event.currentTarget.checked){ | ||
+ | startExploding(); | ||
+ | } else { | ||
+ | clearIntervals(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function startExploding(){ | ||
+ | intervals.push(setInterval(explodingInterval, | ||
+ | } | ||
+ | |||
+ | |||
+ | function explodingInterval(){ | ||
+ | explodeScale += explodingSpeed; | ||
+ | if (explodeScale <= 6){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else{ | ||
+ | explode(6); | ||
+ | explodeScale = 6; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startUnexploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | |||
+ | function startUnexploding(){ | ||
+ | intervals.push(setInterval(unexplodingInterval, | ||
+ | } | ||
+ | |||
+ | function unexplodingInterval(){ | ||
+ | explodeScale -= explodingSpeed; | ||
+ | if (explodeScale >= 0){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else { | ||
+ | explode(0); | ||
+ | explodeScale = 0; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startExploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | function clearIntervals(){ | ||
+ | intervals.forEach(function(interval){ | ||
+ | clearInterval(interval); | ||
+ | }); | ||
+ | intervals = []; | ||
+ | timeouts.forEach(function(timeout){ | ||
+ | clearTimeout(timeout); | ||
+ | }); | ||
+ | timeouts = []; | ||
+ | } | ||
+ | |||
+ | // ---------------------- DISPLAY -------------------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | const objectTypeInnerHTMLs = { points: " | ||
+ | const objectTypeVisible = {}; | ||
+ | Object.assign(objectTypeVisible, | ||
+ | const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort(); | ||
+ | const shownObjectTypesList = document.getElementById(' | ||
+ | |||
+ | function setVisibility(bool, | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i].getObjectByName(objname); | ||
+ | if (obj) { | ||
+ | obj.visible = bool; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleObjectTypeVisibility(event){ | ||
+ | var name = event.currentTarget.name; | ||
+ | var checked = event.currentTarget.checked; | ||
+ | objectTypeVisible[name] = checked; | ||
+ | if (name == " | ||
+ | setVisibility(checked," | ||
+ | setVisibility(checked," | ||
+ | } else { | ||
+ | setVisibility(checked, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var key = sortedObjectTypeKeys[i]; | ||
+ | if (modelContains[key]) { | ||
+ | var objTypeNode = document.createElement(' | ||
+ | objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = key; | ||
+ | checkbox.onchange = toggleObjectTypeVisibility; | ||
+ | shownObjectTypesList.appendChild(checkbox); | ||
+ | shownObjectTypesList.appendChild(objTypeNode); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // ------------------------------------------------------ | ||
+ | |||
+ | function toggleObjectVisibility(event){ | ||
+ | var nr = Number(event.currentTarget.name); | ||
+ | scene.children[nr].visible = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | // append checkboxes for displaying or hiding objects | ||
+ | var shownObjectsList = document.getElementById(' | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | var objNode = document.createElement(' | ||
+ | objNode.innerHTML = obj.name + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = String(i); | ||
+ | checkbox.onchange = toggleObjectVisibility; | ||
+ | shownObjectsList.appendChild(checkbox); | ||
+ | shownObjectsList.appendChild(objNode); | ||
+ | } | ||
+ | |||
+ | // ---------------------- SVG ------------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function takeSvgScreenshot() { | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | svgRenderer.render(scene, | ||
+ | svgElement = XMLS.serializeToString(svgRenderer.domElement); | ||
+ | | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | |||
+ | if (document.getElementById(' | ||
+ | //show in new tab | ||
+ | var myWindow = window.open("","" | ||
+ | myWindow.document.body.innerHTML = svgElement; | ||
+ | } else{ | ||
+ | // download svg file | ||
+ | download(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function download(filename, | ||
+ | var element = document.createElement(' | ||
+ | element.setAttribute(' | ||
+ | element.setAttribute(' | ||
+ | |||
+ | element.style.display = ' | ||
+ | document.body.appendChild(element); | ||
+ | |||
+ | element.click(); | ||
+ | |||
+ | document.body.removeChild(element); | ||
+ | } | ||
+ | |||
+ | |||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | |||
+ | |||
+ | // ------------------ SHORTCUTS -------------------------------------------- | ||
+ | // ------------------------------------------------------------------------- | ||
+ | |||
+ | /** | ||
+ | * http:// | ||
+ | * Version : 2.01.B | ||
+ | * By Binny V A | ||
+ | * License : BSD | ||
+ | */ | ||
+ | shortcut = { | ||
+ | ' | ||
+ | ' | ||
+ | //Provide a set of default options | ||
+ | var default_options = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | if(!opt) opt = default_options; | ||
+ | else { | ||
+ | for(var dfo in default_options) { | ||
+ | if(typeof opt[dfo] == ' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var ele = opt.target; | ||
+ | if(typeof opt.target == ' | ||
+ | var ths = this; | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | |||
+ | //The function to be called at keypress | ||
+ | var func = function(e) { | ||
+ | e = e || window.event; | ||
+ | |||
+ | if(opt[' | ||
+ | var element; | ||
+ | if(e.target) element=e.target; | ||
+ | else if(e.srcElement) element=e.srcElement; | ||
+ | if(element.nodeType==3) element=element.parentNode; | ||
+ | |||
+ | if(element.tagName == ' | ||
+ | } | ||
+ | |||
+ | //Find Which key is pressed | ||
+ | if (e.keyCode) code = e.keyCode; | ||
+ | else if (e.which) code = e.which; | ||
+ | var character = String.fromCharCode(code).toLowerCase(); | ||
+ | |||
+ | if(code == 188) character=","; | ||
+ | if(code == 190) character=" | ||
+ | |||
+ | var keys = shortcut_combination.split(" | ||
+ | //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked | ||
+ | var kp = 0; | ||
+ | |||
+ | //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken | ||
+ | var shift_nums = { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | ";":":", | ||
+ | "'":" | ||
+ | ",":"<", | ||
+ | " | ||
+ | "/":"?", | ||
+ | " | ||
+ | } | ||
+ | // | ||
+ | var special_keys = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | |||
+ | var modifiers = { | ||
+ | shift: { wanted: | ||
+ | ctrl : { wanted: | ||
+ | alt | ||
+ | meta : { wanted: | ||
+ | }; | ||
+ | | ||
+ | if(e.ctrlKey) modifiers.ctrl.pressed = true; | ||
+ | if(e.shiftKey) modifiers.shift.pressed = true; | ||
+ | if(e.altKey) modifiers.alt.pressed = true; | ||
+ | if(e.metaKey) | ||
+ | | ||
+ | for(var i=0; k=keys[i], | ||
+ | // | ||
+ | if(k == ' | ||
+ | kp++; | ||
+ | modifiers.ctrl.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.shift.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.alt.wanted = true; | ||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.meta.wanted = true; | ||
+ | } else if(k.length > 1) { //If it is a special key | ||
+ | if(special_keys[k] == code) kp++; | ||
+ | |||
+ | } else if(opt[' | ||
+ | if(opt[' | ||
+ | |||
+ | } else { //The special keys did not match | ||
+ | if(character == k) kp++; | ||
+ | else { | ||
+ | if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase | ||
+ | character = shift_nums[character]; | ||
+ | if(character == k) kp++; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if(kp == keys.length && | ||
+ | modifiers.ctrl.pressed == modifiers.ctrl.wanted && | ||
+ | modifiers.shift.pressed == modifiers.shift.wanted && | ||
+ | modifiers.alt.pressed == modifiers.alt.wanted && | ||
+ | modifiers.meta.pressed == modifiers.meta.wanted) { | ||
+ | callback(e); | ||
+ | |||
+ | if(!opt[' | ||
+ | // | ||
+ | e.cancelBubble = true; | ||
+ | e.returnValue = false; | ||
+ | |||
+ | // | ||
+ | if (e.stopPropagation) { | ||
+ | e.stopPropagation(); | ||
+ | e.preventDefault(); | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | this.all_shortcuts[shortcut_combination] = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }; | ||
+ | //Attach the function with the event | ||
+ | if(ele.addEventListener) ele.addEventListener(opt[' | ||
+ | else if(ele.attachEvent) ele.attachEvent(' | ||
+ | else ele[' | ||
+ | }, | ||
+ | |||
+ | //Remove the shortcut - just specify the shortcut and I will remove the binding | ||
+ | ' | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | var binding = this.all_shortcuts[shortcut_combination]; | ||
+ | delete(this.all_shortcuts[shortcut_combination]) | ||
+ | if(!binding) return; | ||
+ | var type = binding[' | ||
+ | var ele = binding[' | ||
+ | var callback = binding[' | ||
+ | |||
+ | if(ele.detachEvent) ele.detachEvent(' | ||
+ | else if(ele.removeEventListener) ele.removeEventListener(type, | ||
+ | else ele[' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | shortcut.add(" | ||
+ | var event = new Event(' | ||
+ | if (settingsShown){ | ||
+ | document.getElementById(' | ||
+ | } else { | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | You can also change the colors in the visualization backends (e.g. jReality). How to do this is explained below. | ||
+ | |||
+ | To set the colors of the vertices individually, | ||
+ | |||
+ | **Array of colors**: Instead of passing one color to the // | ||
+ | |||
+ | <code perl> | ||
+ | > simplex(3)-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Tue Mar 29 16:03:37 2022 | ||
+ | unnamed | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <meta charset=utf-8> | ||
+ | < | ||
+ | < | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | */ | ||
+ | html {overflow: scroll;} | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | # | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_END | ||
+ | */ | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | <div id=' | ||
+ | <div class=group id=' | ||
+ | < | ||
+ | < | ||
+ | <div class=indented>< | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | <div class=suboption> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | <div class=suboption> | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | <select id=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <img id=' | ||
+ | <img id=' | ||
+ | <div id=" | ||
+ | </ | ||
+ | < | ||
+ | requirejs.config({ | ||
+ | paths: { | ||
+ | three: '/ | ||
+ | TrackballControls: | ||
+ | OrbitControls: | ||
+ | Projector: '/ | ||
+ | SVGRenderer: | ||
+ | WEBGL: '/ | ||
+ | }, | ||
+ | shim: { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | }); | ||
+ | | ||
+ | require([' | ||
+ | window.THREE = THREE; | ||
+ | require([' | ||
+ | | ||
+ | THREE.TrackballControls = TrackballControls; | ||
+ | THREE.OrbitControls = OrbitControls; | ||
+ | THREE.Projector = Projector; | ||
+ | THREE.SVGRenderer = SVGRenderer; | ||
+ | THREE.WEBGL = WEBGL; | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | |||
+ | const intervalLength = 25; // for automatic animations | ||
+ | const explodableModel = false; | ||
+ | const modelContains = { points: false, pointlabels: | ||
+ | const foldables = []; | ||
+ | |||
+ | var three = document.getElementById(" | ||
+ | var scene = new THREE.Scene(); | ||
+ | var renderer = new THREE.WebGLRenderer( { antialias: true } ); | ||
+ | var svgRenderer = new THREE.SVGRenderer( { antialias: true } ); | ||
+ | renderer.setPixelRatio( window.devicePixelRatio ); | ||
+ | renderer.setClearColor(0xFFFFFF, | ||
+ | svgRenderer.setClearColor(0xFFFFFF, | ||
+ | three.appendChild(renderer.domElement); | ||
+ | |||
+ | var frustumSize = 4; | ||
+ | var cameras = [new THREE.PerspectiveCamera(75, | ||
+ | cameras.forEach(function(cam) { | ||
+ | cam.position.set(0, | ||
+ | cam.lookAt(0, | ||
+ | cam.up.set(0, | ||
+ | }); | ||
+ | var controls = [new THREE.TrackballControls(cameras[0], | ||
+ | var camera, control; | ||
+ | |||
+ | controls[0].zoomSpeed = 0.2; | ||
+ | controls[0].rotateSpeed = 4; | ||
+ | |||
+ | |||
+ | // class to allow move points together with labels and spheres | ||
+ | var PMPoint = function (x,y,z) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addLabel = function(labelsprite) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addSphere = function(spheremesh) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.set = function(x, | ||
+ | | ||
+ | if (this.sprite) { | ||
+ | this.sprite.position.copy(this.vector); | ||
+ | } | ||
+ | if (this.sphere) { | ||
+ | this.sphere.position.copy(this.vector); | ||
+ | } | ||
+ | } | ||
+ | PMPoint.prototype.radius = function() { | ||
+ | if (this.sphere) { | ||
+ | return this.sphere.geometry.parameters.radius; | ||
+ | } else { | ||
+ | return 0; | ||
+ | } | ||
+ | }; | ||
+ | // select the target node | ||
+ | var target = document.querySelector('# | ||
+ | |||
+ | // create an observer instance | ||
+ | var observer = new MutationObserver(function(mutations) { | ||
+ | | ||
+ | if (mutation.removedNodes && mutation.removedNodes.length > 0) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | // configuration of the observer: | ||
+ | var config = { childList: true, characterData: | ||
+ | |||
+ | // pass in the target node, as well as the observer options | ||
+ | while (target) { | ||
+ | if (target.className==" | ||
+ | observer.observe(target, | ||
+ | break; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | var obj0 = new THREE.Object3D(); | ||
+ | obj0.name = " | ||
+ | obj0.userData.explodable = 1; | ||
+ | obj0.userData.points = []; | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 1)); | ||
+ | |||
+ | obj0.userData.pointradii = 0.02; | ||
+ | < | ||
+ | obj0.userData.pointmaterial = [new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x00FF00, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x0000FF, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFFFF00, side: THREE.DoubleSide, | ||
+ | obj0.userData.pointlabels = [" | ||
+ | obj0.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[2, 3, 1], [0, 3, 2], [1, 3, 0], [2, 1, 0]]; | ||
+ | < | ||
+ | obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj0); | ||
+ | scene.add(obj0); | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | function textSpriteMaterial(message, | ||
+ | if ( parameters === undefined ) parameters = {}; | ||
+ | var fontface = " | ||
+ | var fontsize = parameters.hasOwnProperty(" | ||
+ | fontsize = fontsize*10; | ||
+ | var lines = message.split(' | ||
+ | var size = 512; | ||
+ | for(var i = 0; i< | ||
+ | var tmp = lines[i].length; | ||
+ | while(tmp*fontsize > size){ | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | var canvas = document.createElement(' | ||
+ | canvas.width = size; | ||
+ | canvas.height = size; | ||
+ | var context = canvas.getContext(' | ||
+ | context.fillStyle = " | ||
+ | context.fill(); | ||
+ | context.font = fontsize + "px " + fontface; | ||
+ | | ||
+ | // text color | ||
+ | context.fillStyle = " | ||
+ | | ||
+ | context.fillText(lines[i], | ||
+ | } | ||
+ | | ||
+ | // canvas contents will be used for a texture | ||
+ | var texture = new THREE.Texture(canvas); | ||
+ | texture.needsUpdate = true; | ||
+ | | ||
+ | var spriteMaterial = new THREE.SpriteMaterial({map: | ||
+ | return spriteMaterial; | ||
+ | } | ||
+ | |||
+ | |||
+ | // ---------------------- INITIALIZING OBJECTS-------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function init_object(obj) { | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_points(obj); | ||
+ | modelContains.points = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_pointlabels(obj); | ||
+ | modelContains.pointlabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_lines(obj); | ||
+ | modelContains.lines = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_edgelabels(obj); | ||
+ | modelContains.edgelabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_arrowheads(obj); | ||
+ | modelContains.arrowheads = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_faces(obj); | ||
+ | modelContains.faces = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function init_points(obj) { | ||
+ | var pointgroup = new THREE.Group(); | ||
+ | pointgroup.name = " | ||
+ | var points = obj.userData.points; | ||
+ | var radii = obj.userData.pointradii; | ||
+ | var materials = obj.userData.pointmaterial; | ||
+ | var geometry, | ||
+ | if (!Array.isArray(radii)) { | ||
+ | geometry = new THREE.SphereBufferGeometry(radii); | ||
+ | } | ||
+ | if (!Array.isArray(materials)) { | ||
+ | material = materials; | ||
+ | } | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | if (Array.isArray(radii)) { | ||
+ | if (radii[i] == 0) { | ||
+ | continue; | ||
+ | } | ||
+ | geometry = new THREE.SphereBufferGeometry(radii[i]); | ||
+ | } | ||
+ | if (Array.isArray(materials)) { | ||
+ | material = materials[i]; | ||
+ | } | ||
+ | var sphere = new THREE.Mesh(geometry, | ||
+ | point.addSphere(sphere); | ||
+ | pointgroup.add(sphere); | ||
+ | } | ||
+ | obj.add(pointgroup); | ||
+ | } | ||
+ | |||
+ | function init_pointlabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var labels = obj.userData.pointlabels; | ||
+ | var pointlabels = new THREE.Group(); | ||
+ | pointlabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(pointlabels); | ||
+ | } | ||
+ | |||
+ | function init_lines(obj) { | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var points = obj.userData.points; | ||
+ | var materials = obj.userData.edgematerial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 ); | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | for (var i=0; i< | ||
+ | geometry.addGroup(2*i, | ||
+ | } | ||
+ | } | ||
+ | var lines = new THREE.LineSegments(geometry, | ||
+ | lines.name = " | ||
+ | obj.add(lines); | ||
+ | updateEdgesPosition(obj); | ||
+ | } | ||
+ | |||
+ | function init_edgelabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var labels = obj.userData.edgelabels; | ||
+ | var edgelabels = new THREE.Group(); | ||
+ | edgelabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(edgelabels); | ||
+ | } | ||
+ | |||
+ | function init_arrowheads(obj) { | ||
+ | var arrowheads = new THREE.Group(); | ||
+ | arrowheads.name = " | ||
+ | var arrowstyle = obj.userData.arrowstyle; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var edgematerials = obj.userData.edgematerial; | ||
+ | var points = obj.userData.points; | ||
+ | var material; | ||
+ | if (!Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials.color} ); | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var start = points[edgeindices[i]]; | ||
+ | var end = points[edgeindices[i+1]]; | ||
+ | var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius(); | ||
+ | if (dist <= 0) { | ||
+ | continue; | ||
+ | } | ||
+ | var dir = new THREE.Vector3().subVectors(end.vector, | ||
+ | dir.normalize(); | ||
+ | var axis = new THREE.Vector3().set(dir.z, | ||
+ | axis.normalize(); | ||
+ | var radians = Math.acos( dir.y ); | ||
+ | var radius = dist/25; | ||
+ | var height = dist/5; | ||
+ | var geometry = new THREE.ConeBufferGeometry(radius, | ||
+ | var position = new THREE.Vector3().addVectors(start.vector, | ||
+ | if (Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} ); | ||
+ | } | ||
+ | var cone = new THREE.Mesh( geometry, material ); | ||
+ | cone.quaternion.setFromAxisAngle(axis, | ||
+ | cone.position.copy(position);; | ||
+ | arrowheads.add(cone); | ||
+ | } | ||
+ | obj.add(arrowheads); | ||
+ | } | ||
+ | |||
+ | function init_faces(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var facets = obj.userData.facets; | ||
+ | obj.userData.triangleindices = []; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | for (var t=0; t< | ||
+ | obj.userData.triangleindices.push(facet[0], | ||
+ | } | ||
+ | } | ||
+ | var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute(bufarr, | ||
+ | | ||
+ | var materials = obj.userData.facetmaterial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var frontmaterials = []; | ||
+ | var backmaterials = []; | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | var tricount = 0; | ||
+ | var facet; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | geometry.addGroup(tricount, | ||
+ | tricount += (facet.length-2)*3; | ||
+ | } | ||
+ | for (var j=0; j< | ||
+ | var fmat = materials[j].clone() | ||
+ | fmat.side = THREE.FrontSide; | ||
+ | frontmaterials.push(fmat); | ||
+ | var bmat = materials[j].clone() | ||
+ | bmat.side = THREE.BackSide; | ||
+ | backmaterials.push(bmat); | ||
+ | obj.userData.facetmaterial = frontmaterials.concat(backmaterials); | ||
+ | } | ||
+ | } else if (materials instanceof THREE.Material) { | ||
+ | frontmaterials = materials.clone() | ||
+ | frontmaterials.side = THREE.FrontSide; | ||
+ | backmaterials = materials.clone() | ||
+ | backmaterials.side = THREE.BackSide; | ||
+ | obj.userData.facetmaterial = [frontmaterials, | ||
+ | } | ||
+ | // duplicating the object with front and back should avoid transparency issues | ||
+ | var backmesh = new THREE.Mesh(geometry, | ||
+ | // meshname is used to show/hide objects | ||
+ | backmesh.name = " | ||
+ | obj.add(backmesh); | ||
+ | var frontmesh = new THREE.Mesh(geometry, | ||
+ | frontmesh.name = " | ||
+ | obj.add(frontmesh); | ||
+ | updateFacesPosition(obj); | ||
+ | } | ||
+ | // // | ||
+ | |||
+ | |||
+ | function updateFacesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.triangleindices; | ||
+ | var faces = obj.getObjectByName(" | ||
+ | var ba = faces.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | faces.geometry.attributes.position.needsUpdate = true; | ||
+ | | ||
+ | } | ||
+ | |||
+ | function updateEdgesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.edgeindices; | ||
+ | var lines = obj.getObjectByName(" | ||
+ | var ba = lines.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | lines.geometry.attributes.position.needsUpdate = true; | ||
+ | } | ||
+ | |||
+ | function onWindowResize() { | ||
+ | renderer.setSize( three.clientWidth, | ||
+ | svgRenderer.setSize( three.clientWidth, | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | function updateCamera() { | ||
+ | var width = three.clientWidth; | ||
+ | var height = three.clientHeight; | ||
+ | var aspect = width / height; | ||
+ | if (camera.type == " | ||
+ | camera.left = frustumSize * aspect / - 2; | ||
+ | camera.right = frustumSize * aspect / 2; | ||
+ | camera.top = frustumSize / 2; | ||
+ | camera.bottom = - frustumSize / 2; | ||
+ | } else if (camera.type == " | ||
+ | camera.aspect = aspect; | ||
+ | } | ||
+ | camera.updateProjectionMatrix(); | ||
+ | } | ||
+ | |||
+ | function changeCamera(event) { | ||
+ | var selindex = event.currentTarget.selectedIndex; | ||
+ | camera = cameras[selindex]; | ||
+ | control = controls[selindex]; | ||
+ | control.enabled = true; | ||
+ | for (var i=0; i< | ||
+ | if (i!=selindex) { | ||
+ | controls[i].enabled = false; | ||
+ | } | ||
+ | } | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | var camtypenode = document.getElementById(' | ||
+ | camtypenode.onchange = changeCamera; | ||
+ | camtypenode.dispatchEvent(new Event(' | ||
+ | |||
+ | onWindowResize(); | ||
+ | window.addEventListener(' | ||
+ | |||
+ | |||
+ | var xRotationEnabled = false; | ||
+ | var yRotationEnabled = false; | ||
+ | var zRotationEnabled = false; | ||
+ | var rotationSpeedFactor = 1; | ||
+ | var settingsShown = false; | ||
+ | var labelsShown = true; | ||
+ | var intervals = []; | ||
+ | var timeouts = []; | ||
+ | var explodingSpeed = 0.05; | ||
+ | var explodeScale = 0.000001; | ||
+ | var XMLS = new XMLSerializer(); | ||
+ | var svgElement; | ||
+ | var renderId; | ||
+ | |||
+ | var render = function () { | ||
+ | |||
+ | renderId = requestAnimationFrame(render); | ||
+ | |||
+ | // comment in for automatic explosion | ||
+ | // | ||
+ | |||
+ | var phi = 0.02 * rotationSpeedFactor; | ||
+ | |||
+ | if (xRotationEnabled) { | ||
+ | scene.rotation.x += phi; | ||
+ | } | ||
+ | if (yRotationEnabled) { | ||
+ | scene.rotation.y += phi; | ||
+ | } | ||
+ | if (zRotationEnabled) { | ||
+ | scene.rotation.z += phi; | ||
+ | } | ||
+ | |||
+ | control.update(); | ||
+ | renderer.render(scene, | ||
+ | }; | ||
+ | |||
+ | if ( THREE.WEBGL.isWebGLAvailable() ) { | ||
+ | render(); | ||
+ | } else { | ||
+ | var warning = WEBGL.getWebGLErrorMessage(); | ||
+ | three.appendChild( warning ); | ||
+ | } | ||
+ | | ||
+ | function changeTransparency() { | ||
+ | var opacity = 1-Number(event.currentTarget.value); | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].opacity = opacity; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.opacity = opacity; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleDepthWrite(event) { | ||
+ | depthwrite = event.currentTarget.checked; | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].depthWrite = depthwrite; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.depthWrite = depthWrite; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function changeRotationX(event){ | ||
+ | xRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationY(event){ | ||
+ | yRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationZ(event){ | ||
+ | zRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | |||
+ | function changeRotationSpeedFactor(event){ | ||
+ | rotationSpeedFactor = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function resetScene(){ | ||
+ | scene.rotation.set(0, | ||
+ | camera.position.set(0, | ||
+ | camera.up.set(0, | ||
+ | } | ||
+ | |||
+ | function showSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = true; | ||
+ | } | ||
+ | |||
+ | function hideSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = false; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | var pos = 150* Math.PI; | ||
+ | |||
+ | function updateFactor() { | ||
+ | pos++; | ||
+ | return Math.sin(.01*pos)+1; | ||
+ | } | ||
+ | |||
+ | // ------------------------ FOLDING ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | // rotate point p around axis defined by points p1 and p2 by given angle | ||
+ | function rotate(p, p1, p2, angle ){ | ||
+ | angle = -angle; | ||
+ | var x = p.x, y = p.y, z = p.z, | ||
+ | a = p1.x, b = p1.y, c = p1.z, | ||
+ | u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z; | ||
+ | var result = []; | ||
+ | var L = u*u + v*v + w*w; | ||
+ | var sqrt = Math.sqrt; | ||
+ | var cos = Math.cos; | ||
+ | var sin = Math.sin; | ||
+ | |||
+ | result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/ | ||
+ | result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/ | ||
+ | result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/ | ||
+ | |||
+ | return result; | ||
+ | } | ||
+ | |||
+ | var fold = function(event){ | ||
+ | var obj = foldables[Number(event.currentTarget.name)]; | ||
+ | var foldvalue = Number(event.currentTarget.value); | ||
+ | var scale = foldvalue - obj.userData.oldscale; | ||
+ | |||
+ | for (var j=0; j< | ||
+ | rotateVertices(obj, | ||
+ | } | ||
+ | update(obj); | ||
+ | obj.userData.oldscale += scale; | ||
+ | lookAtBarycenter(obj); | ||
+ | } | ||
+ | |||
+ | function lookAtBarycenter(obj){ | ||
+ | control.target = barycenter(obj); | ||
+ | } | ||
+ | |||
+ | function barycenter(obj) { | ||
+ | var center = new THREE.Vector3(0, | ||
+ | var points = obj.userData.points; | ||
+ | for (var i=0; i< | ||
+ | center.add(points[i].vector); | ||
+ | } | ||
+ | center.divideScalar(points.length); | ||
+ | return center; | ||
+ | } | ||
+ | |||
+ | function rotateVertices(obj, | ||
+ | var axes = obj.userData.axes; | ||
+ | var subtrees = obj.userData.subtrees; | ||
+ | var points = obj.userData.points; | ||
+ | var angles = obj.userData.angles; | ||
+ | if (edge < axes.length){ | ||
+ | for (var j=0; j< | ||
+ | var rotP = rotate(points[subtrees[edge][j]].vector, | ||
+ | points[subtrees[edge][j]].set(rotP[0], | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function update(obj) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | if (foldables.length) { | ||
+ | var settings = document.getElementById(' | ||
+ | var foldDiv = document.createElement(' | ||
+ | foldDiv.id = ' | ||
+ | var title = document.createElement(' | ||
+ | title.innerHTML = ' | ||
+ | foldDiv.appendChild(title); | ||
+ | foldDiv.className = ' | ||
+ | for (var i=0; i< | ||
+ | var range = document.createElement(' | ||
+ | range.type = ' | ||
+ | range.min = 0; | ||
+ | range.max = 1; | ||
+ | range.value = 0; | ||
+ | range.step = 0.001; | ||
+ | range.name = String(i); | ||
+ | range.oninput = fold; | ||
+ | foldDiv.appendChild(range); | ||
+ | } | ||
+ | lookAtBarycenter(foldables[0]); | ||
+ | settings.insertBefore(foldDiv, | ||
+ | } | ||
+ | |||
+ | | ||
+ | // ---------------------- EXPLOSION ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | if (explodableModel) { | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | if ( obj.userData.explodable ) { | ||
+ | computeCentroid(obj); | ||
+ | } | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | explode(0.000001); | ||
+ | } | ||
+ | |||
+ | function computeCentroid(obj) { | ||
+ | centroid = new THREE.Vector3(); | ||
+ | obj.userData.points.forEach(function(pmpoint) { | ||
+ | centroid.add(pmpoint.vector); | ||
+ | }); | ||
+ | centroid.divideScalar(obj.userData.points.length); | ||
+ | obj.userData.centroid = centroid; | ||
+ | } | ||
+ | |||
+ | function explode(factor) { | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i]; | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | var c = obj.userData.centroid; | ||
+ | obj.position.set(c.x*factor, | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function triggerExplode(event){ | ||
+ | explodeScale = Number(event.currentTarget.value); | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | |||
+ | function setExplodingSpeed(event){ | ||
+ | explodingSpeed = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function triggerAutomaticExplode(event){ | ||
+ | if (event.currentTarget.checked){ | ||
+ | startExploding(); | ||
+ | } else { | ||
+ | clearIntervals(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function startExploding(){ | ||
+ | intervals.push(setInterval(explodingInterval, | ||
+ | } | ||
+ | |||
+ | |||
+ | function explodingInterval(){ | ||
+ | explodeScale += explodingSpeed; | ||
+ | if (explodeScale <= 6){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else{ | ||
+ | explode(6); | ||
+ | explodeScale = 6; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startUnexploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | |||
+ | function startUnexploding(){ | ||
+ | intervals.push(setInterval(unexplodingInterval, | ||
+ | } | ||
+ | |||
+ | function unexplodingInterval(){ | ||
+ | explodeScale -= explodingSpeed; | ||
+ | if (explodeScale >= 0){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else { | ||
+ | explode(0); | ||
+ | explodeScale = 0; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startExploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | function clearIntervals(){ | ||
+ | intervals.forEach(function(interval){ | ||
+ | clearInterval(interval); | ||
+ | }); | ||
+ | intervals = []; | ||
+ | timeouts.forEach(function(timeout){ | ||
+ | clearTimeout(timeout); | ||
+ | }); | ||
+ | timeouts = []; | ||
+ | } | ||
+ | |||
+ | // ---------------------- DISPLAY -------------------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | const objectTypeInnerHTMLs = { points: " | ||
+ | const objectTypeVisible = {}; | ||
+ | Object.assign(objectTypeVisible, | ||
+ | const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort(); | ||
+ | const shownObjectTypesList = document.getElementById(' | ||
+ | |||
+ | function setVisibility(bool, | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i].getObjectByName(objname); | ||
+ | if (obj) { | ||
+ | obj.visible = bool; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleObjectTypeVisibility(event){ | ||
+ | var name = event.currentTarget.name; | ||
+ | var checked = event.currentTarget.checked; | ||
+ | objectTypeVisible[name] = checked; | ||
+ | if (name == " | ||
+ | setVisibility(checked," | ||
+ | setVisibility(checked," | ||
+ | } else { | ||
+ | setVisibility(checked, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var key = sortedObjectTypeKeys[i]; | ||
+ | if (modelContains[key]) { | ||
+ | var objTypeNode = document.createElement(' | ||
+ | objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = key; | ||
+ | checkbox.onchange = toggleObjectTypeVisibility; | ||
+ | shownObjectTypesList.appendChild(checkbox); | ||
+ | shownObjectTypesList.appendChild(objTypeNode); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // ------------------------------------------------------ | ||
+ | |||
+ | function toggleObjectVisibility(event){ | ||
+ | var nr = Number(event.currentTarget.name); | ||
+ | scene.children[nr].visible = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | // append checkboxes for displaying or hiding objects | ||
+ | var shownObjectsList = document.getElementById(' | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | var objNode = document.createElement(' | ||
+ | objNode.innerHTML = obj.name + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = String(i); | ||
+ | checkbox.onchange = toggleObjectVisibility; | ||
+ | shownObjectsList.appendChild(checkbox); | ||
+ | shownObjectsList.appendChild(objNode); | ||
+ | } | ||
+ | |||
+ | // ---------------------- SVG ------------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function takeSvgScreenshot() { | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | svgRenderer.render(scene, | ||
+ | svgElement = XMLS.serializeToString(svgRenderer.domElement); | ||
+ | | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | |||
+ | if (document.getElementById(' | ||
+ | //show in new tab | ||
+ | var myWindow = window.open("","" | ||
+ | myWindow.document.body.innerHTML = svgElement; | ||
+ | } else{ | ||
+ | // download svg file | ||
+ | download(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function download(filename, | ||
+ | var element = document.createElement(' | ||
+ | element.setAttribute(' | ||
+ | element.setAttribute(' | ||
+ | |||
+ | element.style.display = ' | ||
+ | document.body.appendChild(element); | ||
+ | |||
+ | element.click(); | ||
+ | |||
+ | document.body.removeChild(element); | ||
+ | } | ||
+ | |||
+ | |||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | |||
+ | |||
+ | // ------------------ SHORTCUTS -------------------------------------------- | ||
+ | // ------------------------------------------------------------------------- | ||
+ | |||
+ | /** | ||
+ | * http:// | ||
+ | * Version : 2.01.B | ||
+ | * By Binny V A | ||
+ | * License : BSD | ||
+ | */ | ||
+ | shortcut = { | ||
+ | ' | ||
+ | ' | ||
+ | //Provide a set of default options | ||
+ | var default_options = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | if(!opt) opt = default_options; | ||
+ | else { | ||
+ | for(var dfo in default_options) { | ||
+ | if(typeof opt[dfo] == ' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var ele = opt.target; | ||
+ | if(typeof opt.target == ' | ||
+ | var ths = this; | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | |||
+ | //The function to be called at keypress | ||
+ | var func = function(e) { | ||
+ | e = e || window.event; | ||
+ | |||
+ | if(opt[' | ||
+ | var element; | ||
+ | if(e.target) element=e.target; | ||
+ | else if(e.srcElement) element=e.srcElement; | ||
+ | if(element.nodeType==3) element=element.parentNode; | ||
+ | |||
+ | if(element.tagName == ' | ||
+ | } | ||
+ | |||
+ | //Find Which key is pressed | ||
+ | if (e.keyCode) code = e.keyCode; | ||
+ | else if (e.which) code = e.which; | ||
+ | var character = String.fromCharCode(code).toLowerCase(); | ||
+ | |||
+ | if(code == 188) character=","; | ||
+ | if(code == 190) character=" | ||
+ | |||
+ | var keys = shortcut_combination.split(" | ||
+ | //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked | ||
+ | var kp = 0; | ||
+ | |||
+ | //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken | ||
+ | var shift_nums = { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | ";":":", | ||
+ | "'":" | ||
+ | ",":"<", | ||
+ | " | ||
+ | "/":"?", | ||
+ | " | ||
+ | } | ||
+ | // | ||
+ | var special_keys = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | |||
+ | var modifiers = { | ||
+ | shift: { wanted: | ||
+ | ctrl : { wanted: | ||
+ | alt | ||
+ | meta : { wanted: | ||
+ | }; | ||
+ | | ||
+ | if(e.ctrlKey) modifiers.ctrl.pressed = true; | ||
+ | if(e.shiftKey) modifiers.shift.pressed = true; | ||
+ | if(e.altKey) modifiers.alt.pressed = true; | ||
+ | if(e.metaKey) | ||
+ | | ||
+ | for(var i=0; k=keys[i], | ||
+ | // | ||
+ | if(k == ' | ||
+ | kp++; | ||
+ | modifiers.ctrl.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.shift.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.alt.wanted = true; | ||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.meta.wanted = true; | ||
+ | } else if(k.length > 1) { //If it is a special key | ||
+ | if(special_keys[k] == code) kp++; | ||
+ | |||
+ | } else if(opt[' | ||
+ | if(opt[' | ||
+ | |||
+ | } else { //The special keys did not match | ||
+ | if(character == k) kp++; | ||
+ | else { | ||
+ | if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase | ||
+ | character = shift_nums[character]; | ||
+ | if(character == k) kp++; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if(kp == keys.length && | ||
+ | modifiers.ctrl.pressed == modifiers.ctrl.wanted && | ||
+ | modifiers.shift.pressed == modifiers.shift.wanted && | ||
+ | modifiers.alt.pressed == modifiers.alt.wanted && | ||
+ | modifiers.meta.pressed == modifiers.meta.wanted) { | ||
+ | callback(e); | ||
+ | |||
+ | if(!opt[' | ||
+ | // | ||
+ | e.cancelBubble = true; | ||
+ | e.returnValue = false; | ||
+ | |||
+ | // | ||
+ | if (e.stopPropagation) { | ||
+ | e.stopPropagation(); | ||
+ | e.preventDefault(); | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | this.all_shortcuts[shortcut_combination] = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }; | ||
+ | //Attach the function with the event | ||
+ | if(ele.addEventListener) ele.addEventListener(opt[' | ||
+ | else if(ele.attachEvent) ele.attachEvent(' | ||
+ | else ele[' | ||
+ | }, | ||
+ | |||
+ | //Remove the shortcut - just specify the shortcut and I will remove the binding | ||
+ | ' | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | var binding = this.all_shortcuts[shortcut_combination]; | ||
+ | delete(this.all_shortcuts[shortcut_combination]) | ||
+ | if(!binding) return; | ||
+ | var type = binding[' | ||
+ | var ele = binding[' | ||
+ | var callback = binding[' | ||
+ | |||
+ | if(ele.detachEvent) ele.detachEvent(' | ||
+ | else if(ele.removeEventListener) ele.removeEventListener(type, | ||
+ | else ele[' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | shortcut.add(" | ||
+ | var event = new Event(' | ||
+ | if (settingsShown){ | ||
+ | document.getElementById(' | ||
+ | } else { | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | The following line produces the same picture but each color is specified using a different color format: | ||
+ | |||
+ | <code perl> | ||
+ | polytope > simplex(3)-> | ||
+ | </ | ||
+ | See [[visual_tutorial# | ||
+ | |||
+ | **Function**: | ||
+ | |||
+ | <code perl> | ||
+ | > simplex(3)-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Tue Mar 29 16:03:37 2022 | ||
+ | unnamed | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <meta charset=utf-8> | ||
+ | < | ||
+ | < | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | */ | ||
+ | html {overflow: scroll;} | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | # | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_END | ||
+ | */ | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | <div id=' | ||
+ | <div class=group id=' | ||
+ | < | ||
+ | < | ||
+ | <div class=indented>< | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | <div class=suboption> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | <div class=suboption> | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | <select id=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <img id=' | ||
+ | <img id=' | ||
+ | <div id=" | ||
+ | </ | ||
+ | < | ||
+ | requirejs.config({ | ||
+ | paths: { | ||
+ | three: '/ | ||
+ | TrackballControls: | ||
+ | OrbitControls: | ||
+ | Projector: '/ | ||
+ | SVGRenderer: | ||
+ | WEBGL: '/ | ||
+ | }, | ||
+ | shim: { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | }); | ||
+ | | ||
+ | require([' | ||
+ | window.THREE = THREE; | ||
+ | require([' | ||
+ | | ||
+ | THREE.TrackballControls = TrackballControls; | ||
+ | THREE.OrbitControls = OrbitControls; | ||
+ | THREE.Projector = Projector; | ||
+ | THREE.SVGRenderer = SVGRenderer; | ||
+ | THREE.WEBGL = WEBGL; | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | |||
+ | const intervalLength = 25; // for automatic animations | ||
+ | const explodableModel = false; | ||
+ | const modelContains = { points: false, pointlabels: | ||
+ | const foldables = []; | ||
+ | |||
+ | var three = document.getElementById(" | ||
+ | var scene = new THREE.Scene(); | ||
+ | var renderer = new THREE.WebGLRenderer( { antialias: true } ); | ||
+ | var svgRenderer = new THREE.SVGRenderer( { antialias: true } ); | ||
+ | renderer.setPixelRatio( window.devicePixelRatio ); | ||
+ | renderer.setClearColor(0xFFFFFF, | ||
+ | svgRenderer.setClearColor(0xFFFFFF, | ||
+ | three.appendChild(renderer.domElement); | ||
+ | |||
+ | var frustumSize = 4; | ||
+ | var cameras = [new THREE.PerspectiveCamera(75, | ||
+ | cameras.forEach(function(cam) { | ||
+ | cam.position.set(0, | ||
+ | cam.lookAt(0, | ||
+ | cam.up.set(0, | ||
+ | }); | ||
+ | var controls = [new THREE.TrackballControls(cameras[0], | ||
+ | var camera, control; | ||
+ | |||
+ | controls[0].zoomSpeed = 0.2; | ||
+ | controls[0].rotateSpeed = 4; | ||
+ | |||
+ | |||
+ | // class to allow move points together with labels and spheres | ||
+ | var PMPoint = function (x,y,z) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addLabel = function(labelsprite) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addSphere = function(spheremesh) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.set = function(x, | ||
+ | | ||
+ | if (this.sprite) { | ||
+ | this.sprite.position.copy(this.vector); | ||
+ | } | ||
+ | if (this.sphere) { | ||
+ | this.sphere.position.copy(this.vector); | ||
+ | } | ||
+ | } | ||
+ | PMPoint.prototype.radius = function() { | ||
+ | if (this.sphere) { | ||
+ | return this.sphere.geometry.parameters.radius; | ||
+ | } else { | ||
+ | return 0; | ||
+ | } | ||
+ | }; | ||
+ | // select the target node | ||
+ | var target = document.querySelector('# | ||
+ | |||
+ | // create an observer instance | ||
+ | var observer = new MutationObserver(function(mutations) { | ||
+ | | ||
+ | if (mutation.removedNodes && mutation.removedNodes.length > 0) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | // configuration of the observer: | ||
+ | var config = { childList: true, characterData: | ||
+ | |||
+ | // pass in the target node, as well as the observer options | ||
+ | while (target) { | ||
+ | if (target.className==" | ||
+ | observer.observe(target, | ||
+ | break; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | var obj0 = new THREE.Object3D(); | ||
+ | obj0.name = " | ||
+ | obj0.userData.explodable = 1; | ||
+ | obj0.userData.points = []; | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 1)); | ||
+ | |||
+ | obj0.userData.pointradii = 0.02; | ||
+ | < | ||
+ | obj0.userData.pointmaterial = [new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x545400, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xA8A800, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFCFC00, side: THREE.DoubleSide, | ||
+ | obj0.userData.pointlabels = [" | ||
+ | obj0.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[2, 3, 1], [0, 3, 2], [1, 3, 0], [2, 1, 0]]; | ||
+ | < | ||
+ | obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj0); | ||
+ | scene.add(obj0); | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | function textSpriteMaterial(message, | ||
+ | if ( parameters === undefined ) parameters = {}; | ||
+ | var fontface = " | ||
+ | var fontsize = parameters.hasOwnProperty(" | ||
+ | fontsize = fontsize*10; | ||
+ | var lines = message.split(' | ||
+ | var size = 512; | ||
+ | for(var i = 0; i< | ||
+ | var tmp = lines[i].length; | ||
+ | while(tmp*fontsize > size){ | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | var canvas = document.createElement(' | ||
+ | canvas.width = size; | ||
+ | canvas.height = size; | ||
+ | var context = canvas.getContext(' | ||
+ | context.fillStyle = " | ||
+ | context.fill(); | ||
+ | context.font = fontsize + "px " + fontface; | ||
+ | | ||
+ | // text color | ||
+ | context.fillStyle = " | ||
+ | | ||
+ | context.fillText(lines[i], | ||
+ | } | ||
+ | | ||
+ | // canvas contents will be used for a texture | ||
+ | var texture = new THREE.Texture(canvas); | ||
+ | texture.needsUpdate = true; | ||
+ | | ||
+ | var spriteMaterial = new THREE.SpriteMaterial({map: | ||
+ | return spriteMaterial; | ||
+ | } | ||
+ | |||
+ | |||
+ | // ---------------------- INITIALIZING OBJECTS-------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function init_object(obj) { | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_points(obj); | ||
+ | modelContains.points = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_pointlabels(obj); | ||
+ | modelContains.pointlabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_lines(obj); | ||
+ | modelContains.lines = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_edgelabels(obj); | ||
+ | modelContains.edgelabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_arrowheads(obj); | ||
+ | modelContains.arrowheads = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_faces(obj); | ||
+ | modelContains.faces = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function init_points(obj) { | ||
+ | var pointgroup = new THREE.Group(); | ||
+ | pointgroup.name = " | ||
+ | var points = obj.userData.points; | ||
+ | var radii = obj.userData.pointradii; | ||
+ | var materials = obj.userData.pointmaterial; | ||
+ | var geometry, | ||
+ | if (!Array.isArray(radii)) { | ||
+ | geometry = new THREE.SphereBufferGeometry(radii); | ||
+ | } | ||
+ | if (!Array.isArray(materials)) { | ||
+ | material = materials; | ||
+ | } | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | if (Array.isArray(radii)) { | ||
+ | if (radii[i] == 0) { | ||
+ | continue; | ||
+ | } | ||
+ | geometry = new THREE.SphereBufferGeometry(radii[i]); | ||
+ | } | ||
+ | if (Array.isArray(materials)) { | ||
+ | material = materials[i]; | ||
+ | } | ||
+ | var sphere = new THREE.Mesh(geometry, | ||
+ | point.addSphere(sphere); | ||
+ | pointgroup.add(sphere); | ||
+ | } | ||
+ | obj.add(pointgroup); | ||
+ | } | ||
+ | |||
+ | function init_pointlabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var labels = obj.userData.pointlabels; | ||
+ | var pointlabels = new THREE.Group(); | ||
+ | pointlabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(pointlabels); | ||
+ | } | ||
+ | |||
+ | function init_lines(obj) { | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var points = obj.userData.points; | ||
+ | var materials = obj.userData.edgematerial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 ); | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | for (var i=0; i< | ||
+ | geometry.addGroup(2*i, | ||
+ | } | ||
+ | } | ||
+ | var lines = new THREE.LineSegments(geometry, | ||
+ | lines.name = " | ||
+ | obj.add(lines); | ||
+ | updateEdgesPosition(obj); | ||
+ | } | ||
+ | |||
+ | function init_edgelabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var labels = obj.userData.edgelabels; | ||
+ | var edgelabels = new THREE.Group(); | ||
+ | edgelabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(edgelabels); | ||
+ | } | ||
+ | |||
+ | function init_arrowheads(obj) { | ||
+ | var arrowheads = new THREE.Group(); | ||
+ | arrowheads.name = " | ||
+ | var arrowstyle = obj.userData.arrowstyle; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var edgematerials = obj.userData.edgematerial; | ||
+ | var points = obj.userData.points; | ||
+ | var material; | ||
+ | if (!Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials.color} ); | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var start = points[edgeindices[i]]; | ||
+ | var end = points[edgeindices[i+1]]; | ||
+ | var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius(); | ||
+ | if (dist <= 0) { | ||
+ | continue; | ||
+ | } | ||
+ | var dir = new THREE.Vector3().subVectors(end.vector, | ||
+ | dir.normalize(); | ||
+ | var axis = new THREE.Vector3().set(dir.z, | ||
+ | axis.normalize(); | ||
+ | var radians = Math.acos( dir.y ); | ||
+ | var radius = dist/25; | ||
+ | var height = dist/5; | ||
+ | var geometry = new THREE.ConeBufferGeometry(radius, | ||
+ | var position = new THREE.Vector3().addVectors(start.vector, | ||
+ | if (Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} ); | ||
+ | } | ||
+ | var cone = new THREE.Mesh( geometry, material ); | ||
+ | cone.quaternion.setFromAxisAngle(axis, | ||
+ | cone.position.copy(position);; | ||
+ | arrowheads.add(cone); | ||
+ | } | ||
+ | obj.add(arrowheads); | ||
+ | } | ||
+ | |||
+ | function init_faces(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var facets = obj.userData.facets; | ||
+ | obj.userData.triangleindices = []; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | for (var t=0; t< | ||
+ | obj.userData.triangleindices.push(facet[0], | ||
+ | } | ||
+ | } | ||
+ | var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute(bufarr, | ||
+ | | ||
+ | var materials = obj.userData.facetmaterial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var frontmaterials = []; | ||
+ | var backmaterials = []; | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | var tricount = 0; | ||
+ | var facet; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | geometry.addGroup(tricount, | ||
+ | tricount += (facet.length-2)*3; | ||
+ | } | ||
+ | for (var j=0; j< | ||
+ | var fmat = materials[j].clone() | ||
+ | fmat.side = THREE.FrontSide; | ||
+ | frontmaterials.push(fmat); | ||
+ | var bmat = materials[j].clone() | ||
+ | bmat.side = THREE.BackSide; | ||
+ | backmaterials.push(bmat); | ||
+ | obj.userData.facetmaterial = frontmaterials.concat(backmaterials); | ||
+ | } | ||
+ | } else if (materials instanceof THREE.Material) { | ||
+ | frontmaterials = materials.clone() | ||
+ | frontmaterials.side = THREE.FrontSide; | ||
+ | backmaterials = materials.clone() | ||
+ | backmaterials.side = THREE.BackSide; | ||
+ | obj.userData.facetmaterial = [frontmaterials, | ||
+ | } | ||
+ | // duplicating the object with front and back should avoid transparency issues | ||
+ | var backmesh = new THREE.Mesh(geometry, | ||
+ | // meshname is used to show/hide objects | ||
+ | backmesh.name = " | ||
+ | obj.add(backmesh); | ||
+ | var frontmesh = new THREE.Mesh(geometry, | ||
+ | frontmesh.name = " | ||
+ | obj.add(frontmesh); | ||
+ | updateFacesPosition(obj); | ||
+ | } | ||
+ | // // | ||
+ | |||
+ | |||
+ | function updateFacesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.triangleindices; | ||
+ | var faces = obj.getObjectByName(" | ||
+ | var ba = faces.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | faces.geometry.attributes.position.needsUpdate = true; | ||
+ | | ||
+ | } | ||
+ | |||
+ | function updateEdgesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.edgeindices; | ||
+ | var lines = obj.getObjectByName(" | ||
+ | var ba = lines.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | lines.geometry.attributes.position.needsUpdate = true; | ||
+ | } | ||
+ | |||
+ | function onWindowResize() { | ||
+ | renderer.setSize( three.clientWidth, | ||
+ | svgRenderer.setSize( three.clientWidth, | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | function updateCamera() { | ||
+ | var width = three.clientWidth; | ||
+ | var height = three.clientHeight; | ||
+ | var aspect = width / height; | ||
+ | if (camera.type == " | ||
+ | camera.left = frustumSize * aspect / - 2; | ||
+ | camera.right = frustumSize * aspect / 2; | ||
+ | camera.top = frustumSize / 2; | ||
+ | camera.bottom = - frustumSize / 2; | ||
+ | } else if (camera.type == " | ||
+ | camera.aspect = aspect; | ||
+ | } | ||
+ | camera.updateProjectionMatrix(); | ||
+ | } | ||
+ | |||
+ | function changeCamera(event) { | ||
+ | var selindex = event.currentTarget.selectedIndex; | ||
+ | camera = cameras[selindex]; | ||
+ | control = controls[selindex]; | ||
+ | control.enabled = true; | ||
+ | for (var i=0; i< | ||
+ | if (i!=selindex) { | ||
+ | controls[i].enabled = false; | ||
+ | } | ||
+ | } | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | var camtypenode = document.getElementById(' | ||
+ | camtypenode.onchange = changeCamera; | ||
+ | camtypenode.dispatchEvent(new Event(' | ||
+ | |||
+ | onWindowResize(); | ||
+ | window.addEventListener(' | ||
+ | |||
+ | |||
+ | var xRotationEnabled = false; | ||
+ | var yRotationEnabled = false; | ||
+ | var zRotationEnabled = false; | ||
+ | var rotationSpeedFactor = 1; | ||
+ | var settingsShown = false; | ||
+ | var labelsShown = true; | ||
+ | var intervals = []; | ||
+ | var timeouts = []; | ||
+ | var explodingSpeed = 0.05; | ||
+ | var explodeScale = 0.000001; | ||
+ | var XMLS = new XMLSerializer(); | ||
+ | var svgElement; | ||
+ | var renderId; | ||
+ | |||
+ | var render = function () { | ||
+ | |||
+ | renderId = requestAnimationFrame(render); | ||
+ | |||
+ | // comment in for automatic explosion | ||
+ | // | ||
+ | |||
+ | var phi = 0.02 * rotationSpeedFactor; | ||
+ | |||
+ | if (xRotationEnabled) { | ||
+ | scene.rotation.x += phi; | ||
+ | } | ||
+ | if (yRotationEnabled) { | ||
+ | scene.rotation.y += phi; | ||
+ | } | ||
+ | if (zRotationEnabled) { | ||
+ | scene.rotation.z += phi; | ||
+ | } | ||
+ | |||
+ | control.update(); | ||
+ | renderer.render(scene, | ||
+ | }; | ||
+ | |||
+ | if ( THREE.WEBGL.isWebGLAvailable() ) { | ||
+ | render(); | ||
+ | } else { | ||
+ | var warning = WEBGL.getWebGLErrorMessage(); | ||
+ | three.appendChild( warning ); | ||
+ | } | ||
+ | | ||
+ | function changeTransparency() { | ||
+ | var opacity = 1-Number(event.currentTarget.value); | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].opacity = opacity; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.opacity = opacity; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleDepthWrite(event) { | ||
+ | depthwrite = event.currentTarget.checked; | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].depthWrite = depthwrite; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.depthWrite = depthWrite; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function changeRotationX(event){ | ||
+ | xRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationY(event){ | ||
+ | yRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationZ(event){ | ||
+ | zRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | |||
+ | function changeRotationSpeedFactor(event){ | ||
+ | rotationSpeedFactor = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function resetScene(){ | ||
+ | scene.rotation.set(0, | ||
+ | camera.position.set(0, | ||
+ | camera.up.set(0, | ||
+ | } | ||
+ | |||
+ | function showSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = true; | ||
+ | } | ||
+ | |||
+ | function hideSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = false; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | var pos = 150* Math.PI; | ||
+ | |||
+ | function updateFactor() { | ||
+ | pos++; | ||
+ | return Math.sin(.01*pos)+1; | ||
+ | } | ||
+ | |||
+ | // ------------------------ FOLDING ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | // rotate point p around axis defined by points p1 and p2 by given angle | ||
+ | function rotate(p, p1, p2, angle ){ | ||
+ | angle = -angle; | ||
+ | var x = p.x, y = p.y, z = p.z, | ||
+ | a = p1.x, b = p1.y, c = p1.z, | ||
+ | u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z; | ||
+ | var result = []; | ||
+ | var L = u*u + v*v + w*w; | ||
+ | var sqrt = Math.sqrt; | ||
+ | var cos = Math.cos; | ||
+ | var sin = Math.sin; | ||
+ | |||
+ | result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/ | ||
+ | result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/ | ||
+ | result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/ | ||
+ | |||
+ | return result; | ||
+ | } | ||
+ | |||
+ | var fold = function(event){ | ||
+ | var obj = foldables[Number(event.currentTarget.name)]; | ||
+ | var foldvalue = Number(event.currentTarget.value); | ||
+ | var scale = foldvalue - obj.userData.oldscale; | ||
+ | |||
+ | for (var j=0; j< | ||
+ | rotateVertices(obj, | ||
+ | } | ||
+ | update(obj); | ||
+ | obj.userData.oldscale += scale; | ||
+ | lookAtBarycenter(obj); | ||
+ | } | ||
+ | |||
+ | function lookAtBarycenter(obj){ | ||
+ | control.target = barycenter(obj); | ||
+ | } | ||
+ | |||
+ | function barycenter(obj) { | ||
+ | var center = new THREE.Vector3(0, | ||
+ | var points = obj.userData.points; | ||
+ | for (var i=0; i< | ||
+ | center.add(points[i].vector); | ||
+ | } | ||
+ | center.divideScalar(points.length); | ||
+ | return center; | ||
+ | } | ||
+ | |||
+ | function rotateVertices(obj, | ||
+ | var axes = obj.userData.axes; | ||
+ | var subtrees = obj.userData.subtrees; | ||
+ | var points = obj.userData.points; | ||
+ | var angles = obj.userData.angles; | ||
+ | if (edge < axes.length){ | ||
+ | for (var j=0; j< | ||
+ | var rotP = rotate(points[subtrees[edge][j]].vector, | ||
+ | points[subtrees[edge][j]].set(rotP[0], | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function update(obj) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | if (foldables.length) { | ||
+ | var settings = document.getElementById(' | ||
+ | var foldDiv = document.createElement(' | ||
+ | foldDiv.id = ' | ||
+ | var title = document.createElement(' | ||
+ | title.innerHTML = ' | ||
+ | foldDiv.appendChild(title); | ||
+ | foldDiv.className = ' | ||
+ | for (var i=0; i< | ||
+ | var range = document.createElement(' | ||
+ | range.type = ' | ||
+ | range.min = 0; | ||
+ | range.max = 1; | ||
+ | range.value = 0; | ||
+ | range.step = 0.001; | ||
+ | range.name = String(i); | ||
+ | range.oninput = fold; | ||
+ | foldDiv.appendChild(range); | ||
+ | } | ||
+ | lookAtBarycenter(foldables[0]); | ||
+ | settings.insertBefore(foldDiv, | ||
+ | } | ||
+ | |||
+ | | ||
+ | // ---------------------- EXPLOSION ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | if (explodableModel) { | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | if ( obj.userData.explodable ) { | ||
+ | computeCentroid(obj); | ||
+ | } | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | explode(0.000001); | ||
+ | } | ||
+ | |||
+ | function computeCentroid(obj) { | ||
+ | centroid = new THREE.Vector3(); | ||
+ | obj.userData.points.forEach(function(pmpoint) { | ||
+ | centroid.add(pmpoint.vector); | ||
+ | }); | ||
+ | centroid.divideScalar(obj.userData.points.length); | ||
+ | obj.userData.centroid = centroid; | ||
+ | } | ||
+ | |||
+ | function explode(factor) { | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i]; | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | var c = obj.userData.centroid; | ||
+ | obj.position.set(c.x*factor, | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function triggerExplode(event){ | ||
+ | explodeScale = Number(event.currentTarget.value); | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | |||
+ | function setExplodingSpeed(event){ | ||
+ | explodingSpeed = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function triggerAutomaticExplode(event){ | ||
+ | if (event.currentTarget.checked){ | ||
+ | startExploding(); | ||
+ | } else { | ||
+ | clearIntervals(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function startExploding(){ | ||
+ | intervals.push(setInterval(explodingInterval, | ||
+ | } | ||
+ | |||
+ | |||
+ | function explodingInterval(){ | ||
+ | explodeScale += explodingSpeed; | ||
+ | if (explodeScale <= 6){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else{ | ||
+ | explode(6); | ||
+ | explodeScale = 6; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startUnexploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | |||
+ | function startUnexploding(){ | ||
+ | intervals.push(setInterval(unexplodingInterval, | ||
+ | } | ||
+ | |||
+ | function unexplodingInterval(){ | ||
+ | explodeScale -= explodingSpeed; | ||
+ | if (explodeScale >= 0){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else { | ||
+ | explode(0); | ||
+ | explodeScale = 0; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startExploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | function clearIntervals(){ | ||
+ | intervals.forEach(function(interval){ | ||
+ | clearInterval(interval); | ||
+ | }); | ||
+ | intervals = []; | ||
+ | timeouts.forEach(function(timeout){ | ||
+ | clearTimeout(timeout); | ||
+ | }); | ||
+ | timeouts = []; | ||
+ | } | ||
+ | |||
+ | // ---------------------- DISPLAY -------------------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | const objectTypeInnerHTMLs = { points: " | ||
+ | const objectTypeVisible = {}; | ||
+ | Object.assign(objectTypeVisible, | ||
+ | const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort(); | ||
+ | const shownObjectTypesList = document.getElementById(' | ||
+ | |||
+ | function setVisibility(bool, | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i].getObjectByName(objname); | ||
+ | if (obj) { | ||
+ | obj.visible = bool; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleObjectTypeVisibility(event){ | ||
+ | var name = event.currentTarget.name; | ||
+ | var checked = event.currentTarget.checked; | ||
+ | objectTypeVisible[name] = checked; | ||
+ | if (name == " | ||
+ | setVisibility(checked," | ||
+ | setVisibility(checked," | ||
+ | } else { | ||
+ | setVisibility(checked, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var key = sortedObjectTypeKeys[i]; | ||
+ | if (modelContains[key]) { | ||
+ | var objTypeNode = document.createElement(' | ||
+ | objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = key; | ||
+ | checkbox.onchange = toggleObjectTypeVisibility; | ||
+ | shownObjectTypesList.appendChild(checkbox); | ||
+ | shownObjectTypesList.appendChild(objTypeNode); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // ------------------------------------------------------ | ||
+ | |||
+ | function toggleObjectVisibility(event){ | ||
+ | var nr = Number(event.currentTarget.name); | ||
+ | scene.children[nr].visible = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | // append checkboxes for displaying or hiding objects | ||
+ | var shownObjectsList = document.getElementById(' | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | var objNode = document.createElement(' | ||
+ | objNode.innerHTML = obj.name + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = String(i); | ||
+ | checkbox.onchange = toggleObjectVisibility; | ||
+ | shownObjectsList.appendChild(checkbox); | ||
+ | shownObjectsList.appendChild(objNode); | ||
+ | } | ||
+ | |||
+ | // ---------------------- SVG ------------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function takeSvgScreenshot() { | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | svgRenderer.render(scene, | ||
+ | svgElement = XMLS.serializeToString(svgRenderer.domElement); | ||
+ | | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | |||
+ | if (document.getElementById(' | ||
+ | //show in new tab | ||
+ | var myWindow = window.open("","" | ||
+ | myWindow.document.body.innerHTML = svgElement; | ||
+ | } else{ | ||
+ | // download svg file | ||
+ | download(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function download(filename, | ||
+ | var element = document.createElement(' | ||
+ | element.setAttribute(' | ||
+ | element.setAttribute(' | ||
+ | |||
+ | element.style.display = ' | ||
+ | document.body.appendChild(element); | ||
+ | |||
+ | element.click(); | ||
+ | |||
+ | document.body.removeChild(element); | ||
+ | } | ||
+ | |||
+ | |||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | |||
+ | |||
+ | // ------------------ SHORTCUTS -------------------------------------------- | ||
+ | // ------------------------------------------------------------------------- | ||
+ | |||
+ | /** | ||
+ | * http:// | ||
+ | * Version : 2.01.B | ||
+ | * By Binny V A | ||
+ | * License : BSD | ||
+ | */ | ||
+ | shortcut = { | ||
+ | ' | ||
+ | ' | ||
+ | //Provide a set of default options | ||
+ | var default_options = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | if(!opt) opt = default_options; | ||
+ | else { | ||
+ | for(var dfo in default_options) { | ||
+ | if(typeof opt[dfo] == ' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var ele = opt.target; | ||
+ | if(typeof opt.target == ' | ||
+ | var ths = this; | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | |||
+ | //The function to be called at keypress | ||
+ | var func = function(e) { | ||
+ | e = e || window.event; | ||
+ | |||
+ | if(opt[' | ||
+ | var element; | ||
+ | if(e.target) element=e.target; | ||
+ | else if(e.srcElement) element=e.srcElement; | ||
+ | if(element.nodeType==3) element=element.parentNode; | ||
+ | |||
+ | if(element.tagName == ' | ||
+ | } | ||
+ | |||
+ | //Find Which key is pressed | ||
+ | if (e.keyCode) code = e.keyCode; | ||
+ | else if (e.which) code = e.which; | ||
+ | var character = String.fromCharCode(code).toLowerCase(); | ||
+ | |||
+ | if(code == 188) character=","; | ||
+ | if(code == 190) character=" | ||
+ | |||
+ | var keys = shortcut_combination.split(" | ||
+ | //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked | ||
+ | var kp = 0; | ||
+ | |||
+ | //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken | ||
+ | var shift_nums = { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | ";":":", | ||
+ | "'":" | ||
+ | ",":"<", | ||
+ | " | ||
+ | "/":"?", | ||
+ | " | ||
+ | } | ||
+ | // | ||
+ | var special_keys = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | |||
+ | var modifiers = { | ||
+ | shift: { wanted: | ||
+ | ctrl : { wanted: | ||
+ | alt | ||
+ | meta : { wanted: | ||
+ | }; | ||
+ | | ||
+ | if(e.ctrlKey) modifiers.ctrl.pressed = true; | ||
+ | if(e.shiftKey) modifiers.shift.pressed = true; | ||
+ | if(e.altKey) modifiers.alt.pressed = true; | ||
+ | if(e.metaKey) | ||
+ | | ||
+ | for(var i=0; k=keys[i], | ||
+ | // | ||
+ | if(k == ' | ||
+ | kp++; | ||
+ | modifiers.ctrl.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.shift.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.alt.wanted = true; | ||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.meta.wanted = true; | ||
+ | } else if(k.length > 1) { //If it is a special key | ||
+ | if(special_keys[k] == code) kp++; | ||
+ | |||
+ | } else if(opt[' | ||
+ | if(opt[' | ||
+ | |||
+ | } else { //The special keys did not match | ||
+ | if(character == k) kp++; | ||
+ | else { | ||
+ | if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase | ||
+ | character = shift_nums[character]; | ||
+ | if(character == k) kp++; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if(kp == keys.length && | ||
+ | modifiers.ctrl.pressed == modifiers.ctrl.wanted && | ||
+ | modifiers.shift.pressed == modifiers.shift.wanted && | ||
+ | modifiers.alt.pressed == modifiers.alt.wanted && | ||
+ | modifiers.meta.pressed == modifiers.meta.wanted) { | ||
+ | callback(e); | ||
+ | |||
+ | if(!opt[' | ||
+ | // | ||
+ | e.cancelBubble = true; | ||
+ | e.returnValue = false; | ||
+ | |||
+ | // | ||
+ | if (e.stopPropagation) { | ||
+ | e.stopPropagation(); | ||
+ | e.preventDefault(); | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | this.all_shortcuts[shortcut_combination] = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }; | ||
+ | //Attach the function with the event | ||
+ | if(ele.addEventListener) ele.addEventListener(opt[' | ||
+ | else if(ele.attachEvent) ele.attachEvent(' | ||
+ | else ele[' | ||
+ | }, | ||
+ | |||
+ | //Remove the shortcut - just specify the shortcut and I will remove the binding | ||
+ | ' | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | var binding = this.all_shortcuts[shortcut_combination]; | ||
+ | delete(this.all_shortcuts[shortcut_combination]) | ||
+ | if(!binding) return; | ||
+ | var type = binding[' | ||
+ | var ele = binding[' | ||
+ | var callback = binding[' | ||
+ | |||
+ | if(ele.detachEvent) ele.detachEvent(' | ||
+ | else if(ele.removeEventListener) ele.removeEventListener(type, | ||
+ | else ele[' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | shortcut.add(" | ||
+ | var event = new Event(' | ||
+ | if (settingsShown){ | ||
+ | document.getElementById(' | ||
+ | } else { | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | === Labels === | ||
+ | |||
+ | The labels can be specified either by an array or a function that returns a label depending on the index of the vertex. | ||
+ | |||
+ | **Array of labels**: To label the vertices of a tetrahedron by A, B, C, and D we just pass the array '' | ||
+ | |||
+ | <code perl> | ||
+ | > simplex(3)-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Tue Mar 29 16:03:37 2022 | ||
+ | unnamed | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <meta charset=utf-8> | ||
+ | < | ||
+ | < | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | */ | ||
+ | html {overflow: scroll;} | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | # | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_END | ||
+ | */ | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | <div id=' | ||
+ | <div class=group id=' | ||
+ | < | ||
+ | < | ||
+ | <div class=indented>< | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | <div class=suboption> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | <div class=suboption> | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | <select id=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <img id=' | ||
+ | <img id=' | ||
+ | <div id=" | ||
+ | </ | ||
+ | < | ||
+ | requirejs.config({ | ||
+ | paths: { | ||
+ | three: '/ | ||
+ | TrackballControls: | ||
+ | OrbitControls: | ||
+ | Projector: '/ | ||
+ | SVGRenderer: | ||
+ | WEBGL: '/ | ||
+ | }, | ||
+ | shim: { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | }); | ||
+ | | ||
+ | require([' | ||
+ | window.THREE = THREE; | ||
+ | require([' | ||
+ | | ||
+ | THREE.TrackballControls = TrackballControls; | ||
+ | THREE.OrbitControls = OrbitControls; | ||
+ | THREE.Projector = Projector; | ||
+ | THREE.SVGRenderer = SVGRenderer; | ||
+ | THREE.WEBGL = WEBGL; | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | |||
+ | const intervalLength = 25; // for automatic animations | ||
+ | const explodableModel = false; | ||
+ | const modelContains = { points: false, pointlabels: | ||
+ | const foldables = []; | ||
+ | |||
+ | var three = document.getElementById(" | ||
+ | var scene = new THREE.Scene(); | ||
+ | var renderer = new THREE.WebGLRenderer( { antialias: true } ); | ||
+ | var svgRenderer = new THREE.SVGRenderer( { antialias: true } ); | ||
+ | renderer.setPixelRatio( window.devicePixelRatio ); | ||
+ | renderer.setClearColor(0xFFFFFF, | ||
+ | svgRenderer.setClearColor(0xFFFFFF, | ||
+ | three.appendChild(renderer.domElement); | ||
+ | |||
+ | var frustumSize = 4; | ||
+ | var cameras = [new THREE.PerspectiveCamera(75, | ||
+ | cameras.forEach(function(cam) { | ||
+ | cam.position.set(0, | ||
+ | cam.lookAt(0, | ||
+ | cam.up.set(0, | ||
+ | }); | ||
+ | var controls = [new THREE.TrackballControls(cameras[0], | ||
+ | var camera, control; | ||
+ | |||
+ | controls[0].zoomSpeed = 0.2; | ||
+ | controls[0].rotateSpeed = 4; | ||
+ | |||
+ | |||
+ | // class to allow move points together with labels and spheres | ||
+ | var PMPoint = function (x,y,z) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addLabel = function(labelsprite) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addSphere = function(spheremesh) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.set = function(x, | ||
+ | | ||
+ | if (this.sprite) { | ||
+ | this.sprite.position.copy(this.vector); | ||
+ | } | ||
+ | if (this.sphere) { | ||
+ | this.sphere.position.copy(this.vector); | ||
+ | } | ||
+ | } | ||
+ | PMPoint.prototype.radius = function() { | ||
+ | if (this.sphere) { | ||
+ | return this.sphere.geometry.parameters.radius; | ||
+ | } else { | ||
+ | return 0; | ||
+ | } | ||
+ | }; | ||
+ | // select the target node | ||
+ | var target = document.querySelector('# | ||
+ | |||
+ | // create an observer instance | ||
+ | var observer = new MutationObserver(function(mutations) { | ||
+ | | ||
+ | if (mutation.removedNodes && mutation.removedNodes.length > 0) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | // configuration of the observer: | ||
+ | var config = { childList: true, characterData: | ||
+ | |||
+ | // pass in the target node, as well as the observer options | ||
+ | while (target) { | ||
+ | if (target.className==" | ||
+ | observer.observe(target, | ||
+ | break; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | var obj0 = new THREE.Object3D(); | ||
+ | obj0.name = " | ||
+ | obj0.userData.explodable = 1; | ||
+ | obj0.userData.points = []; | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 1)); | ||
+ | |||
+ | obj0.userData.pointradii = 0.02; | ||
+ | < | ||
+ | obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | obj0.userData.pointlabels = [" | ||
+ | obj0.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[2, 3, 1], [0, 3, 2], [1, 3, 0], [2, 1, 0]]; | ||
+ | < | ||
+ | obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj0); | ||
+ | scene.add(obj0); | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | function textSpriteMaterial(message, | ||
+ | if ( parameters === undefined ) parameters = {}; | ||
+ | var fontface = " | ||
+ | var fontsize = parameters.hasOwnProperty(" | ||
+ | fontsize = fontsize*10; | ||
+ | var lines = message.split(' | ||
+ | var size = 512; | ||
+ | for(var i = 0; i< | ||
+ | var tmp = lines[i].length; | ||
+ | while(tmp*fontsize > size){ | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | var canvas = document.createElement(' | ||
+ | canvas.width = size; | ||
+ | canvas.height = size; | ||
+ | var context = canvas.getContext(' | ||
+ | context.fillStyle = " | ||
+ | context.fill(); | ||
+ | context.font = fontsize + "px " + fontface; | ||
+ | | ||
+ | // text color | ||
+ | context.fillStyle = " | ||
+ | | ||
+ | context.fillText(lines[i], | ||
+ | } | ||
+ | | ||
+ | // canvas contents will be used for a texture | ||
+ | var texture = new THREE.Texture(canvas); | ||
+ | texture.needsUpdate = true; | ||
+ | | ||
+ | var spriteMaterial = new THREE.SpriteMaterial({map: | ||
+ | return spriteMaterial; | ||
+ | } | ||
+ | |||
+ | |||
+ | // ---------------------- INITIALIZING OBJECTS-------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function init_object(obj) { | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_points(obj); | ||
+ | modelContains.points = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_pointlabels(obj); | ||
+ | modelContains.pointlabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_lines(obj); | ||
+ | modelContains.lines = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_edgelabels(obj); | ||
+ | modelContains.edgelabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_arrowheads(obj); | ||
+ | modelContains.arrowheads = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_faces(obj); | ||
+ | modelContains.faces = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function init_points(obj) { | ||
+ | var pointgroup = new THREE.Group(); | ||
+ | pointgroup.name = " | ||
+ | var points = obj.userData.points; | ||
+ | var radii = obj.userData.pointradii; | ||
+ | var materials = obj.userData.pointmaterial; | ||
+ | var geometry, | ||
+ | if (!Array.isArray(radii)) { | ||
+ | geometry = new THREE.SphereBufferGeometry(radii); | ||
+ | } | ||
+ | if (!Array.isArray(materials)) { | ||
+ | material = materials; | ||
+ | } | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | if (Array.isArray(radii)) { | ||
+ | if (radii[i] == 0) { | ||
+ | continue; | ||
+ | } | ||
+ | geometry = new THREE.SphereBufferGeometry(radii[i]); | ||
+ | } | ||
+ | if (Array.isArray(materials)) { | ||
+ | material = materials[i]; | ||
+ | } | ||
+ | var sphere = new THREE.Mesh(geometry, | ||
+ | point.addSphere(sphere); | ||
+ | pointgroup.add(sphere); | ||
+ | } | ||
+ | obj.add(pointgroup); | ||
+ | } | ||
+ | |||
+ | function init_pointlabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var labels = obj.userData.pointlabels; | ||
+ | var pointlabels = new THREE.Group(); | ||
+ | pointlabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(pointlabels); | ||
+ | } | ||
+ | |||
+ | function init_lines(obj) { | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var points = obj.userData.points; | ||
+ | var materials = obj.userData.edgematerial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 ); | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | for (var i=0; i< | ||
+ | geometry.addGroup(2*i, | ||
+ | } | ||
+ | } | ||
+ | var lines = new THREE.LineSegments(geometry, | ||
+ | lines.name = " | ||
+ | obj.add(lines); | ||
+ | updateEdgesPosition(obj); | ||
+ | } | ||
+ | |||
+ | function init_edgelabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var labels = obj.userData.edgelabels; | ||
+ | var edgelabels = new THREE.Group(); | ||
+ | edgelabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(edgelabels); | ||
+ | } | ||
+ | |||
+ | function init_arrowheads(obj) { | ||
+ | var arrowheads = new THREE.Group(); | ||
+ | arrowheads.name = " | ||
+ | var arrowstyle = obj.userData.arrowstyle; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var edgematerials = obj.userData.edgematerial; | ||
+ | var points = obj.userData.points; | ||
+ | var material; | ||
+ | if (!Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials.color} ); | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var start = points[edgeindices[i]]; | ||
+ | var end = points[edgeindices[i+1]]; | ||
+ | var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius(); | ||
+ | if (dist <= 0) { | ||
+ | continue; | ||
+ | } | ||
+ | var dir = new THREE.Vector3().subVectors(end.vector, | ||
+ | dir.normalize(); | ||
+ | var axis = new THREE.Vector3().set(dir.z, | ||
+ | axis.normalize(); | ||
+ | var radians = Math.acos( dir.y ); | ||
+ | var radius = dist/25; | ||
+ | var height = dist/5; | ||
+ | var geometry = new THREE.ConeBufferGeometry(radius, | ||
+ | var position = new THREE.Vector3().addVectors(start.vector, | ||
+ | if (Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} ); | ||
+ | } | ||
+ | var cone = new THREE.Mesh( geometry, material ); | ||
+ | cone.quaternion.setFromAxisAngle(axis, | ||
+ | cone.position.copy(position);; | ||
+ | arrowheads.add(cone); | ||
+ | } | ||
+ | obj.add(arrowheads); | ||
+ | } | ||
+ | |||
+ | function init_faces(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var facets = obj.userData.facets; | ||
+ | obj.userData.triangleindices = []; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | for (var t=0; t< | ||
+ | obj.userData.triangleindices.push(facet[0], | ||
+ | } | ||
+ | } | ||
+ | var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute(bufarr, | ||
+ | | ||
+ | var materials = obj.userData.facetmaterial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var frontmaterials = []; | ||
+ | var backmaterials = []; | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | var tricount = 0; | ||
+ | var facet; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | geometry.addGroup(tricount, | ||
+ | tricount += (facet.length-2)*3; | ||
+ | } | ||
+ | for (var j=0; j< | ||
+ | var fmat = materials[j].clone() | ||
+ | fmat.side = THREE.FrontSide; | ||
+ | frontmaterials.push(fmat); | ||
+ | var bmat = materials[j].clone() | ||
+ | bmat.side = THREE.BackSide; | ||
+ | backmaterials.push(bmat); | ||
+ | obj.userData.facetmaterial = frontmaterials.concat(backmaterials); | ||
+ | } | ||
+ | } else if (materials instanceof THREE.Material) { | ||
+ | frontmaterials = materials.clone() | ||
+ | frontmaterials.side = THREE.FrontSide; | ||
+ | backmaterials = materials.clone() | ||
+ | backmaterials.side = THREE.BackSide; | ||
+ | obj.userData.facetmaterial = [frontmaterials, | ||
+ | } | ||
+ | // duplicating the object with front and back should avoid transparency issues | ||
+ | var backmesh = new THREE.Mesh(geometry, | ||
+ | // meshname is used to show/hide objects | ||
+ | backmesh.name = " | ||
+ | obj.add(backmesh); | ||
+ | var frontmesh = new THREE.Mesh(geometry, | ||
+ | frontmesh.name = " | ||
+ | obj.add(frontmesh); | ||
+ | updateFacesPosition(obj); | ||
+ | } | ||
+ | // // | ||
+ | |||
+ | |||
+ | function updateFacesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.triangleindices; | ||
+ | var faces = obj.getObjectByName(" | ||
+ | var ba = faces.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | faces.geometry.attributes.position.needsUpdate = true; | ||
+ | | ||
+ | } | ||
+ | |||
+ | function updateEdgesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.edgeindices; | ||
+ | var lines = obj.getObjectByName(" | ||
+ | var ba = lines.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | lines.geometry.attributes.position.needsUpdate = true; | ||
+ | } | ||
+ | |||
+ | function onWindowResize() { | ||
+ | renderer.setSize( three.clientWidth, | ||
+ | svgRenderer.setSize( three.clientWidth, | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | function updateCamera() { | ||
+ | var width = three.clientWidth; | ||
+ | var height = three.clientHeight; | ||
+ | var aspect = width / height; | ||
+ | if (camera.type == " | ||
+ | camera.left = frustumSize * aspect / - 2; | ||
+ | camera.right = frustumSize * aspect / 2; | ||
+ | camera.top = frustumSize / 2; | ||
+ | camera.bottom = - frustumSize / 2; | ||
+ | } else if (camera.type == " | ||
+ | camera.aspect = aspect; | ||
+ | } | ||
+ | camera.updateProjectionMatrix(); | ||
+ | } | ||
+ | |||
+ | function changeCamera(event) { | ||
+ | var selindex = event.currentTarget.selectedIndex; | ||
+ | camera = cameras[selindex]; | ||
+ | control = controls[selindex]; | ||
+ | control.enabled = true; | ||
+ | for (var i=0; i< | ||
+ | if (i!=selindex) { | ||
+ | controls[i].enabled = false; | ||
+ | } | ||
+ | } | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | var camtypenode = document.getElementById(' | ||
+ | camtypenode.onchange = changeCamera; | ||
+ | camtypenode.dispatchEvent(new Event(' | ||
+ | |||
+ | onWindowResize(); | ||
+ | window.addEventListener(' | ||
+ | |||
+ | |||
+ | var xRotationEnabled = false; | ||
+ | var yRotationEnabled = false; | ||
+ | var zRotationEnabled = false; | ||
+ | var rotationSpeedFactor = 1; | ||
+ | var settingsShown = false; | ||
+ | var labelsShown = true; | ||
+ | var intervals = []; | ||
+ | var timeouts = []; | ||
+ | var explodingSpeed = 0.05; | ||
+ | var explodeScale = 0.000001; | ||
+ | var XMLS = new XMLSerializer(); | ||
+ | var svgElement; | ||
+ | var renderId; | ||
+ | |||
+ | var render = function () { | ||
+ | |||
+ | renderId = requestAnimationFrame(render); | ||
+ | |||
+ | // comment in for automatic explosion | ||
+ | // | ||
+ | |||
+ | var phi = 0.02 * rotationSpeedFactor; | ||
+ | |||
+ | if (xRotationEnabled) { | ||
+ | scene.rotation.x += phi; | ||
+ | } | ||
+ | if (yRotationEnabled) { | ||
+ | scene.rotation.y += phi; | ||
+ | } | ||
+ | if (zRotationEnabled) { | ||
+ | scene.rotation.z += phi; | ||
+ | } | ||
+ | |||
+ | control.update(); | ||
+ | renderer.render(scene, | ||
+ | }; | ||
+ | |||
+ | if ( THREE.WEBGL.isWebGLAvailable() ) { | ||
+ | render(); | ||
+ | } else { | ||
+ | var warning = WEBGL.getWebGLErrorMessage(); | ||
+ | three.appendChild( warning ); | ||
+ | } | ||
+ | | ||
+ | function changeTransparency() { | ||
+ | var opacity = 1-Number(event.currentTarget.value); | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].opacity = opacity; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.opacity = opacity; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleDepthWrite(event) { | ||
+ | depthwrite = event.currentTarget.checked; | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].depthWrite = depthwrite; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.depthWrite = depthWrite; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function changeRotationX(event){ | ||
+ | xRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationY(event){ | ||
+ | yRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationZ(event){ | ||
+ | zRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | |||
+ | function changeRotationSpeedFactor(event){ | ||
+ | rotationSpeedFactor = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function resetScene(){ | ||
+ | scene.rotation.set(0, | ||
+ | camera.position.set(0, | ||
+ | camera.up.set(0, | ||
+ | } | ||
+ | |||
+ | function showSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = true; | ||
+ | } | ||
+ | |||
+ | function hideSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = false; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | var pos = 150* Math.PI; | ||
+ | |||
+ | function updateFactor() { | ||
+ | pos++; | ||
+ | return Math.sin(.01*pos)+1; | ||
+ | } | ||
+ | |||
+ | // ------------------------ FOLDING ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | // rotate point p around axis defined by points p1 and p2 by given angle | ||
+ | function rotate(p, p1, p2, angle ){ | ||
+ | angle = -angle; | ||
+ | var x = p.x, y = p.y, z = p.z, | ||
+ | a = p1.x, b = p1.y, c = p1.z, | ||
+ | u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z; | ||
+ | var result = []; | ||
+ | var L = u*u + v*v + w*w; | ||
+ | var sqrt = Math.sqrt; | ||
+ | var cos = Math.cos; | ||
+ | var sin = Math.sin; | ||
+ | |||
+ | result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/ | ||
+ | result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/ | ||
+ | result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/ | ||
+ | |||
+ | return result; | ||
+ | } | ||
+ | |||
+ | var fold = function(event){ | ||
+ | var obj = foldables[Number(event.currentTarget.name)]; | ||
+ | var foldvalue = Number(event.currentTarget.value); | ||
+ | var scale = foldvalue - obj.userData.oldscale; | ||
+ | |||
+ | for (var j=0; j< | ||
+ | rotateVertices(obj, | ||
+ | } | ||
+ | update(obj); | ||
+ | obj.userData.oldscale += scale; | ||
+ | lookAtBarycenter(obj); | ||
+ | } | ||
+ | |||
+ | function lookAtBarycenter(obj){ | ||
+ | control.target = barycenter(obj); | ||
+ | } | ||
+ | |||
+ | function barycenter(obj) { | ||
+ | var center = new THREE.Vector3(0, | ||
+ | var points = obj.userData.points; | ||
+ | for (var i=0; i< | ||
+ | center.add(points[i].vector); | ||
+ | } | ||
+ | center.divideScalar(points.length); | ||
+ | return center; | ||
+ | } | ||
+ | |||
+ | function rotateVertices(obj, | ||
+ | var axes = obj.userData.axes; | ||
+ | var subtrees = obj.userData.subtrees; | ||
+ | var points = obj.userData.points; | ||
+ | var angles = obj.userData.angles; | ||
+ | if (edge < axes.length){ | ||
+ | for (var j=0; j< | ||
+ | var rotP = rotate(points[subtrees[edge][j]].vector, | ||
+ | points[subtrees[edge][j]].set(rotP[0], | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function update(obj) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | if (foldables.length) { | ||
+ | var settings = document.getElementById(' | ||
+ | var foldDiv = document.createElement(' | ||
+ | foldDiv.id = ' | ||
+ | var title = document.createElement(' | ||
+ | title.innerHTML = ' | ||
+ | foldDiv.appendChild(title); | ||
+ | foldDiv.className = ' | ||
+ | for (var i=0; i< | ||
+ | var range = document.createElement(' | ||
+ | range.type = ' | ||
+ | range.min = 0; | ||
+ | range.max = 1; | ||
+ | range.value = 0; | ||
+ | range.step = 0.001; | ||
+ | range.name = String(i); | ||
+ | range.oninput = fold; | ||
+ | foldDiv.appendChild(range); | ||
+ | } | ||
+ | lookAtBarycenter(foldables[0]); | ||
+ | settings.insertBefore(foldDiv, | ||
+ | } | ||
+ | |||
+ | | ||
+ | // ---------------------- EXPLOSION ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | if (explodableModel) { | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | if ( obj.userData.explodable ) { | ||
+ | computeCentroid(obj); | ||
+ | } | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | explode(0.000001); | ||
+ | } | ||
+ | |||
+ | function computeCentroid(obj) { | ||
+ | centroid = new THREE.Vector3(); | ||
+ | obj.userData.points.forEach(function(pmpoint) { | ||
+ | centroid.add(pmpoint.vector); | ||
+ | }); | ||
+ | centroid.divideScalar(obj.userData.points.length); | ||
+ | obj.userData.centroid = centroid; | ||
+ | } | ||
+ | |||
+ | function explode(factor) { | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i]; | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | var c = obj.userData.centroid; | ||
+ | obj.position.set(c.x*factor, | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function triggerExplode(event){ | ||
+ | explodeScale = Number(event.currentTarget.value); | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | |||
+ | function setExplodingSpeed(event){ | ||
+ | explodingSpeed = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function triggerAutomaticExplode(event){ | ||
+ | if (event.currentTarget.checked){ | ||
+ | startExploding(); | ||
+ | } else { | ||
+ | clearIntervals(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function startExploding(){ | ||
+ | intervals.push(setInterval(explodingInterval, | ||
+ | } | ||
+ | |||
+ | |||
+ | function explodingInterval(){ | ||
+ | explodeScale += explodingSpeed; | ||
+ | if (explodeScale <= 6){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else{ | ||
+ | explode(6); | ||
+ | explodeScale = 6; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startUnexploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | |||
+ | function startUnexploding(){ | ||
+ | intervals.push(setInterval(unexplodingInterval, | ||
+ | } | ||
+ | |||
+ | function unexplodingInterval(){ | ||
+ | explodeScale -= explodingSpeed; | ||
+ | if (explodeScale >= 0){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else { | ||
+ | explode(0); | ||
+ | explodeScale = 0; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startExploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | function clearIntervals(){ | ||
+ | intervals.forEach(function(interval){ | ||
+ | clearInterval(interval); | ||
+ | }); | ||
+ | intervals = []; | ||
+ | timeouts.forEach(function(timeout){ | ||
+ | clearTimeout(timeout); | ||
+ | }); | ||
+ | timeouts = []; | ||
+ | } | ||
+ | |||
+ | // ---------------------- DISPLAY -------------------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | const objectTypeInnerHTMLs = { points: " | ||
+ | const objectTypeVisible = {}; | ||
+ | Object.assign(objectTypeVisible, | ||
+ | const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort(); | ||
+ | const shownObjectTypesList = document.getElementById(' | ||
+ | |||
+ | function setVisibility(bool, | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i].getObjectByName(objname); | ||
+ | if (obj) { | ||
+ | obj.visible = bool; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleObjectTypeVisibility(event){ | ||
+ | var name = event.currentTarget.name; | ||
+ | var checked = event.currentTarget.checked; | ||
+ | objectTypeVisible[name] = checked; | ||
+ | if (name == " | ||
+ | setVisibility(checked," | ||
+ | setVisibility(checked," | ||
+ | } else { | ||
+ | setVisibility(checked, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var key = sortedObjectTypeKeys[i]; | ||
+ | if (modelContains[key]) { | ||
+ | var objTypeNode = document.createElement(' | ||
+ | objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = key; | ||
+ | checkbox.onchange = toggleObjectTypeVisibility; | ||
+ | shownObjectTypesList.appendChild(checkbox); | ||
+ | shownObjectTypesList.appendChild(objTypeNode); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // ------------------------------------------------------ | ||
+ | |||
+ | function toggleObjectVisibility(event){ | ||
+ | var nr = Number(event.currentTarget.name); | ||
+ | scene.children[nr].visible = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | // append checkboxes for displaying or hiding objects | ||
+ | var shownObjectsList = document.getElementById(' | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | var objNode = document.createElement(' | ||
+ | objNode.innerHTML = obj.name + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = String(i); | ||
+ | checkbox.onchange = toggleObjectVisibility; | ||
+ | shownObjectsList.appendChild(checkbox); | ||
+ | shownObjectsList.appendChild(objNode); | ||
+ | } | ||
+ | |||
+ | // ---------------------- SVG ------------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function takeSvgScreenshot() { | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | svgRenderer.render(scene, | ||
+ | svgElement = XMLS.serializeToString(svgRenderer.domElement); | ||
+ | | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | |||
+ | if (document.getElementById(' | ||
+ | //show in new tab | ||
+ | var myWindow = window.open("","" | ||
+ | myWindow.document.body.innerHTML = svgElement; | ||
+ | } else{ | ||
+ | // download svg file | ||
+ | download(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function download(filename, | ||
+ | var element = document.createElement(' | ||
+ | element.setAttribute(' | ||
+ | element.setAttribute(' | ||
+ | |||
+ | element.style.display = ' | ||
+ | document.body.appendChild(element); | ||
+ | |||
+ | element.click(); | ||
+ | |||
+ | document.body.removeChild(element); | ||
+ | } | ||
+ | |||
+ | |||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | |||
+ | |||
+ | // ------------------ SHORTCUTS -------------------------------------------- | ||
+ | // ------------------------------------------------------------------------- | ||
+ | |||
+ | /** | ||
+ | * http:// | ||
+ | * Version : 2.01.B | ||
+ | * By Binny V A | ||
+ | * License : BSD | ||
+ | */ | ||
+ | shortcut = { | ||
+ | ' | ||
+ | ' | ||
+ | //Provide a set of default options | ||
+ | var default_options = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | if(!opt) opt = default_options; | ||
+ | else { | ||
+ | for(var dfo in default_options) { | ||
+ | if(typeof opt[dfo] == ' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var ele = opt.target; | ||
+ | if(typeof opt.target == ' | ||
+ | var ths = this; | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | |||
+ | //The function to be called at keypress | ||
+ | var func = function(e) { | ||
+ | e = e || window.event; | ||
+ | |||
+ | if(opt[' | ||
+ | var element; | ||
+ | if(e.target) element=e.target; | ||
+ | else if(e.srcElement) element=e.srcElement; | ||
+ | if(element.nodeType==3) element=element.parentNode; | ||
+ | |||
+ | if(element.tagName == ' | ||
+ | } | ||
+ | |||
+ | //Find Which key is pressed | ||
+ | if (e.keyCode) code = e.keyCode; | ||
+ | else if (e.which) code = e.which; | ||
+ | var character = String.fromCharCode(code).toLowerCase(); | ||
+ | |||
+ | if(code == 188) character=","; | ||
+ | if(code == 190) character=" | ||
+ | |||
+ | var keys = shortcut_combination.split(" | ||
+ | //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked | ||
+ | var kp = 0; | ||
+ | |||
+ | //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken | ||
+ | var shift_nums = { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | ";":":", | ||
+ | "'":" | ||
+ | ",":"<", | ||
+ | " | ||
+ | "/":"?", | ||
+ | " | ||
+ | } | ||
+ | // | ||
+ | var special_keys = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | |||
+ | var modifiers = { | ||
+ | shift: { wanted: | ||
+ | ctrl : { wanted: | ||
+ | alt | ||
+ | meta : { wanted: | ||
+ | }; | ||
+ | | ||
+ | if(e.ctrlKey) modifiers.ctrl.pressed = true; | ||
+ | if(e.shiftKey) modifiers.shift.pressed = true; | ||
+ | if(e.altKey) modifiers.alt.pressed = true; | ||
+ | if(e.metaKey) | ||
+ | | ||
+ | for(var i=0; k=keys[i], | ||
+ | // | ||
+ | if(k == ' | ||
+ | kp++; | ||
+ | modifiers.ctrl.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.shift.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.alt.wanted = true; | ||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.meta.wanted = true; | ||
+ | } else if(k.length > 1) { //If it is a special key | ||
+ | if(special_keys[k] == code) kp++; | ||
+ | |||
+ | } else if(opt[' | ||
+ | if(opt[' | ||
+ | |||
+ | } else { //The special keys did not match | ||
+ | if(character == k) kp++; | ||
+ | else { | ||
+ | if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase | ||
+ | character = shift_nums[character]; | ||
+ | if(character == k) kp++; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if(kp == keys.length && | ||
+ | modifiers.ctrl.pressed == modifiers.ctrl.wanted && | ||
+ | modifiers.shift.pressed == modifiers.shift.wanted && | ||
+ | modifiers.alt.pressed == modifiers.alt.wanted && | ||
+ | modifiers.meta.pressed == modifiers.meta.wanted) { | ||
+ | callback(e); | ||
+ | |||
+ | if(!opt[' | ||
+ | // | ||
+ | e.cancelBubble = true; | ||
+ | e.returnValue = false; | ||
+ | |||
+ | // | ||
+ | if (e.stopPropagation) { | ||
+ | e.stopPropagation(); | ||
+ | e.preventDefault(); | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | this.all_shortcuts[shortcut_combination] = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }; | ||
+ | //Attach the function with the event | ||
+ | if(ele.addEventListener) ele.addEventListener(opt[' | ||
+ | else if(ele.attachEvent) ele.attachEvent(' | ||
+ | else ele[' | ||
+ | }, | ||
+ | |||
+ | //Remove the shortcut - just specify the shortcut and I will remove the binding | ||
+ | ' | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | var binding = this.all_shortcuts[shortcut_combination]; | ||
+ | delete(this.all_shortcuts[shortcut_combination]) | ||
+ | if(!binding) return; | ||
+ | var type = binding[' | ||
+ | var ele = binding[' | ||
+ | var callback = binding[' | ||
+ | |||
+ | if(ele.detachEvent) ele.detachEvent(' | ||
+ | else if(ele.removeEventListener) ele.removeEventListener(type, | ||
+ | else ele[' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | shortcut.add(" | ||
+ | var event = new Event(' | ||
+ | if (settingsShown){ | ||
+ | document.getElementById(' | ||
+ | } else { | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | If you want to set only one label for example, you can do so by passing the empty string '' | ||
+ | |||
+ | <code perl> | ||
+ | > simplex(3)-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Tue Mar 29 16:03:37 2022 | ||
+ | unnamed | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <meta charset=utf-8> | ||
+ | < | ||
+ | < | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | */ | ||
+ | html {overflow: scroll;} | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | # | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_END | ||
+ | */ | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | <div id=' | ||
+ | <div class=group id=' | ||
+ | < | ||
+ | < | ||
+ | <div class=indented>< | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | <div class=suboption> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | <div class=suboption> | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | <select id=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <img id=' | ||
+ | <img id=' | ||
+ | <div id=" | ||
+ | </ | ||
+ | < | ||
+ | requirejs.config({ | ||
+ | paths: { | ||
+ | three: '/ | ||
+ | TrackballControls: | ||
+ | OrbitControls: | ||
+ | Projector: '/ | ||
+ | SVGRenderer: | ||
+ | WEBGL: '/ | ||
+ | }, | ||
+ | shim: { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | }); | ||
+ | | ||
+ | require([' | ||
+ | window.THREE = THREE; | ||
+ | require([' | ||
+ | | ||
+ | THREE.TrackballControls = TrackballControls; | ||
+ | THREE.OrbitControls = OrbitControls; | ||
+ | THREE.Projector = Projector; | ||
+ | THREE.SVGRenderer = SVGRenderer; | ||
+ | THREE.WEBGL = WEBGL; | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | |||
+ | const intervalLength = 25; // for automatic animations | ||
+ | const explodableModel = false; | ||
+ | const modelContains = { points: false, pointlabels: | ||
+ | const foldables = []; | ||
+ | |||
+ | var three = document.getElementById(" | ||
+ | var scene = new THREE.Scene(); | ||
+ | var renderer = new THREE.WebGLRenderer( { antialias: true } ); | ||
+ | var svgRenderer = new THREE.SVGRenderer( { antialias: true } ); | ||
+ | renderer.setPixelRatio( window.devicePixelRatio ); | ||
+ | renderer.setClearColor(0xFFFFFF, | ||
+ | svgRenderer.setClearColor(0xFFFFFF, | ||
+ | three.appendChild(renderer.domElement); | ||
+ | |||
+ | var frustumSize = 4; | ||
+ | var cameras = [new THREE.PerspectiveCamera(75, | ||
+ | cameras.forEach(function(cam) { | ||
+ | cam.position.set(0, | ||
+ | cam.lookAt(0, | ||
+ | cam.up.set(0, | ||
+ | }); | ||
+ | var controls = [new THREE.TrackballControls(cameras[0], | ||
+ | var camera, control; | ||
+ | |||
+ | controls[0].zoomSpeed = 0.2; | ||
+ | controls[0].rotateSpeed = 4; | ||
+ | |||
+ | |||
+ | // class to allow move points together with labels and spheres | ||
+ | var PMPoint = function (x,y,z) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addLabel = function(labelsprite) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addSphere = function(spheremesh) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.set = function(x, | ||
+ | | ||
+ | if (this.sprite) { | ||
+ | this.sprite.position.copy(this.vector); | ||
+ | } | ||
+ | if (this.sphere) { | ||
+ | this.sphere.position.copy(this.vector); | ||
+ | } | ||
+ | } | ||
+ | PMPoint.prototype.radius = function() { | ||
+ | if (this.sphere) { | ||
+ | return this.sphere.geometry.parameters.radius; | ||
+ | } else { | ||
+ | return 0; | ||
+ | } | ||
+ | }; | ||
+ | // select the target node | ||
+ | var target = document.querySelector('# | ||
+ | |||
+ | // create an observer instance | ||
+ | var observer = new MutationObserver(function(mutations) { | ||
+ | | ||
+ | if (mutation.removedNodes && mutation.removedNodes.length > 0) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | // configuration of the observer: | ||
+ | var config = { childList: true, characterData: | ||
+ | |||
+ | // pass in the target node, as well as the observer options | ||
+ | while (target) { | ||
+ | if (target.className==" | ||
+ | observer.observe(target, | ||
+ | break; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | var obj0 = new THREE.Object3D(); | ||
+ | obj0.name = " | ||
+ | obj0.userData.explodable = 1; | ||
+ | obj0.userData.points = []; | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 1)); | ||
+ | |||
+ | obj0.userData.pointradii = 0.02; | ||
+ | < | ||
+ | obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | obj0.userData.pointlabels = ["", | ||
+ | obj0.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[2, 3, 1], [0, 3, 2], [1, 3, 0], [2, 1, 0]]; | ||
+ | < | ||
+ | obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj0); | ||
+ | scene.add(obj0); | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | function textSpriteMaterial(message, | ||
+ | if ( parameters === undefined ) parameters = {}; | ||
+ | var fontface = " | ||
+ | var fontsize = parameters.hasOwnProperty(" | ||
+ | fontsize = fontsize*10; | ||
+ | var lines = message.split(' | ||
+ | var size = 512; | ||
+ | for(var i = 0; i< | ||
+ | var tmp = lines[i].length; | ||
+ | while(tmp*fontsize > size){ | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | var canvas = document.createElement(' | ||
+ | canvas.width = size; | ||
+ | canvas.height = size; | ||
+ | var context = canvas.getContext(' | ||
+ | context.fillStyle = " | ||
+ | context.fill(); | ||
+ | context.font = fontsize + "px " + fontface; | ||
+ | | ||
+ | // text color | ||
+ | context.fillStyle = " | ||
+ | | ||
+ | context.fillText(lines[i], | ||
+ | } | ||
+ | | ||
+ | // canvas contents will be used for a texture | ||
+ | var texture = new THREE.Texture(canvas); | ||
+ | texture.needsUpdate = true; | ||
+ | | ||
+ | var spriteMaterial = new THREE.SpriteMaterial({map: | ||
+ | return spriteMaterial; | ||
+ | } | ||
+ | |||
+ | |||
+ | // ---------------------- INITIALIZING OBJECTS-------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function init_object(obj) { | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_points(obj); | ||
+ | modelContains.points = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_pointlabels(obj); | ||
+ | modelContains.pointlabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_lines(obj); | ||
+ | modelContains.lines = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_edgelabels(obj); | ||
+ | modelContains.edgelabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_arrowheads(obj); | ||
+ | modelContains.arrowheads = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_faces(obj); | ||
+ | modelContains.faces = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function init_points(obj) { | ||
+ | var pointgroup = new THREE.Group(); | ||
+ | pointgroup.name = " | ||
+ | var points = obj.userData.points; | ||
+ | var radii = obj.userData.pointradii; | ||
+ | var materials = obj.userData.pointmaterial; | ||
+ | var geometry, | ||
+ | if (!Array.isArray(radii)) { | ||
+ | geometry = new THREE.SphereBufferGeometry(radii); | ||
+ | } | ||
+ | if (!Array.isArray(materials)) { | ||
+ | material = materials; | ||
+ | } | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | if (Array.isArray(radii)) { | ||
+ | if (radii[i] == 0) { | ||
+ | continue; | ||
+ | } | ||
+ | geometry = new THREE.SphereBufferGeometry(radii[i]); | ||
+ | } | ||
+ | if (Array.isArray(materials)) { | ||
+ | material = materials[i]; | ||
+ | } | ||
+ | var sphere = new THREE.Mesh(geometry, | ||
+ | point.addSphere(sphere); | ||
+ | pointgroup.add(sphere); | ||
+ | } | ||
+ | obj.add(pointgroup); | ||
+ | } | ||
+ | |||
+ | function init_pointlabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var labels = obj.userData.pointlabels; | ||
+ | var pointlabels = new THREE.Group(); | ||
+ | pointlabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(pointlabels); | ||
+ | } | ||
+ | |||
+ | function init_lines(obj) { | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var points = obj.userData.points; | ||
+ | var materials = obj.userData.edgematerial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 ); | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | for (var i=0; i< | ||
+ | geometry.addGroup(2*i, | ||
+ | } | ||
+ | } | ||
+ | var lines = new THREE.LineSegments(geometry, | ||
+ | lines.name = " | ||
+ | obj.add(lines); | ||
+ | updateEdgesPosition(obj); | ||
+ | } | ||
+ | |||
+ | function init_edgelabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var labels = obj.userData.edgelabels; | ||
+ | var edgelabels = new THREE.Group(); | ||
+ | edgelabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(edgelabels); | ||
+ | } | ||
+ | |||
+ | function init_arrowheads(obj) { | ||
+ | var arrowheads = new THREE.Group(); | ||
+ | arrowheads.name = " | ||
+ | var arrowstyle = obj.userData.arrowstyle; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var edgematerials = obj.userData.edgematerial; | ||
+ | var points = obj.userData.points; | ||
+ | var material; | ||
+ | if (!Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials.color} ); | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var start = points[edgeindices[i]]; | ||
+ | var end = points[edgeindices[i+1]]; | ||
+ | var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius(); | ||
+ | if (dist <= 0) { | ||
+ | continue; | ||
+ | } | ||
+ | var dir = new THREE.Vector3().subVectors(end.vector, | ||
+ | dir.normalize(); | ||
+ | var axis = new THREE.Vector3().set(dir.z, | ||
+ | axis.normalize(); | ||
+ | var radians = Math.acos( dir.y ); | ||
+ | var radius = dist/25; | ||
+ | var height = dist/5; | ||
+ | var geometry = new THREE.ConeBufferGeometry(radius, | ||
+ | var position = new THREE.Vector3().addVectors(start.vector, | ||
+ | if (Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} ); | ||
+ | } | ||
+ | var cone = new THREE.Mesh( geometry, material ); | ||
+ | cone.quaternion.setFromAxisAngle(axis, | ||
+ | cone.position.copy(position);; | ||
+ | arrowheads.add(cone); | ||
+ | } | ||
+ | obj.add(arrowheads); | ||
+ | } | ||
+ | |||
+ | function init_faces(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var facets = obj.userData.facets; | ||
+ | obj.userData.triangleindices = []; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | for (var t=0; t< | ||
+ | obj.userData.triangleindices.push(facet[0], | ||
+ | } | ||
+ | } | ||
+ | var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute(bufarr, | ||
+ | | ||
+ | var materials = obj.userData.facetmaterial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var frontmaterials = []; | ||
+ | var backmaterials = []; | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | var tricount = 0; | ||
+ | var facet; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | geometry.addGroup(tricount, | ||
+ | tricount += (facet.length-2)*3; | ||
+ | } | ||
+ | for (var j=0; j< | ||
+ | var fmat = materials[j].clone() | ||
+ | fmat.side = THREE.FrontSide; | ||
+ | frontmaterials.push(fmat); | ||
+ | var bmat = materials[j].clone() | ||
+ | bmat.side = THREE.BackSide; | ||
+ | backmaterials.push(bmat); | ||
+ | obj.userData.facetmaterial = frontmaterials.concat(backmaterials); | ||
+ | } | ||
+ | } else if (materials instanceof THREE.Material) { | ||
+ | frontmaterials = materials.clone() | ||
+ | frontmaterials.side = THREE.FrontSide; | ||
+ | backmaterials = materials.clone() | ||
+ | backmaterials.side = THREE.BackSide; | ||
+ | obj.userData.facetmaterial = [frontmaterials, | ||
+ | } | ||
+ | // duplicating the object with front and back should avoid transparency issues | ||
+ | var backmesh = new THREE.Mesh(geometry, | ||
+ | // meshname is used to show/hide objects | ||
+ | backmesh.name = " | ||
+ | obj.add(backmesh); | ||
+ | var frontmesh = new THREE.Mesh(geometry, | ||
+ | frontmesh.name = " | ||
+ | obj.add(frontmesh); | ||
+ | updateFacesPosition(obj); | ||
+ | } | ||
+ | // // | ||
+ | |||
+ | |||
+ | function updateFacesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.triangleindices; | ||
+ | var faces = obj.getObjectByName(" | ||
+ | var ba = faces.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | faces.geometry.attributes.position.needsUpdate = true; | ||
+ | | ||
+ | } | ||
+ | |||
+ | function updateEdgesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.edgeindices; | ||
+ | var lines = obj.getObjectByName(" | ||
+ | var ba = lines.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | lines.geometry.attributes.position.needsUpdate = true; | ||
+ | } | ||
+ | |||
+ | function onWindowResize() { | ||
+ | renderer.setSize( three.clientWidth, | ||
+ | svgRenderer.setSize( three.clientWidth, | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | function updateCamera() { | ||
+ | var width = three.clientWidth; | ||
+ | var height = three.clientHeight; | ||
+ | var aspect = width / height; | ||
+ | if (camera.type == " | ||
+ | camera.left = frustumSize * aspect / - 2; | ||
+ | camera.right = frustumSize * aspect / 2; | ||
+ | camera.top = frustumSize / 2; | ||
+ | camera.bottom = - frustumSize / 2; | ||
+ | } else if (camera.type == " | ||
+ | camera.aspect = aspect; | ||
+ | } | ||
+ | camera.updateProjectionMatrix(); | ||
+ | } | ||
+ | |||
+ | function changeCamera(event) { | ||
+ | var selindex = event.currentTarget.selectedIndex; | ||
+ | camera = cameras[selindex]; | ||
+ | control = controls[selindex]; | ||
+ | control.enabled = true; | ||
+ | for (var i=0; i< | ||
+ | if (i!=selindex) { | ||
+ | controls[i].enabled = false; | ||
+ | } | ||
+ | } | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | var camtypenode = document.getElementById(' | ||
+ | camtypenode.onchange = changeCamera; | ||
+ | camtypenode.dispatchEvent(new Event(' | ||
+ | |||
+ | onWindowResize(); | ||
+ | window.addEventListener(' | ||
+ | |||
+ | |||
+ | var xRotationEnabled = false; | ||
+ | var yRotationEnabled = false; | ||
+ | var zRotationEnabled = false; | ||
+ | var rotationSpeedFactor = 1; | ||
+ | var settingsShown = false; | ||
+ | var labelsShown = true; | ||
+ | var intervals = []; | ||
+ | var timeouts = []; | ||
+ | var explodingSpeed = 0.05; | ||
+ | var explodeScale = 0.000001; | ||
+ | var XMLS = new XMLSerializer(); | ||
+ | var svgElement; | ||
+ | var renderId; | ||
+ | |||
+ | var render = function () { | ||
+ | |||
+ | renderId = requestAnimationFrame(render); | ||
+ | |||
+ | // comment in for automatic explosion | ||
+ | // | ||
+ | |||
+ | var phi = 0.02 * rotationSpeedFactor; | ||
+ | |||
+ | if (xRotationEnabled) { | ||
+ | scene.rotation.x += phi; | ||
+ | } | ||
+ | if (yRotationEnabled) { | ||
+ | scene.rotation.y += phi; | ||
+ | } | ||
+ | if (zRotationEnabled) { | ||
+ | scene.rotation.z += phi; | ||
+ | } | ||
+ | |||
+ | control.update(); | ||
+ | renderer.render(scene, | ||
+ | }; | ||
+ | |||
+ | if ( THREE.WEBGL.isWebGLAvailable() ) { | ||
+ | render(); | ||
+ | } else { | ||
+ | var warning = WEBGL.getWebGLErrorMessage(); | ||
+ | three.appendChild( warning ); | ||
+ | } | ||
+ | | ||
+ | function changeTransparency() { | ||
+ | var opacity = 1-Number(event.currentTarget.value); | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].opacity = opacity; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.opacity = opacity; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleDepthWrite(event) { | ||
+ | depthwrite = event.currentTarget.checked; | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].depthWrite = depthwrite; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.depthWrite = depthWrite; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function changeRotationX(event){ | ||
+ | xRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationY(event){ | ||
+ | yRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationZ(event){ | ||
+ | zRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | |||
+ | function changeRotationSpeedFactor(event){ | ||
+ | rotationSpeedFactor = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function resetScene(){ | ||
+ | scene.rotation.set(0, | ||
+ | camera.position.set(0, | ||
+ | camera.up.set(0, | ||
+ | } | ||
+ | |||
+ | function showSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = true; | ||
+ | } | ||
+ | |||
+ | function hideSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = false; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | var pos = 150* Math.PI; | ||
+ | |||
+ | function updateFactor() { | ||
+ | pos++; | ||
+ | return Math.sin(.01*pos)+1; | ||
+ | } | ||
+ | |||
+ | // ------------------------ FOLDING ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | // rotate point p around axis defined by points p1 and p2 by given angle | ||
+ | function rotate(p, p1, p2, angle ){ | ||
+ | angle = -angle; | ||
+ | var x = p.x, y = p.y, z = p.z, | ||
+ | a = p1.x, b = p1.y, c = p1.z, | ||
+ | u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z; | ||
+ | var result = []; | ||
+ | var L = u*u + v*v + w*w; | ||
+ | var sqrt = Math.sqrt; | ||
+ | var cos = Math.cos; | ||
+ | var sin = Math.sin; | ||
+ | |||
+ | result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/ | ||
+ | result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/ | ||
+ | result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/ | ||
+ | |||
+ | return result; | ||
+ | } | ||
+ | |||
+ | var fold = function(event){ | ||
+ | var obj = foldables[Number(event.currentTarget.name)]; | ||
+ | var foldvalue = Number(event.currentTarget.value); | ||
+ | var scale = foldvalue - obj.userData.oldscale; | ||
+ | |||
+ | for (var j=0; j< | ||
+ | rotateVertices(obj, | ||
+ | } | ||
+ | update(obj); | ||
+ | obj.userData.oldscale += scale; | ||
+ | lookAtBarycenter(obj); | ||
+ | } | ||
+ | |||
+ | function lookAtBarycenter(obj){ | ||
+ | control.target = barycenter(obj); | ||
+ | } | ||
+ | |||
+ | function barycenter(obj) { | ||
+ | var center = new THREE.Vector3(0, | ||
+ | var points = obj.userData.points; | ||
+ | for (var i=0; i< | ||
+ | center.add(points[i].vector); | ||
+ | } | ||
+ | center.divideScalar(points.length); | ||
+ | return center; | ||
+ | } | ||
+ | |||
+ | function rotateVertices(obj, | ||
+ | var axes = obj.userData.axes; | ||
+ | var subtrees = obj.userData.subtrees; | ||
+ | var points = obj.userData.points; | ||
+ | var angles = obj.userData.angles; | ||
+ | if (edge < axes.length){ | ||
+ | for (var j=0; j< | ||
+ | var rotP = rotate(points[subtrees[edge][j]].vector, | ||
+ | points[subtrees[edge][j]].set(rotP[0], | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function update(obj) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | if (foldables.length) { | ||
+ | var settings = document.getElementById(' | ||
+ | var foldDiv = document.createElement(' | ||
+ | foldDiv.id = ' | ||
+ | var title = document.createElement(' | ||
+ | title.innerHTML = ' | ||
+ | foldDiv.appendChild(title); | ||
+ | foldDiv.className = ' | ||
+ | for (var i=0; i< | ||
+ | var range = document.createElement(' | ||
+ | range.type = ' | ||
+ | range.min = 0; | ||
+ | range.max = 1; | ||
+ | range.value = 0; | ||
+ | range.step = 0.001; | ||
+ | range.name = String(i); | ||
+ | range.oninput = fold; | ||
+ | foldDiv.appendChild(range); | ||
+ | } | ||
+ | lookAtBarycenter(foldables[0]); | ||
+ | settings.insertBefore(foldDiv, | ||
+ | } | ||
+ | |||
+ | | ||
+ | // ---------------------- EXPLOSION ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | if (explodableModel) { | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | if ( obj.userData.explodable ) { | ||
+ | computeCentroid(obj); | ||
+ | } | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | explode(0.000001); | ||
+ | } | ||
+ | |||
+ | function computeCentroid(obj) { | ||
+ | centroid = new THREE.Vector3(); | ||
+ | obj.userData.points.forEach(function(pmpoint) { | ||
+ | centroid.add(pmpoint.vector); | ||
+ | }); | ||
+ | centroid.divideScalar(obj.userData.points.length); | ||
+ | obj.userData.centroid = centroid; | ||
+ | } | ||
+ | |||
+ | function explode(factor) { | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i]; | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | var c = obj.userData.centroid; | ||
+ | obj.position.set(c.x*factor, | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function triggerExplode(event){ | ||
+ | explodeScale = Number(event.currentTarget.value); | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | |||
+ | function setExplodingSpeed(event){ | ||
+ | explodingSpeed = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function triggerAutomaticExplode(event){ | ||
+ | if (event.currentTarget.checked){ | ||
+ | startExploding(); | ||
+ | } else { | ||
+ | clearIntervals(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function startExploding(){ | ||
+ | intervals.push(setInterval(explodingInterval, | ||
+ | } | ||
+ | |||
+ | |||
+ | function explodingInterval(){ | ||
+ | explodeScale += explodingSpeed; | ||
+ | if (explodeScale <= 6){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else{ | ||
+ | explode(6); | ||
+ | explodeScale = 6; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startUnexploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | |||
+ | function startUnexploding(){ | ||
+ | intervals.push(setInterval(unexplodingInterval, | ||
+ | } | ||
+ | |||
+ | function unexplodingInterval(){ | ||
+ | explodeScale -= explodingSpeed; | ||
+ | if (explodeScale >= 0){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else { | ||
+ | explode(0); | ||
+ | explodeScale = 0; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startExploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | function clearIntervals(){ | ||
+ | intervals.forEach(function(interval){ | ||
+ | clearInterval(interval); | ||
+ | }); | ||
+ | intervals = []; | ||
+ | timeouts.forEach(function(timeout){ | ||
+ | clearTimeout(timeout); | ||
+ | }); | ||
+ | timeouts = []; | ||
+ | } | ||
+ | |||
+ | // ---------------------- DISPLAY -------------------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | const objectTypeInnerHTMLs = { points: " | ||
+ | const objectTypeVisible = {}; | ||
+ | Object.assign(objectTypeVisible, | ||
+ | const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort(); | ||
+ | const shownObjectTypesList = document.getElementById(' | ||
+ | |||
+ | function setVisibility(bool, | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i].getObjectByName(objname); | ||
+ | if (obj) { | ||
+ | obj.visible = bool; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleObjectTypeVisibility(event){ | ||
+ | var name = event.currentTarget.name; | ||
+ | var checked = event.currentTarget.checked; | ||
+ | objectTypeVisible[name] = checked; | ||
+ | if (name == " | ||
+ | setVisibility(checked," | ||
+ | setVisibility(checked," | ||
+ | } else { | ||
+ | setVisibility(checked, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var key = sortedObjectTypeKeys[i]; | ||
+ | if (modelContains[key]) { | ||
+ | var objTypeNode = document.createElement(' | ||
+ | objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = key; | ||
+ | checkbox.onchange = toggleObjectTypeVisibility; | ||
+ | shownObjectTypesList.appendChild(checkbox); | ||
+ | shownObjectTypesList.appendChild(objTypeNode); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // ------------------------------------------------------ | ||
+ | |||
+ | function toggleObjectVisibility(event){ | ||
+ | var nr = Number(event.currentTarget.name); | ||
+ | scene.children[nr].visible = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | // append checkboxes for displaying or hiding objects | ||
+ | var shownObjectsList = document.getElementById(' | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | var objNode = document.createElement(' | ||
+ | objNode.innerHTML = obj.name + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = String(i); | ||
+ | checkbox.onchange = toggleObjectVisibility; | ||
+ | shownObjectsList.appendChild(checkbox); | ||
+ | shownObjectsList.appendChild(objNode); | ||
+ | } | ||
+ | |||
+ | // ---------------------- SVG ------------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function takeSvgScreenshot() { | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | svgRenderer.render(scene, | ||
+ | svgElement = XMLS.serializeToString(svgRenderer.domElement); | ||
+ | | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | |||
+ | if (document.getElementById(' | ||
+ | //show in new tab | ||
+ | var myWindow = window.open("","" | ||
+ | myWindow.document.body.innerHTML = svgElement; | ||
+ | } else{ | ||
+ | // download svg file | ||
+ | download(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function download(filename, | ||
+ | var element = document.createElement(' | ||
+ | element.setAttribute(' | ||
+ | element.setAttribute(' | ||
+ | |||
+ | element.style.display = ' | ||
+ | document.body.appendChild(element); | ||
+ | |||
+ | element.click(); | ||
+ | |||
+ | document.body.removeChild(element); | ||
+ | } | ||
+ | |||
+ | |||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | |||
+ | |||
+ | // ------------------ SHORTCUTS -------------------------------------------- | ||
+ | // ------------------------------------------------------------------------- | ||
+ | |||
+ | /** | ||
+ | * http:// | ||
+ | * Version : 2.01.B | ||
+ | * By Binny V A | ||
+ | * License : BSD | ||
+ | */ | ||
+ | shortcut = { | ||
+ | ' | ||
+ | ' | ||
+ | //Provide a set of default options | ||
+ | var default_options = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | if(!opt) opt = default_options; | ||
+ | else { | ||
+ | for(var dfo in default_options) { | ||
+ | if(typeof opt[dfo] == ' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var ele = opt.target; | ||
+ | if(typeof opt.target == ' | ||
+ | var ths = this; | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | |||
+ | //The function to be called at keypress | ||
+ | var func = function(e) { | ||
+ | e = e || window.event; | ||
+ | |||
+ | if(opt[' | ||
+ | var element; | ||
+ | if(e.target) element=e.target; | ||
+ | else if(e.srcElement) element=e.srcElement; | ||
+ | if(element.nodeType==3) element=element.parentNode; | ||
+ | |||
+ | if(element.tagName == ' | ||
+ | } | ||
+ | |||
+ | //Find Which key is pressed | ||
+ | if (e.keyCode) code = e.keyCode; | ||
+ | else if (e.which) code = e.which; | ||
+ | var character = String.fromCharCode(code).toLowerCase(); | ||
+ | |||
+ | if(code == 188) character=","; | ||
+ | if(code == 190) character=" | ||
+ | |||
+ | var keys = shortcut_combination.split(" | ||
+ | //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked | ||
+ | var kp = 0; | ||
+ | |||
+ | //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken | ||
+ | var shift_nums = { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | ";":":", | ||
+ | "'":" | ||
+ | ",":"<", | ||
+ | " | ||
+ | "/":"?", | ||
+ | " | ||
+ | } | ||
+ | // | ||
+ | var special_keys = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | |||
+ | var modifiers = { | ||
+ | shift: { wanted: | ||
+ | ctrl : { wanted: | ||
+ | alt | ||
+ | meta : { wanted: | ||
+ | }; | ||
+ | | ||
+ | if(e.ctrlKey) modifiers.ctrl.pressed = true; | ||
+ | if(e.shiftKey) modifiers.shift.pressed = true; | ||
+ | if(e.altKey) modifiers.alt.pressed = true; | ||
+ | if(e.metaKey) | ||
+ | | ||
+ | for(var i=0; k=keys[i], | ||
+ | // | ||
+ | if(k == ' | ||
+ | kp++; | ||
+ | modifiers.ctrl.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.shift.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.alt.wanted = true; | ||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.meta.wanted = true; | ||
+ | } else if(k.length > 1) { //If it is a special key | ||
+ | if(special_keys[k] == code) kp++; | ||
+ | |||
+ | } else if(opt[' | ||
+ | if(opt[' | ||
+ | |||
+ | } else { //The special keys did not match | ||
+ | if(character == k) kp++; | ||
+ | else { | ||
+ | if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase | ||
+ | character = shift_nums[character]; | ||
+ | if(character == k) kp++; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if(kp == keys.length && | ||
+ | modifiers.ctrl.pressed == modifiers.ctrl.wanted && | ||
+ | modifiers.shift.pressed == modifiers.shift.wanted && | ||
+ | modifiers.alt.pressed == modifiers.alt.wanted && | ||
+ | modifiers.meta.pressed == modifiers.meta.wanted) { | ||
+ | callback(e); | ||
+ | |||
+ | if(!opt[' | ||
+ | // | ||
+ | e.cancelBubble = true; | ||
+ | e.returnValue = false; | ||
+ | |||
+ | // | ||
+ | if (e.stopPropagation) { | ||
+ | e.stopPropagation(); | ||
+ | e.preventDefault(); | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | this.all_shortcuts[shortcut_combination] = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }; | ||
+ | //Attach the function with the event | ||
+ | if(ele.addEventListener) ele.addEventListener(opt[' | ||
+ | else if(ele.attachEvent) ele.attachEvent(' | ||
+ | else ele[' | ||
+ | }, | ||
+ | |||
+ | //Remove the shortcut - just specify the shortcut and I will remove the binding | ||
+ | ' | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | var binding = this.all_shortcuts[shortcut_combination]; | ||
+ | delete(this.all_shortcuts[shortcut_combination]) | ||
+ | if(!binding) return; | ||
+ | var type = binding[' | ||
+ | var ele = binding[' | ||
+ | var callback = binding[' | ||
+ | |||
+ | if(ele.detachEvent) ele.detachEvent(' | ||
+ | else if(ele.removeEventListener) ele.removeEventListener(type, | ||
+ | else ele[' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | shortcut.add(" | ||
+ | var event = new Event(' | ||
+ | if (settingsShown){ | ||
+ | document.getElementById(' | ||
+ | } else { | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | **Function**: | ||
+ | |||
+ | <code perl> | ||
+ | > $tet = simplex(3); | ||
+ | > $tet-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Tue Mar 29 16:03:37 2022 | ||
+ | tet | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <meta charset=utf-8> | ||
+ | < | ||
+ | < | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | */ | ||
+ | html {overflow: scroll;} | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | # | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_END | ||
+ | */ | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | <div id=' | ||
+ | <div class=group id=' | ||
+ | < | ||
+ | < | ||
+ | <div class=indented>< | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | <div class=suboption> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | <div class=suboption> | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | <select id=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <img id=' | ||
+ | <img id=' | ||
+ | <div id=" | ||
+ | </ | ||
+ | < | ||
+ | requirejs.config({ | ||
+ | paths: { | ||
+ | three: '/ | ||
+ | TrackballControls: | ||
+ | OrbitControls: | ||
+ | Projector: '/ | ||
+ | SVGRenderer: | ||
+ | WEBGL: '/ | ||
+ | }, | ||
+ | shim: { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | }); | ||
+ | | ||
+ | require([' | ||
+ | window.THREE = THREE; | ||
+ | require([' | ||
+ | | ||
+ | THREE.TrackballControls = TrackballControls; | ||
+ | THREE.OrbitControls = OrbitControls; | ||
+ | THREE.Projector = Projector; | ||
+ | THREE.SVGRenderer = SVGRenderer; | ||
+ | THREE.WEBGL = WEBGL; | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | |||
+ | const intervalLength = 25; // for automatic animations | ||
+ | const explodableModel = false; | ||
+ | const modelContains = { points: false, pointlabels: | ||
+ | const foldables = []; | ||
+ | |||
+ | var three = document.getElementById(" | ||
+ | var scene = new THREE.Scene(); | ||
+ | var renderer = new THREE.WebGLRenderer( { antialias: true } ); | ||
+ | var svgRenderer = new THREE.SVGRenderer( { antialias: true } ); | ||
+ | renderer.setPixelRatio( window.devicePixelRatio ); | ||
+ | renderer.setClearColor(0xFFFFFF, | ||
+ | svgRenderer.setClearColor(0xFFFFFF, | ||
+ | three.appendChild(renderer.domElement); | ||
+ | |||
+ | var frustumSize = 4; | ||
+ | var cameras = [new THREE.PerspectiveCamera(75, | ||
+ | cameras.forEach(function(cam) { | ||
+ | cam.position.set(0, | ||
+ | cam.lookAt(0, | ||
+ | cam.up.set(0, | ||
+ | }); | ||
+ | var controls = [new THREE.TrackballControls(cameras[0], | ||
+ | var camera, control; | ||
+ | |||
+ | controls[0].zoomSpeed = 0.2; | ||
+ | controls[0].rotateSpeed = 4; | ||
+ | |||
+ | |||
+ | // class to allow move points together with labels and spheres | ||
+ | var PMPoint = function (x,y,z) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addLabel = function(labelsprite) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addSphere = function(spheremesh) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.set = function(x, | ||
+ | | ||
+ | if (this.sprite) { | ||
+ | this.sprite.position.copy(this.vector); | ||
+ | } | ||
+ | if (this.sphere) { | ||
+ | this.sphere.position.copy(this.vector); | ||
+ | } | ||
+ | } | ||
+ | PMPoint.prototype.radius = function() { | ||
+ | if (this.sphere) { | ||
+ | return this.sphere.geometry.parameters.radius; | ||
+ | } else { | ||
+ | return 0; | ||
+ | } | ||
+ | }; | ||
+ | // select the target node | ||
+ | var target = document.querySelector('# | ||
+ | |||
+ | // create an observer instance | ||
+ | var observer = new MutationObserver(function(mutations) { | ||
+ | | ||
+ | if (mutation.removedNodes && mutation.removedNodes.length > 0) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | // configuration of the observer: | ||
+ | var config = { childList: true, characterData: | ||
+ | |||
+ | // pass in the target node, as well as the observer options | ||
+ | while (target) { | ||
+ | if (target.className==" | ||
+ | observer.observe(target, | ||
+ | break; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | var obj0 = new THREE.Object3D(); | ||
+ | obj0.name = " | ||
+ | obj0.userData.explodable = 1; | ||
+ | obj0.userData.points = []; | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 1)); | ||
+ | |||
+ | obj0.userData.pointradii = 0.02; | ||
+ | < | ||
+ | obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | obj0.userData.pointlabels = ["(4) (0 1)", "1 1 0 0", "1 0 1 0", "1 0 0 1"]; | ||
+ | obj0.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[2, 3, 1], [0, 3, 2], [1, 3, 0], [2, 1, 0]]; | ||
+ | < | ||
+ | obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj0); | ||
+ | scene.add(obj0); | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | function textSpriteMaterial(message, | ||
+ | if ( parameters === undefined ) parameters = {}; | ||
+ | var fontface = " | ||
+ | var fontsize = parameters.hasOwnProperty(" | ||
+ | fontsize = fontsize*10; | ||
+ | var lines = message.split(' | ||
+ | var size = 512; | ||
+ | for(var i = 0; i< | ||
+ | var tmp = lines[i].length; | ||
+ | while(tmp*fontsize > size){ | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | var canvas = document.createElement(' | ||
+ | canvas.width = size; | ||
+ | canvas.height = size; | ||
+ | var context = canvas.getContext(' | ||
+ | context.fillStyle = " | ||
+ | context.fill(); | ||
+ | context.font = fontsize + "px " + fontface; | ||
+ | | ||
+ | // text color | ||
+ | context.fillStyle = " | ||
+ | | ||
+ | context.fillText(lines[i], | ||
+ | } | ||
+ | | ||
+ | // canvas contents will be used for a texture | ||
+ | var texture = new THREE.Texture(canvas); | ||
+ | texture.needsUpdate = true; | ||
+ | | ||
+ | var spriteMaterial = new THREE.SpriteMaterial({map: | ||
+ | return spriteMaterial; | ||
+ | } | ||
+ | |||
+ | |||
+ | // ---------------------- INITIALIZING OBJECTS-------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function init_object(obj) { | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_points(obj); | ||
+ | modelContains.points = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_pointlabels(obj); | ||
+ | modelContains.pointlabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_lines(obj); | ||
+ | modelContains.lines = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_edgelabels(obj); | ||
+ | modelContains.edgelabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_arrowheads(obj); | ||
+ | modelContains.arrowheads = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_faces(obj); | ||
+ | modelContains.faces = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function init_points(obj) { | ||
+ | var pointgroup = new THREE.Group(); | ||
+ | pointgroup.name = " | ||
+ | var points = obj.userData.points; | ||
+ | var radii = obj.userData.pointradii; | ||
+ | var materials = obj.userData.pointmaterial; | ||
+ | var geometry, | ||
+ | if (!Array.isArray(radii)) { | ||
+ | geometry = new THREE.SphereBufferGeometry(radii); | ||
+ | } | ||
+ | if (!Array.isArray(materials)) { | ||
+ | material = materials; | ||
+ | } | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | if (Array.isArray(radii)) { | ||
+ | if (radii[i] == 0) { | ||
+ | continue; | ||
+ | } | ||
+ | geometry = new THREE.SphereBufferGeometry(radii[i]); | ||
+ | } | ||
+ | if (Array.isArray(materials)) { | ||
+ | material = materials[i]; | ||
+ | } | ||
+ | var sphere = new THREE.Mesh(geometry, | ||
+ | point.addSphere(sphere); | ||
+ | pointgroup.add(sphere); | ||
+ | } | ||
+ | obj.add(pointgroup); | ||
+ | } | ||
+ | |||
+ | function init_pointlabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var labels = obj.userData.pointlabels; | ||
+ | var pointlabels = new THREE.Group(); | ||
+ | pointlabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(pointlabels); | ||
+ | } | ||
+ | |||
+ | function init_lines(obj) { | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var points = obj.userData.points; | ||
+ | var materials = obj.userData.edgematerial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 ); | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | for (var i=0; i< | ||
+ | geometry.addGroup(2*i, | ||
+ | } | ||
+ | } | ||
+ | var lines = new THREE.LineSegments(geometry, | ||
+ | lines.name = " | ||
+ | obj.add(lines); | ||
+ | updateEdgesPosition(obj); | ||
+ | } | ||
+ | |||
+ | function init_edgelabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var labels = obj.userData.edgelabels; | ||
+ | var edgelabels = new THREE.Group(); | ||
+ | edgelabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(edgelabels); | ||
+ | } | ||
+ | |||
+ | function init_arrowheads(obj) { | ||
+ | var arrowheads = new THREE.Group(); | ||
+ | arrowheads.name = " | ||
+ | var arrowstyle = obj.userData.arrowstyle; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var edgematerials = obj.userData.edgematerial; | ||
+ | var points = obj.userData.points; | ||
+ | var material; | ||
+ | if (!Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials.color} ); | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var start = points[edgeindices[i]]; | ||
+ | var end = points[edgeindices[i+1]]; | ||
+ | var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius(); | ||
+ | if (dist <= 0) { | ||
+ | continue; | ||
+ | } | ||
+ | var dir = new THREE.Vector3().subVectors(end.vector, | ||
+ | dir.normalize(); | ||
+ | var axis = new THREE.Vector3().set(dir.z, | ||
+ | axis.normalize(); | ||
+ | var radians = Math.acos( dir.y ); | ||
+ | var radius = dist/25; | ||
+ | var height = dist/5; | ||
+ | var geometry = new THREE.ConeBufferGeometry(radius, | ||
+ | var position = new THREE.Vector3().addVectors(start.vector, | ||
+ | if (Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} ); | ||
+ | } | ||
+ | var cone = new THREE.Mesh( geometry, material ); | ||
+ | cone.quaternion.setFromAxisAngle(axis, | ||
+ | cone.position.copy(position);; | ||
+ | arrowheads.add(cone); | ||
+ | } | ||
+ | obj.add(arrowheads); | ||
+ | } | ||
+ | |||
+ | function init_faces(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var facets = obj.userData.facets; | ||
+ | obj.userData.triangleindices = []; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | for (var t=0; t< | ||
+ | obj.userData.triangleindices.push(facet[0], | ||
+ | } | ||
+ | } | ||
+ | var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute(bufarr, | ||
+ | | ||
+ | var materials = obj.userData.facetmaterial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var frontmaterials = []; | ||
+ | var backmaterials = []; | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | var tricount = 0; | ||
+ | var facet; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | geometry.addGroup(tricount, | ||
+ | tricount += (facet.length-2)*3; | ||
+ | } | ||
+ | for (var j=0; j< | ||
+ | var fmat = materials[j].clone() | ||
+ | fmat.side = THREE.FrontSide; | ||
+ | frontmaterials.push(fmat); | ||
+ | var bmat = materials[j].clone() | ||
+ | bmat.side = THREE.BackSide; | ||
+ | backmaterials.push(bmat); | ||
+ | obj.userData.facetmaterial = frontmaterials.concat(backmaterials); | ||
+ | } | ||
+ | } else if (materials instanceof THREE.Material) { | ||
+ | frontmaterials = materials.clone() | ||
+ | frontmaterials.side = THREE.FrontSide; | ||
+ | backmaterials = materials.clone() | ||
+ | backmaterials.side = THREE.BackSide; | ||
+ | obj.userData.facetmaterial = [frontmaterials, | ||
+ | } | ||
+ | // duplicating the object with front and back should avoid transparency issues | ||
+ | var backmesh = new THREE.Mesh(geometry, | ||
+ | // meshname is used to show/hide objects | ||
+ | backmesh.name = " | ||
+ | obj.add(backmesh); | ||
+ | var frontmesh = new THREE.Mesh(geometry, | ||
+ | frontmesh.name = " | ||
+ | obj.add(frontmesh); | ||
+ | updateFacesPosition(obj); | ||
+ | } | ||
+ | // // | ||
+ | |||
+ | |||
+ | function updateFacesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.triangleindices; | ||
+ | var faces = obj.getObjectByName(" | ||
+ | var ba = faces.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | faces.geometry.attributes.position.needsUpdate = true; | ||
+ | | ||
+ | } | ||
+ | |||
+ | function updateEdgesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.edgeindices; | ||
+ | var lines = obj.getObjectByName(" | ||
+ | var ba = lines.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | lines.geometry.attributes.position.needsUpdate = true; | ||
+ | } | ||
+ | |||
+ | function onWindowResize() { | ||
+ | renderer.setSize( three.clientWidth, | ||
+ | svgRenderer.setSize( three.clientWidth, | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | function updateCamera() { | ||
+ | var width = three.clientWidth; | ||
+ | var height = three.clientHeight; | ||
+ | var aspect = width / height; | ||
+ | if (camera.type == " | ||
+ | camera.left = frustumSize * aspect / - 2; | ||
+ | camera.right = frustumSize * aspect / 2; | ||
+ | camera.top = frustumSize / 2; | ||
+ | camera.bottom = - frustumSize / 2; | ||
+ | } else if (camera.type == " | ||
+ | camera.aspect = aspect; | ||
+ | } | ||
+ | camera.updateProjectionMatrix(); | ||
+ | } | ||
+ | |||
+ | function changeCamera(event) { | ||
+ | var selindex = event.currentTarget.selectedIndex; | ||
+ | camera = cameras[selindex]; | ||
+ | control = controls[selindex]; | ||
+ | control.enabled = true; | ||
+ | for (var i=0; i< | ||
+ | if (i!=selindex) { | ||
+ | controls[i].enabled = false; | ||
+ | } | ||
+ | } | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | var camtypenode = document.getElementById(' | ||
+ | camtypenode.onchange = changeCamera; | ||
+ | camtypenode.dispatchEvent(new Event(' | ||
+ | |||
+ | onWindowResize(); | ||
+ | window.addEventListener(' | ||
+ | |||
+ | |||
+ | var xRotationEnabled = false; | ||
+ | var yRotationEnabled = false; | ||
+ | var zRotationEnabled = false; | ||
+ | var rotationSpeedFactor = 1; | ||
+ | var settingsShown = false; | ||
+ | var labelsShown = true; | ||
+ | var intervals = []; | ||
+ | var timeouts = []; | ||
+ | var explodingSpeed = 0.05; | ||
+ | var explodeScale = 0.000001; | ||
+ | var XMLS = new XMLSerializer(); | ||
+ | var svgElement; | ||
+ | var renderId; | ||
+ | |||
+ | var render = function () { | ||
+ | |||
+ | renderId = requestAnimationFrame(render); | ||
+ | |||
+ | // comment in for automatic explosion | ||
+ | // | ||
+ | |||
+ | var phi = 0.02 * rotationSpeedFactor; | ||
+ | |||
+ | if (xRotationEnabled) { | ||
+ | scene.rotation.x += phi; | ||
+ | } | ||
+ | if (yRotationEnabled) { | ||
+ | scene.rotation.y += phi; | ||
+ | } | ||
+ | if (zRotationEnabled) { | ||
+ | scene.rotation.z += phi; | ||
+ | } | ||
+ | |||
+ | control.update(); | ||
+ | renderer.render(scene, | ||
+ | }; | ||
+ | |||
+ | if ( THREE.WEBGL.isWebGLAvailable() ) { | ||
+ | render(); | ||
+ | } else { | ||
+ | var warning = WEBGL.getWebGLErrorMessage(); | ||
+ | three.appendChild( warning ); | ||
+ | } | ||
+ | | ||
+ | function changeTransparency() { | ||
+ | var opacity = 1-Number(event.currentTarget.value); | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].opacity = opacity; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.opacity = opacity; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleDepthWrite(event) { | ||
+ | depthwrite = event.currentTarget.checked; | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].depthWrite = depthwrite; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.depthWrite = depthWrite; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function changeRotationX(event){ | ||
+ | xRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationY(event){ | ||
+ | yRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationZ(event){ | ||
+ | zRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | |||
+ | function changeRotationSpeedFactor(event){ | ||
+ | rotationSpeedFactor = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function resetScene(){ | ||
+ | scene.rotation.set(0, | ||
+ | camera.position.set(0, | ||
+ | camera.up.set(0, | ||
+ | } | ||
+ | |||
+ | function showSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = true; | ||
+ | } | ||
+ | |||
+ | function hideSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = false; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | var pos = 150* Math.PI; | ||
+ | |||
+ | function updateFactor() { | ||
+ | pos++; | ||
+ | return Math.sin(.01*pos)+1; | ||
+ | } | ||
+ | |||
+ | // ------------------------ FOLDING ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | // rotate point p around axis defined by points p1 and p2 by given angle | ||
+ | function rotate(p, p1, p2, angle ){ | ||
+ | angle = -angle; | ||
+ | var x = p.x, y = p.y, z = p.z, | ||
+ | a = p1.x, b = p1.y, c = p1.z, | ||
+ | u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z; | ||
+ | var result = []; | ||
+ | var L = u*u + v*v + w*w; | ||
+ | var sqrt = Math.sqrt; | ||
+ | var cos = Math.cos; | ||
+ | var sin = Math.sin; | ||
+ | |||
+ | result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/ | ||
+ | result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/ | ||
+ | result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/ | ||
+ | |||
+ | return result; | ||
+ | } | ||
+ | |||
+ | var fold = function(event){ | ||
+ | var obj = foldables[Number(event.currentTarget.name)]; | ||
+ | var foldvalue = Number(event.currentTarget.value); | ||
+ | var scale = foldvalue - obj.userData.oldscale; | ||
+ | |||
+ | for (var j=0; j< | ||
+ | rotateVertices(obj, | ||
+ | } | ||
+ | update(obj); | ||
+ | obj.userData.oldscale += scale; | ||
+ | lookAtBarycenter(obj); | ||
+ | } | ||
+ | |||
+ | function lookAtBarycenter(obj){ | ||
+ | control.target = barycenter(obj); | ||
+ | } | ||
+ | |||
+ | function barycenter(obj) { | ||
+ | var center = new THREE.Vector3(0, | ||
+ | var points = obj.userData.points; | ||
+ | for (var i=0; i< | ||
+ | center.add(points[i].vector); | ||
+ | } | ||
+ | center.divideScalar(points.length); | ||
+ | return center; | ||
+ | } | ||
+ | |||
+ | function rotateVertices(obj, | ||
+ | var axes = obj.userData.axes; | ||
+ | var subtrees = obj.userData.subtrees; | ||
+ | var points = obj.userData.points; | ||
+ | var angles = obj.userData.angles; | ||
+ | if (edge < axes.length){ | ||
+ | for (var j=0; j< | ||
+ | var rotP = rotate(points[subtrees[edge][j]].vector, | ||
+ | points[subtrees[edge][j]].set(rotP[0], | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function update(obj) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | if (foldables.length) { | ||
+ | var settings = document.getElementById(' | ||
+ | var foldDiv = document.createElement(' | ||
+ | foldDiv.id = ' | ||
+ | var title = document.createElement(' | ||
+ | title.innerHTML = ' | ||
+ | foldDiv.appendChild(title); | ||
+ | foldDiv.className = ' | ||
+ | for (var i=0; i< | ||
+ | var range = document.createElement(' | ||
+ | range.type = ' | ||
+ | range.min = 0; | ||
+ | range.max = 1; | ||
+ | range.value = 0; | ||
+ | range.step = 0.001; | ||
+ | range.name = String(i); | ||
+ | range.oninput = fold; | ||
+ | foldDiv.appendChild(range); | ||
+ | } | ||
+ | lookAtBarycenter(foldables[0]); | ||
+ | settings.insertBefore(foldDiv, | ||
+ | } | ||
+ | |||
+ | | ||
+ | // ---------------------- EXPLOSION ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | if (explodableModel) { | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | if ( obj.userData.explodable ) { | ||
+ | computeCentroid(obj); | ||
+ | } | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | explode(0.000001); | ||
+ | } | ||
+ | |||
+ | function computeCentroid(obj) { | ||
+ | centroid = new THREE.Vector3(); | ||
+ | obj.userData.points.forEach(function(pmpoint) { | ||
+ | centroid.add(pmpoint.vector); | ||
+ | }); | ||
+ | centroid.divideScalar(obj.userData.points.length); | ||
+ | obj.userData.centroid = centroid; | ||
+ | } | ||
+ | |||
+ | function explode(factor) { | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i]; | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | var c = obj.userData.centroid; | ||
+ | obj.position.set(c.x*factor, | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function triggerExplode(event){ | ||
+ | explodeScale = Number(event.currentTarget.value); | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | |||
+ | function setExplodingSpeed(event){ | ||
+ | explodingSpeed = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function triggerAutomaticExplode(event){ | ||
+ | if (event.currentTarget.checked){ | ||
+ | startExploding(); | ||
+ | } else { | ||
+ | clearIntervals(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function startExploding(){ | ||
+ | intervals.push(setInterval(explodingInterval, | ||
+ | } | ||
+ | |||
+ | |||
+ | function explodingInterval(){ | ||
+ | explodeScale += explodingSpeed; | ||
+ | if (explodeScale <= 6){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else{ | ||
+ | explode(6); | ||
+ | explodeScale = 6; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startUnexploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | |||
+ | function startUnexploding(){ | ||
+ | intervals.push(setInterval(unexplodingInterval, | ||
+ | } | ||
+ | |||
+ | function unexplodingInterval(){ | ||
+ | explodeScale -= explodingSpeed; | ||
+ | if (explodeScale >= 0){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else { | ||
+ | explode(0); | ||
+ | explodeScale = 0; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startExploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | function clearIntervals(){ | ||
+ | intervals.forEach(function(interval){ | ||
+ | clearInterval(interval); | ||
+ | }); | ||
+ | intervals = []; | ||
+ | timeouts.forEach(function(timeout){ | ||
+ | clearTimeout(timeout); | ||
+ | }); | ||
+ | timeouts = []; | ||
+ | } | ||
+ | |||
+ | // ---------------------- DISPLAY -------------------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | const objectTypeInnerHTMLs = { points: " | ||
+ | const objectTypeVisible = {}; | ||
+ | Object.assign(objectTypeVisible, | ||
+ | const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort(); | ||
+ | const shownObjectTypesList = document.getElementById(' | ||
+ | |||
+ | function setVisibility(bool, | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i].getObjectByName(objname); | ||
+ | if (obj) { | ||
+ | obj.visible = bool; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleObjectTypeVisibility(event){ | ||
+ | var name = event.currentTarget.name; | ||
+ | var checked = event.currentTarget.checked; | ||
+ | objectTypeVisible[name] = checked; | ||
+ | if (name == " | ||
+ | setVisibility(checked," | ||
+ | setVisibility(checked," | ||
+ | } else { | ||
+ | setVisibility(checked, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var key = sortedObjectTypeKeys[i]; | ||
+ | if (modelContains[key]) { | ||
+ | var objTypeNode = document.createElement(' | ||
+ | objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = key; | ||
+ | checkbox.onchange = toggleObjectTypeVisibility; | ||
+ | shownObjectTypesList.appendChild(checkbox); | ||
+ | shownObjectTypesList.appendChild(objTypeNode); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // ------------------------------------------------------ | ||
+ | |||
+ | function toggleObjectVisibility(event){ | ||
+ | var nr = Number(event.currentTarget.name); | ||
+ | scene.children[nr].visible = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | // append checkboxes for displaying or hiding objects | ||
+ | var shownObjectsList = document.getElementById(' | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | var objNode = document.createElement(' | ||
+ | objNode.innerHTML = obj.name + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = String(i); | ||
+ | checkbox.onchange = toggleObjectVisibility; | ||
+ | shownObjectsList.appendChild(checkbox); | ||
+ | shownObjectsList.appendChild(objNode); | ||
+ | } | ||
+ | |||
+ | // ---------------------- SVG ------------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function takeSvgScreenshot() { | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | svgRenderer.render(scene, | ||
+ | svgElement = XMLS.serializeToString(svgRenderer.domElement); | ||
+ | | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | |||
+ | if (document.getElementById(' | ||
+ | //show in new tab | ||
+ | var myWindow = window.open("","" | ||
+ | myWindow.document.body.innerHTML = svgElement; | ||
+ | } else{ | ||
+ | // download svg file | ||
+ | download(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function download(filename, | ||
+ | var element = document.createElement(' | ||
+ | element.setAttribute(' | ||
+ | element.setAttribute(' | ||
+ | |||
+ | element.style.display = ' | ||
+ | document.body.appendChild(element); | ||
+ | |||
+ | element.click(); | ||
+ | |||
+ | document.body.removeChild(element); | ||
+ | } | ||
+ | |||
+ | |||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | |||
+ | |||
+ | // ------------------ SHORTCUTS -------------------------------------------- | ||
+ | // ------------------------------------------------------------------------- | ||
+ | |||
+ | /** | ||
+ | * http:// | ||
+ | * Version : 2.01.B | ||
+ | * By Binny V A | ||
+ | * License : BSD | ||
+ | */ | ||
+ | shortcut = { | ||
+ | ' | ||
+ | ' | ||
+ | //Provide a set of default options | ||
+ | var default_options = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | if(!opt) opt = default_options; | ||
+ | else { | ||
+ | for(var dfo in default_options) { | ||
+ | if(typeof opt[dfo] == ' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var ele = opt.target; | ||
+ | if(typeof opt.target == ' | ||
+ | var ths = this; | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | |||
+ | //The function to be called at keypress | ||
+ | var func = function(e) { | ||
+ | e = e || window.event; | ||
+ | |||
+ | if(opt[' | ||
+ | var element; | ||
+ | if(e.target) element=e.target; | ||
+ | else if(e.srcElement) element=e.srcElement; | ||
+ | if(element.nodeType==3) element=element.parentNode; | ||
+ | |||
+ | if(element.tagName == ' | ||
+ | } | ||
+ | |||
+ | //Find Which key is pressed | ||
+ | if (e.keyCode) code = e.keyCode; | ||
+ | else if (e.which) code = e.which; | ||
+ | var character = String.fromCharCode(code).toLowerCase(); | ||
+ | |||
+ | if(code == 188) character=","; | ||
+ | if(code == 190) character=" | ||
+ | |||
+ | var keys = shortcut_combination.split(" | ||
+ | //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked | ||
+ | var kp = 0; | ||
+ | |||
+ | //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken | ||
+ | var shift_nums = { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | ";":":", | ||
+ | "'":" | ||
+ | ",":"<", | ||
+ | " | ||
+ | "/":"?", | ||
+ | " | ||
+ | } | ||
+ | // | ||
+ | var special_keys = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | |||
+ | var modifiers = { | ||
+ | shift: { wanted: | ||
+ | ctrl : { wanted: | ||
+ | alt | ||
+ | meta : { wanted: | ||
+ | }; | ||
+ | | ||
+ | if(e.ctrlKey) modifiers.ctrl.pressed = true; | ||
+ | if(e.shiftKey) modifiers.shift.pressed = true; | ||
+ | if(e.altKey) modifiers.alt.pressed = true; | ||
+ | if(e.metaKey) | ||
+ | | ||
+ | for(var i=0; k=keys[i], | ||
+ | // | ||
+ | if(k == ' | ||
+ | kp++; | ||
+ | modifiers.ctrl.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.shift.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.alt.wanted = true; | ||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.meta.wanted = true; | ||
+ | } else if(k.length > 1) { //If it is a special key | ||
+ | if(special_keys[k] == code) kp++; | ||
+ | |||
+ | } else if(opt[' | ||
+ | if(opt[' | ||
+ | |||
+ | } else { //The special keys did not match | ||
+ | if(character == k) kp++; | ||
+ | else { | ||
+ | if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase | ||
+ | character = shift_nums[character]; | ||
+ | if(character == k) kp++; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if(kp == keys.length && | ||
+ | modifiers.ctrl.pressed == modifiers.ctrl.wanted && | ||
+ | modifiers.shift.pressed == modifiers.shift.wanted && | ||
+ | modifiers.alt.pressed == modifiers.alt.wanted && | ||
+ | modifiers.meta.pressed == modifiers.meta.wanted) { | ||
+ | callback(e); | ||
+ | |||
+ | if(!opt[' | ||
+ | // | ||
+ | e.cancelBubble = true; | ||
+ | e.returnValue = false; | ||
+ | |||
+ | // | ||
+ | if (e.stopPropagation) { | ||
+ | e.stopPropagation(); | ||
+ | e.preventDefault(); | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | this.all_shortcuts[shortcut_combination] = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }; | ||
+ | //Attach the function with the event | ||
+ | if(ele.addEventListener) ele.addEventListener(opt[' | ||
+ | else if(ele.attachEvent) ele.attachEvent(' | ||
+ | else ele[' | ||
+ | }, | ||
+ | |||
+ | //Remove the shortcut - just specify the shortcut and I will remove the binding | ||
+ | ' | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | var binding = this.all_shortcuts[shortcut_combination]; | ||
+ | delete(this.all_shortcuts[shortcut_combination]) | ||
+ | if(!binding) return; | ||
+ | var type = binding[' | ||
+ | var ele = binding[' | ||
+ | var callback = binding[' | ||
+ | |||
+ | if(ele.detachEvent) ele.detachEvent(' | ||
+ | else if(ele.removeEventListener) ele.removeEventListener(type, | ||
+ | else ele[' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | shortcut.add(" | ||
+ | var event = new Event(' | ||
+ | if (settingsShown){ | ||
+ | document.getElementById(' | ||
+ | } else { | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | If you prefer dehomogenized float coordinates, | ||
+ | |||
+ | <code perl> | ||
+ | > $tet-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Tue Mar 29 16:03:37 2022 | ||
+ | tet | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <meta charset=utf-8> | ||
+ | < | ||
+ | < | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | */ | ||
+ | html {overflow: scroll;} | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | # | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_END | ||
+ | */ | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | <div id=' | ||
+ | <div class=group id=' | ||
+ | < | ||
+ | < | ||
+ | <div class=indented>< | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | <div class=suboption> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | <div class=suboption> | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | <select id=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <img id=' | ||
+ | <img id=' | ||
+ | <div id=" | ||
+ | </ | ||
+ | < | ||
+ | requirejs.config({ | ||
+ | paths: { | ||
+ | three: '/ | ||
+ | TrackballControls: | ||
+ | OrbitControls: | ||
+ | Projector: '/ | ||
+ | SVGRenderer: | ||
+ | WEBGL: '/ | ||
+ | }, | ||
+ | shim: { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | }); | ||
+ | | ||
+ | require([' | ||
+ | window.THREE = THREE; | ||
+ | require([' | ||
+ | | ||
+ | THREE.TrackballControls = TrackballControls; | ||
+ | THREE.OrbitControls = OrbitControls; | ||
+ | THREE.Projector = Projector; | ||
+ | THREE.SVGRenderer = SVGRenderer; | ||
+ | THREE.WEBGL = WEBGL; | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | |||
+ | const intervalLength = 25; // for automatic animations | ||
+ | const explodableModel = false; | ||
+ | const modelContains = { points: false, pointlabels: | ||
+ | const foldables = []; | ||
+ | |||
+ | var three = document.getElementById(" | ||
+ | var scene = new THREE.Scene(); | ||
+ | var renderer = new THREE.WebGLRenderer( { antialias: true } ); | ||
+ | var svgRenderer = new THREE.SVGRenderer( { antialias: true } ); | ||
+ | renderer.setPixelRatio( window.devicePixelRatio ); | ||
+ | renderer.setClearColor(0xFFFFFF, | ||
+ | svgRenderer.setClearColor(0xFFFFFF, | ||
+ | three.appendChild(renderer.domElement); | ||
+ | |||
+ | var frustumSize = 4; | ||
+ | var cameras = [new THREE.PerspectiveCamera(75, | ||
+ | cameras.forEach(function(cam) { | ||
+ | cam.position.set(0, | ||
+ | cam.lookAt(0, | ||
+ | cam.up.set(0, | ||
+ | }); | ||
+ | var controls = [new THREE.TrackballControls(cameras[0], | ||
+ | var camera, control; | ||
+ | |||
+ | controls[0].zoomSpeed = 0.2; | ||
+ | controls[0].rotateSpeed = 4; | ||
+ | |||
+ | |||
+ | // class to allow move points together with labels and spheres | ||
+ | var PMPoint = function (x,y,z) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addLabel = function(labelsprite) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addSphere = function(spheremesh) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.set = function(x, | ||
+ | | ||
+ | if (this.sprite) { | ||
+ | this.sprite.position.copy(this.vector); | ||
+ | } | ||
+ | if (this.sphere) { | ||
+ | this.sphere.position.copy(this.vector); | ||
+ | } | ||
+ | } | ||
+ | PMPoint.prototype.radius = function() { | ||
+ | if (this.sphere) { | ||
+ | return this.sphere.geometry.parameters.radius; | ||
+ | } else { | ||
+ | return 0; | ||
+ | } | ||
+ | }; | ||
+ | // select the target node | ||
+ | var target = document.querySelector('# | ||
+ | |||
+ | // create an observer instance | ||
+ | var observer = new MutationObserver(function(mutations) { | ||
+ | | ||
+ | if (mutation.removedNodes && mutation.removedNodes.length > 0) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | // configuration of the observer: | ||
+ | var config = { childList: true, characterData: | ||
+ | |||
+ | // pass in the target node, as well as the observer options | ||
+ | while (target) { | ||
+ | if (target.className==" | ||
+ | observer.observe(target, | ||
+ | break; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | var obj0 = new THREE.Object3D(); | ||
+ | obj0.name = " | ||
+ | obj0.userData.explodable = 1; | ||
+ | obj0.userData.points = []; | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 1)); | ||
+ | |||
+ | obj0.userData.pointradii = 0.02; | ||
+ | < | ||
+ | obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | obj0.userData.pointlabels = [" | ||
+ | obj0.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[2, 3, 1], [0, 3, 2], [1, 3, 0], [2, 1, 0]]; | ||
+ | < | ||
+ | obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj0); | ||
+ | scene.add(obj0); | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | function textSpriteMaterial(message, | ||
+ | if ( parameters === undefined ) parameters = {}; | ||
+ | var fontface = " | ||
+ | var fontsize = parameters.hasOwnProperty(" | ||
+ | fontsize = fontsize*10; | ||
+ | var lines = message.split(' | ||
+ | var size = 512; | ||
+ | for(var i = 0; i< | ||
+ | var tmp = lines[i].length; | ||
+ | while(tmp*fontsize > size){ | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | var canvas = document.createElement(' | ||
+ | canvas.width = size; | ||
+ | canvas.height = size; | ||
+ | var context = canvas.getContext(' | ||
+ | context.fillStyle = " | ||
+ | context.fill(); | ||
+ | context.font = fontsize + "px " + fontface; | ||
+ | | ||
+ | // text color | ||
+ | context.fillStyle = " | ||
+ | | ||
+ | context.fillText(lines[i], | ||
+ | } | ||
+ | | ||
+ | // canvas contents will be used for a texture | ||
+ | var texture = new THREE.Texture(canvas); | ||
+ | texture.needsUpdate = true; | ||
+ | | ||
+ | var spriteMaterial = new THREE.SpriteMaterial({map: | ||
+ | return spriteMaterial; | ||
+ | } | ||
+ | |||
+ | |||
+ | // ---------------------- INITIALIZING OBJECTS-------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function init_object(obj) { | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_points(obj); | ||
+ | modelContains.points = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_pointlabels(obj); | ||
+ | modelContains.pointlabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_lines(obj); | ||
+ | modelContains.lines = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_edgelabels(obj); | ||
+ | modelContains.edgelabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_arrowheads(obj); | ||
+ | modelContains.arrowheads = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_faces(obj); | ||
+ | modelContains.faces = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function init_points(obj) { | ||
+ | var pointgroup = new THREE.Group(); | ||
+ | pointgroup.name = " | ||
+ | var points = obj.userData.points; | ||
+ | var radii = obj.userData.pointradii; | ||
+ | var materials = obj.userData.pointmaterial; | ||
+ | var geometry, | ||
+ | if (!Array.isArray(radii)) { | ||
+ | geometry = new THREE.SphereBufferGeometry(radii); | ||
+ | } | ||
+ | if (!Array.isArray(materials)) { | ||
+ | material = materials; | ||
+ | } | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | if (Array.isArray(radii)) { | ||
+ | if (radii[i] == 0) { | ||
+ | continue; | ||
+ | } | ||
+ | geometry = new THREE.SphereBufferGeometry(radii[i]); | ||
+ | } | ||
+ | if (Array.isArray(materials)) { | ||
+ | material = materials[i]; | ||
+ | } | ||
+ | var sphere = new THREE.Mesh(geometry, | ||
+ | point.addSphere(sphere); | ||
+ | pointgroup.add(sphere); | ||
+ | } | ||
+ | obj.add(pointgroup); | ||
+ | } | ||
+ | |||
+ | function init_pointlabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var labels = obj.userData.pointlabels; | ||
+ | var pointlabels = new THREE.Group(); | ||
+ | pointlabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(pointlabels); | ||
+ | } | ||
+ | |||
+ | function init_lines(obj) { | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var points = obj.userData.points; | ||
+ | var materials = obj.userData.edgematerial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 ); | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | for (var i=0; i< | ||
+ | geometry.addGroup(2*i, | ||
+ | } | ||
+ | } | ||
+ | var lines = new THREE.LineSegments(geometry, | ||
+ | lines.name = " | ||
+ | obj.add(lines); | ||
+ | updateEdgesPosition(obj); | ||
+ | } | ||
+ | |||
+ | function init_edgelabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var labels = obj.userData.edgelabels; | ||
+ | var edgelabels = new THREE.Group(); | ||
+ | edgelabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(edgelabels); | ||
+ | } | ||
+ | |||
+ | function init_arrowheads(obj) { | ||
+ | var arrowheads = new THREE.Group(); | ||
+ | arrowheads.name = " | ||
+ | var arrowstyle = obj.userData.arrowstyle; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var edgematerials = obj.userData.edgematerial; | ||
+ | var points = obj.userData.points; | ||
+ | var material; | ||
+ | if (!Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials.color} ); | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var start = points[edgeindices[i]]; | ||
+ | var end = points[edgeindices[i+1]]; | ||
+ | var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius(); | ||
+ | if (dist <= 0) { | ||
+ | continue; | ||
+ | } | ||
+ | var dir = new THREE.Vector3().subVectors(end.vector, | ||
+ | dir.normalize(); | ||
+ | var axis = new THREE.Vector3().set(dir.z, | ||
+ | axis.normalize(); | ||
+ | var radians = Math.acos( dir.y ); | ||
+ | var radius = dist/25; | ||
+ | var height = dist/5; | ||
+ | var geometry = new THREE.ConeBufferGeometry(radius, | ||
+ | var position = new THREE.Vector3().addVectors(start.vector, | ||
+ | if (Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} ); | ||
+ | } | ||
+ | var cone = new THREE.Mesh( geometry, material ); | ||
+ | cone.quaternion.setFromAxisAngle(axis, | ||
+ | cone.position.copy(position);; | ||
+ | arrowheads.add(cone); | ||
+ | } | ||
+ | obj.add(arrowheads); | ||
+ | } | ||
+ | |||
+ | function init_faces(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var facets = obj.userData.facets; | ||
+ | obj.userData.triangleindices = []; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | for (var t=0; t< | ||
+ | obj.userData.triangleindices.push(facet[0], | ||
+ | } | ||
+ | } | ||
+ | var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute(bufarr, | ||
+ | | ||
+ | var materials = obj.userData.facetmaterial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var frontmaterials = []; | ||
+ | var backmaterials = []; | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | var tricount = 0; | ||
+ | var facet; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | geometry.addGroup(tricount, | ||
+ | tricount += (facet.length-2)*3; | ||
+ | } | ||
+ | for (var j=0; j< | ||
+ | var fmat = materials[j].clone() | ||
+ | fmat.side = THREE.FrontSide; | ||
+ | frontmaterials.push(fmat); | ||
+ | var bmat = materials[j].clone() | ||
+ | bmat.side = THREE.BackSide; | ||
+ | backmaterials.push(bmat); | ||
+ | obj.userData.facetmaterial = frontmaterials.concat(backmaterials); | ||
+ | } | ||
+ | } else if (materials instanceof THREE.Material) { | ||
+ | frontmaterials = materials.clone() | ||
+ | frontmaterials.side = THREE.FrontSide; | ||
+ | backmaterials = materials.clone() | ||
+ | backmaterials.side = THREE.BackSide; | ||
+ | obj.userData.facetmaterial = [frontmaterials, | ||
+ | } | ||
+ | // duplicating the object with front and back should avoid transparency issues | ||
+ | var backmesh = new THREE.Mesh(geometry, | ||
+ | // meshname is used to show/hide objects | ||
+ | backmesh.name = " | ||
+ | obj.add(backmesh); | ||
+ | var frontmesh = new THREE.Mesh(geometry, | ||
+ | frontmesh.name = " | ||
+ | obj.add(frontmesh); | ||
+ | updateFacesPosition(obj); | ||
+ | } | ||
+ | // // | ||
+ | |||
+ | |||
+ | function updateFacesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.triangleindices; | ||
+ | var faces = obj.getObjectByName(" | ||
+ | var ba = faces.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | faces.geometry.attributes.position.needsUpdate = true; | ||
+ | | ||
+ | } | ||
+ | |||
+ | function updateEdgesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.edgeindices; | ||
+ | var lines = obj.getObjectByName(" | ||
+ | var ba = lines.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | lines.geometry.attributes.position.needsUpdate = true; | ||
+ | } | ||
+ | |||
+ | function onWindowResize() { | ||
+ | renderer.setSize( three.clientWidth, | ||
+ | svgRenderer.setSize( three.clientWidth, | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | function updateCamera() { | ||
+ | var width = three.clientWidth; | ||
+ | var height = three.clientHeight; | ||
+ | var aspect = width / height; | ||
+ | if (camera.type == " | ||
+ | camera.left = frustumSize * aspect / - 2; | ||
+ | camera.right = frustumSize * aspect / 2; | ||
+ | camera.top = frustumSize / 2; | ||
+ | camera.bottom = - frustumSize / 2; | ||
+ | } else if (camera.type == " | ||
+ | camera.aspect = aspect; | ||
+ | } | ||
+ | camera.updateProjectionMatrix(); | ||
+ | } | ||
+ | |||
+ | function changeCamera(event) { | ||
+ | var selindex = event.currentTarget.selectedIndex; | ||
+ | camera = cameras[selindex]; | ||
+ | control = controls[selindex]; | ||
+ | control.enabled = true; | ||
+ | for (var i=0; i< | ||
+ | if (i!=selindex) { | ||
+ | controls[i].enabled = false; | ||
+ | } | ||
+ | } | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | var camtypenode = document.getElementById(' | ||
+ | camtypenode.onchange = changeCamera; | ||
+ | camtypenode.dispatchEvent(new Event(' | ||
+ | |||
+ | onWindowResize(); | ||
+ | window.addEventListener(' | ||
+ | |||
+ | |||
+ | var xRotationEnabled = false; | ||
+ | var yRotationEnabled = false; | ||
+ | var zRotationEnabled = false; | ||
+ | var rotationSpeedFactor = 1; | ||
+ | var settingsShown = false; | ||
+ | var labelsShown = true; | ||
+ | var intervals = []; | ||
+ | var timeouts = []; | ||
+ | var explodingSpeed = 0.05; | ||
+ | var explodeScale = 0.000001; | ||
+ | var XMLS = new XMLSerializer(); | ||
+ | var svgElement; | ||
+ | var renderId; | ||
+ | |||
+ | var render = function () { | ||
+ | |||
+ | renderId = requestAnimationFrame(render); | ||
+ | |||
+ | // comment in for automatic explosion | ||
+ | // | ||
+ | |||
+ | var phi = 0.02 * rotationSpeedFactor; | ||
+ | |||
+ | if (xRotationEnabled) { | ||
+ | scene.rotation.x += phi; | ||
+ | } | ||
+ | if (yRotationEnabled) { | ||
+ | scene.rotation.y += phi; | ||
+ | } | ||
+ | if (zRotationEnabled) { | ||
+ | scene.rotation.z += phi; | ||
+ | } | ||
+ | |||
+ | control.update(); | ||
+ | renderer.render(scene, | ||
+ | }; | ||
+ | |||
+ | if ( THREE.WEBGL.isWebGLAvailable() ) { | ||
+ | render(); | ||
+ | } else { | ||
+ | var warning = WEBGL.getWebGLErrorMessage(); | ||
+ | three.appendChild( warning ); | ||
+ | } | ||
+ | | ||
+ | function changeTransparency() { | ||
+ | var opacity = 1-Number(event.currentTarget.value); | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].opacity = opacity; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.opacity = opacity; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleDepthWrite(event) { | ||
+ | depthwrite = event.currentTarget.checked; | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].depthWrite = depthwrite; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.depthWrite = depthWrite; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function changeRotationX(event){ | ||
+ | xRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationY(event){ | ||
+ | yRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationZ(event){ | ||
+ | zRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | |||
+ | function changeRotationSpeedFactor(event){ | ||
+ | rotationSpeedFactor = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function resetScene(){ | ||
+ | scene.rotation.set(0, | ||
+ | camera.position.set(0, | ||
+ | camera.up.set(0, | ||
+ | } | ||
+ | |||
+ | function showSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = true; | ||
+ | } | ||
+ | |||
+ | function hideSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = false; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | var pos = 150* Math.PI; | ||
+ | |||
+ | function updateFactor() { | ||
+ | pos++; | ||
+ | return Math.sin(.01*pos)+1; | ||
+ | } | ||
+ | |||
+ | // ------------------------ FOLDING ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | // rotate point p around axis defined by points p1 and p2 by given angle | ||
+ | function rotate(p, p1, p2, angle ){ | ||
+ | angle = -angle; | ||
+ | var x = p.x, y = p.y, z = p.z, | ||
+ | a = p1.x, b = p1.y, c = p1.z, | ||
+ | u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z; | ||
+ | var result = []; | ||
+ | var L = u*u + v*v + w*w; | ||
+ | var sqrt = Math.sqrt; | ||
+ | var cos = Math.cos; | ||
+ | var sin = Math.sin; | ||
+ | |||
+ | result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/ | ||
+ | result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/ | ||
+ | result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/ | ||
+ | |||
+ | return result; | ||
+ | } | ||
+ | |||
+ | var fold = function(event){ | ||
+ | var obj = foldables[Number(event.currentTarget.name)]; | ||
+ | var foldvalue = Number(event.currentTarget.value); | ||
+ | var scale = foldvalue - obj.userData.oldscale; | ||
+ | |||
+ | for (var j=0; j< | ||
+ | rotateVertices(obj, | ||
+ | } | ||
+ | update(obj); | ||
+ | obj.userData.oldscale += scale; | ||
+ | lookAtBarycenter(obj); | ||
+ | } | ||
+ | |||
+ | function lookAtBarycenter(obj){ | ||
+ | control.target = barycenter(obj); | ||
+ | } | ||
+ | |||
+ | function barycenter(obj) { | ||
+ | var center = new THREE.Vector3(0, | ||
+ | var points = obj.userData.points; | ||
+ | for (var i=0; i< | ||
+ | center.add(points[i].vector); | ||
+ | } | ||
+ | center.divideScalar(points.length); | ||
+ | return center; | ||
+ | } | ||
+ | |||
+ | function rotateVertices(obj, | ||
+ | var axes = obj.userData.axes; | ||
+ | var subtrees = obj.userData.subtrees; | ||
+ | var points = obj.userData.points; | ||
+ | var angles = obj.userData.angles; | ||
+ | if (edge < axes.length){ | ||
+ | for (var j=0; j< | ||
+ | var rotP = rotate(points[subtrees[edge][j]].vector, | ||
+ | points[subtrees[edge][j]].set(rotP[0], | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function update(obj) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | if (foldables.length) { | ||
+ | var settings = document.getElementById(' | ||
+ | var foldDiv = document.createElement(' | ||
+ | foldDiv.id = ' | ||
+ | var title = document.createElement(' | ||
+ | title.innerHTML = ' | ||
+ | foldDiv.appendChild(title); | ||
+ | foldDiv.className = ' | ||
+ | for (var i=0; i< | ||
+ | var range = document.createElement(' | ||
+ | range.type = ' | ||
+ | range.min = 0; | ||
+ | range.max = 1; | ||
+ | range.value = 0; | ||
+ | range.step = 0.001; | ||
+ | range.name = String(i); | ||
+ | range.oninput = fold; | ||
+ | foldDiv.appendChild(range); | ||
+ | } | ||
+ | lookAtBarycenter(foldables[0]); | ||
+ | settings.insertBefore(foldDiv, | ||
+ | } | ||
+ | |||
+ | | ||
+ | // ---------------------- EXPLOSION ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | if (explodableModel) { | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | if ( obj.userData.explodable ) { | ||
+ | computeCentroid(obj); | ||
+ | } | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | explode(0.000001); | ||
+ | } | ||
+ | |||
+ | function computeCentroid(obj) { | ||
+ | centroid = new THREE.Vector3(); | ||
+ | obj.userData.points.forEach(function(pmpoint) { | ||
+ | centroid.add(pmpoint.vector); | ||
+ | }); | ||
+ | centroid.divideScalar(obj.userData.points.length); | ||
+ | obj.userData.centroid = centroid; | ||
+ | } | ||
+ | |||
+ | function explode(factor) { | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i]; | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | var c = obj.userData.centroid; | ||
+ | obj.position.set(c.x*factor, | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function triggerExplode(event){ | ||
+ | explodeScale = Number(event.currentTarget.value); | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | |||
+ | function setExplodingSpeed(event){ | ||
+ | explodingSpeed = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function triggerAutomaticExplode(event){ | ||
+ | if (event.currentTarget.checked){ | ||
+ | startExploding(); | ||
+ | } else { | ||
+ | clearIntervals(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function startExploding(){ | ||
+ | intervals.push(setInterval(explodingInterval, | ||
+ | } | ||
+ | |||
+ | |||
+ | function explodingInterval(){ | ||
+ | explodeScale += explodingSpeed; | ||
+ | if (explodeScale <= 6){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else{ | ||
+ | explode(6); | ||
+ | explodeScale = 6; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startUnexploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | |||
+ | function startUnexploding(){ | ||
+ | intervals.push(setInterval(unexplodingInterval, | ||
+ | } | ||
+ | |||
+ | function unexplodingInterval(){ | ||
+ | explodeScale -= explodingSpeed; | ||
+ | if (explodeScale >= 0){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else { | ||
+ | explode(0); | ||
+ | explodeScale = 0; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startExploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | function clearIntervals(){ | ||
+ | intervals.forEach(function(interval){ | ||
+ | clearInterval(interval); | ||
+ | }); | ||
+ | intervals = []; | ||
+ | timeouts.forEach(function(timeout){ | ||
+ | clearTimeout(timeout); | ||
+ | }); | ||
+ | timeouts = []; | ||
+ | } | ||
+ | |||
+ | // ---------------------- DISPLAY -------------------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | const objectTypeInnerHTMLs = { points: " | ||
+ | const objectTypeVisible = {}; | ||
+ | Object.assign(objectTypeVisible, | ||
+ | const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort(); | ||
+ | const shownObjectTypesList = document.getElementById(' | ||
+ | |||
+ | function setVisibility(bool, | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i].getObjectByName(objname); | ||
+ | if (obj) { | ||
+ | obj.visible = bool; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleObjectTypeVisibility(event){ | ||
+ | var name = event.currentTarget.name; | ||
+ | var checked = event.currentTarget.checked; | ||
+ | objectTypeVisible[name] = checked; | ||
+ | if (name == " | ||
+ | setVisibility(checked," | ||
+ | setVisibility(checked," | ||
+ | } else { | ||
+ | setVisibility(checked, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var key = sortedObjectTypeKeys[i]; | ||
+ | if (modelContains[key]) { | ||
+ | var objTypeNode = document.createElement(' | ||
+ | objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = key; | ||
+ | checkbox.onchange = toggleObjectTypeVisibility; | ||
+ | shownObjectTypesList.appendChild(checkbox); | ||
+ | shownObjectTypesList.appendChild(objTypeNode); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // ------------------------------------------------------ | ||
+ | |||
+ | function toggleObjectVisibility(event){ | ||
+ | var nr = Number(event.currentTarget.name); | ||
+ | scene.children[nr].visible = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | // append checkboxes for displaying or hiding objects | ||
+ | var shownObjectsList = document.getElementById(' | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | var objNode = document.createElement(' | ||
+ | objNode.innerHTML = obj.name + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = String(i); | ||
+ | checkbox.onchange = toggleObjectVisibility; | ||
+ | shownObjectsList.appendChild(checkbox); | ||
+ | shownObjectsList.appendChild(objNode); | ||
+ | } | ||
+ | |||
+ | // ---------------------- SVG ------------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function takeSvgScreenshot() { | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | svgRenderer.render(scene, | ||
+ | svgElement = XMLS.serializeToString(svgRenderer.domElement); | ||
+ | | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | |||
+ | if (document.getElementById(' | ||
+ | //show in new tab | ||
+ | var myWindow = window.open("","" | ||
+ | myWindow.document.body.innerHTML = svgElement; | ||
+ | } else{ | ||
+ | // download svg file | ||
+ | download(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function download(filename, | ||
+ | var element = document.createElement(' | ||
+ | element.setAttribute(' | ||
+ | element.setAttribute(' | ||
+ | |||
+ | element.style.display = ' | ||
+ | document.body.appendChild(element); | ||
+ | |||
+ | element.click(); | ||
+ | |||
+ | document.body.removeChild(element); | ||
+ | } | ||
+ | |||
+ | |||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | |||
+ | |||
+ | // ------------------ SHORTCUTS -------------------------------------------- | ||
+ | // ------------------------------------------------------------------------- | ||
+ | |||
+ | /** | ||
+ | * http:// | ||
+ | * Version : 2.01.B | ||
+ | * By Binny V A | ||
+ | * License : BSD | ||
+ | */ | ||
+ | shortcut = { | ||
+ | ' | ||
+ | ' | ||
+ | //Provide a set of default options | ||
+ | var default_options = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | if(!opt) opt = default_options; | ||
+ | else { | ||
+ | for(var dfo in default_options) { | ||
+ | if(typeof opt[dfo] == ' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var ele = opt.target; | ||
+ | if(typeof opt.target == ' | ||
+ | var ths = this; | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | |||
+ | //The function to be called at keypress | ||
+ | var func = function(e) { | ||
+ | e = e || window.event; | ||
+ | |||
+ | if(opt[' | ||
+ | var element; | ||
+ | if(e.target) element=e.target; | ||
+ | else if(e.srcElement) element=e.srcElement; | ||
+ | if(element.nodeType==3) element=element.parentNode; | ||
+ | |||
+ | if(element.tagName == ' | ||
+ | } | ||
+ | |||
+ | //Find Which key is pressed | ||
+ | if (e.keyCode) code = e.keyCode; | ||
+ | else if (e.which) code = e.which; | ||
+ | var character = String.fromCharCode(code).toLowerCase(); | ||
+ | |||
+ | if(code == 188) character=","; | ||
+ | if(code == 190) character=" | ||
+ | |||
+ | var keys = shortcut_combination.split(" | ||
+ | //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked | ||
+ | var kp = 0; | ||
+ | |||
+ | //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken | ||
+ | var shift_nums = { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | ";":":", | ||
+ | "'":" | ||
+ | ",":"<", | ||
+ | " | ||
+ | "/":"?", | ||
+ | " | ||
+ | } | ||
+ | // | ||
+ | var special_keys = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | |||
+ | var modifiers = { | ||
+ | shift: { wanted: | ||
+ | ctrl : { wanted: | ||
+ | alt | ||
+ | meta : { wanted: | ||
+ | }; | ||
+ | | ||
+ | if(e.ctrlKey) modifiers.ctrl.pressed = true; | ||
+ | if(e.shiftKey) modifiers.shift.pressed = true; | ||
+ | if(e.altKey) modifiers.alt.pressed = true; | ||
+ | if(e.metaKey) | ||
+ | | ||
+ | for(var i=0; k=keys[i], | ||
+ | // | ||
+ | if(k == ' | ||
+ | kp++; | ||
+ | modifiers.ctrl.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.shift.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.alt.wanted = true; | ||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.meta.wanted = true; | ||
+ | } else if(k.length > 1) { //If it is a special key | ||
+ | if(special_keys[k] == code) kp++; | ||
+ | |||
+ | } else if(opt[' | ||
+ | if(opt[' | ||
+ | |||
+ | } else { //The special keys did not match | ||
+ | if(character == k) kp++; | ||
+ | else { | ||
+ | if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase | ||
+ | character = shift_nums[character]; | ||
+ | if(character == k) kp++; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if(kp == keys.length && | ||
+ | modifiers.ctrl.pressed == modifiers.ctrl.wanted && | ||
+ | modifiers.shift.pressed == modifiers.shift.wanted && | ||
+ | modifiers.alt.pressed == modifiers.alt.wanted && | ||
+ | modifiers.meta.pressed == modifiers.meta.wanted) { | ||
+ | callback(e); | ||
+ | |||
+ | if(!opt[' | ||
+ | // | ||
+ | e.cancelBubble = true; | ||
+ | e.returnValue = false; | ||
+ | |||
+ | // | ||
+ | if (e.stopPropagation) { | ||
+ | e.stopPropagation(); | ||
+ | e.preventDefault(); | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | this.all_shortcuts[shortcut_combination] = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }; | ||
+ | //Attach the function with the event | ||
+ | if(ele.addEventListener) ele.addEventListener(opt[' | ||
+ | else if(ele.attachEvent) ele.attachEvent(' | ||
+ | else ele[' | ||
+ | }, | ||
+ | |||
+ | //Remove the shortcut - just specify the shortcut and I will remove the binding | ||
+ | ' | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | var binding = this.all_shortcuts[shortcut_combination]; | ||
+ | delete(this.all_shortcuts[shortcut_combination]) | ||
+ | if(!binding) return; | ||
+ | var type = binding[' | ||
+ | var ele = binding[' | ||
+ | var callback = binding[' | ||
+ | |||
+ | if(ele.detachEvent) ele.detachEvent(' | ||
+ | else if(ele.removeEventListener) ele.removeEventListener(type, | ||
+ | else ele[' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | shortcut.add(" | ||
+ | var event = new Event(' | ||
+ | if (settingsShown){ | ||
+ | document.getElementById(' | ||
+ | } else { | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | === Vertex Size === | ||
+ | |||
+ | Similar to changing the colors using the // | ||
+ | |||
+ | **Single size**: To increase the size of the vertices, just pass a number larger than 1 to the // | ||
+ | |||
+ | <code perl> | ||
+ | > simplex(3)-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Tue Mar 29 16:03:37 2022 | ||
+ | unnamed | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <meta charset=utf-8> | ||
+ | < | ||
+ | < | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | */ | ||
+ | html {overflow: scroll;} | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | # | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_END | ||
+ | */ | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | <div id=' | ||
+ | <div class=group id=' | ||
+ | < | ||
+ | < | ||
+ | <div class=indented>< | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | <div class=suboption> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | <div class=suboption> | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | <select id=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <img id=' | ||
+ | <img id=' | ||
+ | <div id=" | ||
+ | </ | ||
+ | < | ||
+ | requirejs.config({ | ||
+ | paths: { | ||
+ | three: '/ | ||
+ | TrackballControls: | ||
+ | OrbitControls: | ||
+ | Projector: '/ | ||
+ | SVGRenderer: | ||
+ | WEBGL: '/ | ||
+ | }, | ||
+ | shim: { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | }); | ||
+ | | ||
+ | require([' | ||
+ | window.THREE = THREE; | ||
+ | require([' | ||
+ | | ||
+ | THREE.TrackballControls = TrackballControls; | ||
+ | THREE.OrbitControls = OrbitControls; | ||
+ | THREE.Projector = Projector; | ||
+ | THREE.SVGRenderer = SVGRenderer; | ||
+ | THREE.WEBGL = WEBGL; | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | |||
+ | const intervalLength = 25; // for automatic animations | ||
+ | const explodableModel = false; | ||
+ | const modelContains = { points: false, pointlabels: | ||
+ | const foldables = []; | ||
+ | |||
+ | var three = document.getElementById(" | ||
+ | var scene = new THREE.Scene(); | ||
+ | var renderer = new THREE.WebGLRenderer( { antialias: true } ); | ||
+ | var svgRenderer = new THREE.SVGRenderer( { antialias: true } ); | ||
+ | renderer.setPixelRatio( window.devicePixelRatio ); | ||
+ | renderer.setClearColor(0xFFFFFF, | ||
+ | svgRenderer.setClearColor(0xFFFFFF, | ||
+ | three.appendChild(renderer.domElement); | ||
+ | |||
+ | var frustumSize = 4; | ||
+ | var cameras = [new THREE.PerspectiveCamera(75, | ||
+ | cameras.forEach(function(cam) { | ||
+ | cam.position.set(0, | ||
+ | cam.lookAt(0, | ||
+ | cam.up.set(0, | ||
+ | }); | ||
+ | var controls = [new THREE.TrackballControls(cameras[0], | ||
+ | var camera, control; | ||
+ | |||
+ | controls[0].zoomSpeed = 0.2; | ||
+ | controls[0].rotateSpeed = 4; | ||
+ | |||
+ | |||
+ | // class to allow move points together with labels and spheres | ||
+ | var PMPoint = function (x,y,z) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addLabel = function(labelsprite) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addSphere = function(spheremesh) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.set = function(x, | ||
+ | | ||
+ | if (this.sprite) { | ||
+ | this.sprite.position.copy(this.vector); | ||
+ | } | ||
+ | if (this.sphere) { | ||
+ | this.sphere.position.copy(this.vector); | ||
+ | } | ||
+ | } | ||
+ | PMPoint.prototype.radius = function() { | ||
+ | if (this.sphere) { | ||
+ | return this.sphere.geometry.parameters.radius; | ||
+ | } else { | ||
+ | return 0; | ||
+ | } | ||
+ | }; | ||
+ | // select the target node | ||
+ | var target = document.querySelector('# | ||
+ | |||
+ | // create an observer instance | ||
+ | var observer = new MutationObserver(function(mutations) { | ||
+ | | ||
+ | if (mutation.removedNodes && mutation.removedNodes.length > 0) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | // configuration of the observer: | ||
+ | var config = { childList: true, characterData: | ||
+ | |||
+ | // pass in the target node, as well as the observer options | ||
+ | while (target) { | ||
+ | if (target.className==" | ||
+ | observer.observe(target, | ||
+ | break; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | var obj0 = new THREE.Object3D(); | ||
+ | obj0.name = " | ||
+ | obj0.userData.explodable = 1; | ||
+ | obj0.userData.points = []; | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 1)); | ||
+ | |||
+ | obj0.userData.pointradii = 0.04; | ||
+ | < | ||
+ | obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | obj0.userData.pointlabels = [" | ||
+ | obj0.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[2, 3, 1], [0, 3, 2], [1, 3, 0], [2, 1, 0]]; | ||
+ | < | ||
+ | obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj0); | ||
+ | scene.add(obj0); | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | function textSpriteMaterial(message, | ||
+ | if ( parameters === undefined ) parameters = {}; | ||
+ | var fontface = " | ||
+ | var fontsize = parameters.hasOwnProperty(" | ||
+ | fontsize = fontsize*10; | ||
+ | var lines = message.split(' | ||
+ | var size = 512; | ||
+ | for(var i = 0; i< | ||
+ | var tmp = lines[i].length; | ||
+ | while(tmp*fontsize > size){ | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | var canvas = document.createElement(' | ||
+ | canvas.width = size; | ||
+ | canvas.height = size; | ||
+ | var context = canvas.getContext(' | ||
+ | context.fillStyle = " | ||
+ | context.fill(); | ||
+ | context.font = fontsize + "px " + fontface; | ||
+ | | ||
+ | // text color | ||
+ | context.fillStyle = " | ||
+ | | ||
+ | context.fillText(lines[i], | ||
+ | } | ||
+ | | ||
+ | // canvas contents will be used for a texture | ||
+ | var texture = new THREE.Texture(canvas); | ||
+ | texture.needsUpdate = true; | ||
+ | | ||
+ | var spriteMaterial = new THREE.SpriteMaterial({map: | ||
+ | return spriteMaterial; | ||
+ | } | ||
+ | |||
+ | |||
+ | // ---------------------- INITIALIZING OBJECTS-------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function init_object(obj) { | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_points(obj); | ||
+ | modelContains.points = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_pointlabels(obj); | ||
+ | modelContains.pointlabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_lines(obj); | ||
+ | modelContains.lines = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_edgelabels(obj); | ||
+ | modelContains.edgelabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_arrowheads(obj); | ||
+ | modelContains.arrowheads = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_faces(obj); | ||
+ | modelContains.faces = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function init_points(obj) { | ||
+ | var pointgroup = new THREE.Group(); | ||
+ | pointgroup.name = " | ||
+ | var points = obj.userData.points; | ||
+ | var radii = obj.userData.pointradii; | ||
+ | var materials = obj.userData.pointmaterial; | ||
+ | var geometry, | ||
+ | if (!Array.isArray(radii)) { | ||
+ | geometry = new THREE.SphereBufferGeometry(radii); | ||
+ | } | ||
+ | if (!Array.isArray(materials)) { | ||
+ | material = materials; | ||
+ | } | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | if (Array.isArray(radii)) { | ||
+ | if (radii[i] == 0) { | ||
+ | continue; | ||
+ | } | ||
+ | geometry = new THREE.SphereBufferGeometry(radii[i]); | ||
+ | } | ||
+ | if (Array.isArray(materials)) { | ||
+ | material = materials[i]; | ||
+ | } | ||
+ | var sphere = new THREE.Mesh(geometry, | ||
+ | point.addSphere(sphere); | ||
+ | pointgroup.add(sphere); | ||
+ | } | ||
+ | obj.add(pointgroup); | ||
+ | } | ||
+ | |||
+ | function init_pointlabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var labels = obj.userData.pointlabels; | ||
+ | var pointlabels = new THREE.Group(); | ||
+ | pointlabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(pointlabels); | ||
+ | } | ||
+ | |||
+ | function init_lines(obj) { | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var points = obj.userData.points; | ||
+ | var materials = obj.userData.edgematerial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 ); | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | for (var i=0; i< | ||
+ | geometry.addGroup(2*i, | ||
+ | } | ||
+ | } | ||
+ | var lines = new THREE.LineSegments(geometry, | ||
+ | lines.name = " | ||
+ | obj.add(lines); | ||
+ | updateEdgesPosition(obj); | ||
+ | } | ||
+ | |||
+ | function init_edgelabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var labels = obj.userData.edgelabels; | ||
+ | var edgelabels = new THREE.Group(); | ||
+ | edgelabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(edgelabels); | ||
+ | } | ||
+ | |||
+ | function init_arrowheads(obj) { | ||
+ | var arrowheads = new THREE.Group(); | ||
+ | arrowheads.name = " | ||
+ | var arrowstyle = obj.userData.arrowstyle; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var edgematerials = obj.userData.edgematerial; | ||
+ | var points = obj.userData.points; | ||
+ | var material; | ||
+ | if (!Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials.color} ); | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var start = points[edgeindices[i]]; | ||
+ | var end = points[edgeindices[i+1]]; | ||
+ | var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius(); | ||
+ | if (dist <= 0) { | ||
+ | continue; | ||
+ | } | ||
+ | var dir = new THREE.Vector3().subVectors(end.vector, | ||
+ | dir.normalize(); | ||
+ | var axis = new THREE.Vector3().set(dir.z, | ||
+ | axis.normalize(); | ||
+ | var radians = Math.acos( dir.y ); | ||
+ | var radius = dist/25; | ||
+ | var height = dist/5; | ||
+ | var geometry = new THREE.ConeBufferGeometry(radius, | ||
+ | var position = new THREE.Vector3().addVectors(start.vector, | ||
+ | if (Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} ); | ||
+ | } | ||
+ | var cone = new THREE.Mesh( geometry, material ); | ||
+ | cone.quaternion.setFromAxisAngle(axis, | ||
+ | cone.position.copy(position);; | ||
+ | arrowheads.add(cone); | ||
+ | } | ||
+ | obj.add(arrowheads); | ||
+ | } | ||
+ | |||
+ | function init_faces(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var facets = obj.userData.facets; | ||
+ | obj.userData.triangleindices = []; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | for (var t=0; t< | ||
+ | obj.userData.triangleindices.push(facet[0], | ||
+ | } | ||
+ | } | ||
+ | var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute(bufarr, | ||
+ | | ||
+ | var materials = obj.userData.facetmaterial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var frontmaterials = []; | ||
+ | var backmaterials = []; | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | var tricount = 0; | ||
+ | var facet; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | geometry.addGroup(tricount, | ||
+ | tricount += (facet.length-2)*3; | ||
+ | } | ||
+ | for (var j=0; j< | ||
+ | var fmat = materials[j].clone() | ||
+ | fmat.side = THREE.FrontSide; | ||
+ | frontmaterials.push(fmat); | ||
+ | var bmat = materials[j].clone() | ||
+ | bmat.side = THREE.BackSide; | ||
+ | backmaterials.push(bmat); | ||
+ | obj.userData.facetmaterial = frontmaterials.concat(backmaterials); | ||
+ | } | ||
+ | } else if (materials instanceof THREE.Material) { | ||
+ | frontmaterials = materials.clone() | ||
+ | frontmaterials.side = THREE.FrontSide; | ||
+ | backmaterials = materials.clone() | ||
+ | backmaterials.side = THREE.BackSide; | ||
+ | obj.userData.facetmaterial = [frontmaterials, | ||
+ | } | ||
+ | // duplicating the object with front and back should avoid transparency issues | ||
+ | var backmesh = new THREE.Mesh(geometry, | ||
+ | // meshname is used to show/hide objects | ||
+ | backmesh.name = " | ||
+ | obj.add(backmesh); | ||
+ | var frontmesh = new THREE.Mesh(geometry, | ||
+ | frontmesh.name = " | ||
+ | obj.add(frontmesh); | ||
+ | updateFacesPosition(obj); | ||
+ | } | ||
+ | // // | ||
+ | |||
+ | |||
+ | function updateFacesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.triangleindices; | ||
+ | var faces = obj.getObjectByName(" | ||
+ | var ba = faces.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | faces.geometry.attributes.position.needsUpdate = true; | ||
+ | | ||
+ | } | ||
+ | |||
+ | function updateEdgesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.edgeindices; | ||
+ | var lines = obj.getObjectByName(" | ||
+ | var ba = lines.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | lines.geometry.attributes.position.needsUpdate = true; | ||
+ | } | ||
+ | |||
+ | function onWindowResize() { | ||
+ | renderer.setSize( three.clientWidth, | ||
+ | svgRenderer.setSize( three.clientWidth, | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | function updateCamera() { | ||
+ | var width = three.clientWidth; | ||
+ | var height = three.clientHeight; | ||
+ | var aspect = width / height; | ||
+ | if (camera.type == " | ||
+ | camera.left = frustumSize * aspect / - 2; | ||
+ | camera.right = frustumSize * aspect / 2; | ||
+ | camera.top = frustumSize / 2; | ||
+ | camera.bottom = - frustumSize / 2; | ||
+ | } else if (camera.type == " | ||
+ | camera.aspect = aspect; | ||
+ | } | ||
+ | camera.updateProjectionMatrix(); | ||
+ | } | ||
+ | |||
+ | function changeCamera(event) { | ||
+ | var selindex = event.currentTarget.selectedIndex; | ||
+ | camera = cameras[selindex]; | ||
+ | control = controls[selindex]; | ||
+ | control.enabled = true; | ||
+ | for (var i=0; i< | ||
+ | if (i!=selindex) { | ||
+ | controls[i].enabled = false; | ||
+ | } | ||
+ | } | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | var camtypenode = document.getElementById(' | ||
+ | camtypenode.onchange = changeCamera; | ||
+ | camtypenode.dispatchEvent(new Event(' | ||
+ | |||
+ | onWindowResize(); | ||
+ | window.addEventListener(' | ||
+ | |||
+ | |||
+ | var xRotationEnabled = false; | ||
+ | var yRotationEnabled = false; | ||
+ | var zRotationEnabled = false; | ||
+ | var rotationSpeedFactor = 1; | ||
+ | var settingsShown = false; | ||
+ | var labelsShown = true; | ||
+ | var intervals = []; | ||
+ | var timeouts = []; | ||
+ | var explodingSpeed = 0.05; | ||
+ | var explodeScale = 0.000001; | ||
+ | var XMLS = new XMLSerializer(); | ||
+ | var svgElement; | ||
+ | var renderId; | ||
+ | |||
+ | var render = function () { | ||
+ | |||
+ | renderId = requestAnimationFrame(render); | ||
+ | |||
+ | // comment in for automatic explosion | ||
+ | // | ||
+ | |||
+ | var phi = 0.02 * rotationSpeedFactor; | ||
+ | |||
+ | if (xRotationEnabled) { | ||
+ | scene.rotation.x += phi; | ||
+ | } | ||
+ | if (yRotationEnabled) { | ||
+ | scene.rotation.y += phi; | ||
+ | } | ||
+ | if (zRotationEnabled) { | ||
+ | scene.rotation.z += phi; | ||
+ | } | ||
+ | |||
+ | control.update(); | ||
+ | renderer.render(scene, | ||
+ | }; | ||
+ | |||
+ | if ( THREE.WEBGL.isWebGLAvailable() ) { | ||
+ | render(); | ||
+ | } else { | ||
+ | var warning = WEBGL.getWebGLErrorMessage(); | ||
+ | three.appendChild( warning ); | ||
+ | } | ||
+ | | ||
+ | function changeTransparency() { | ||
+ | var opacity = 1-Number(event.currentTarget.value); | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].opacity = opacity; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.opacity = opacity; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleDepthWrite(event) { | ||
+ | depthwrite = event.currentTarget.checked; | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].depthWrite = depthwrite; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.depthWrite = depthWrite; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function changeRotationX(event){ | ||
+ | xRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationY(event){ | ||
+ | yRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationZ(event){ | ||
+ | zRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | |||
+ | function changeRotationSpeedFactor(event){ | ||
+ | rotationSpeedFactor = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function resetScene(){ | ||
+ | scene.rotation.set(0, | ||
+ | camera.position.set(0, | ||
+ | camera.up.set(0, | ||
+ | } | ||
+ | |||
+ | function showSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = true; | ||
+ | } | ||
+ | |||
+ | function hideSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = false; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | var pos = 150* Math.PI; | ||
+ | |||
+ | function updateFactor() { | ||
+ | pos++; | ||
+ | return Math.sin(.01*pos)+1; | ||
+ | } | ||
+ | |||
+ | // ------------------------ FOLDING ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | // rotate point p around axis defined by points p1 and p2 by given angle | ||
+ | function rotate(p, p1, p2, angle ){ | ||
+ | angle = -angle; | ||
+ | var x = p.x, y = p.y, z = p.z, | ||
+ | a = p1.x, b = p1.y, c = p1.z, | ||
+ | u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z; | ||
+ | var result = []; | ||
+ | var L = u*u + v*v + w*w; | ||
+ | var sqrt = Math.sqrt; | ||
+ | var cos = Math.cos; | ||
+ | var sin = Math.sin; | ||
+ | |||
+ | result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/ | ||
+ | result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/ | ||
+ | result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/ | ||
+ | |||
+ | return result; | ||
+ | } | ||
+ | |||
+ | var fold = function(event){ | ||
+ | var obj = foldables[Number(event.currentTarget.name)]; | ||
+ | var foldvalue = Number(event.currentTarget.value); | ||
+ | var scale = foldvalue - obj.userData.oldscale; | ||
+ | |||
+ | for (var j=0; j< | ||
+ | rotateVertices(obj, | ||
+ | } | ||
+ | update(obj); | ||
+ | obj.userData.oldscale += scale; | ||
+ | lookAtBarycenter(obj); | ||
+ | } | ||
+ | |||
+ | function lookAtBarycenter(obj){ | ||
+ | control.target = barycenter(obj); | ||
+ | } | ||
+ | |||
+ | function barycenter(obj) { | ||
+ | var center = new THREE.Vector3(0, | ||
+ | var points = obj.userData.points; | ||
+ | for (var i=0; i< | ||
+ | center.add(points[i].vector); | ||
+ | } | ||
+ | center.divideScalar(points.length); | ||
+ | return center; | ||
+ | } | ||
+ | |||
+ | function rotateVertices(obj, | ||
+ | var axes = obj.userData.axes; | ||
+ | var subtrees = obj.userData.subtrees; | ||
+ | var points = obj.userData.points; | ||
+ | var angles = obj.userData.angles; | ||
+ | if (edge < axes.length){ | ||
+ | for (var j=0; j< | ||
+ | var rotP = rotate(points[subtrees[edge][j]].vector, | ||
+ | points[subtrees[edge][j]].set(rotP[0], | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function update(obj) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | if (foldables.length) { | ||
+ | var settings = document.getElementById(' | ||
+ | var foldDiv = document.createElement(' | ||
+ | foldDiv.id = ' | ||
+ | var title = document.createElement(' | ||
+ | title.innerHTML = ' | ||
+ | foldDiv.appendChild(title); | ||
+ | foldDiv.className = ' | ||
+ | for (var i=0; i< | ||
+ | var range = document.createElement(' | ||
+ | range.type = ' | ||
+ | range.min = 0; | ||
+ | range.max = 1; | ||
+ | range.value = 0; | ||
+ | range.step = 0.001; | ||
+ | range.name = String(i); | ||
+ | range.oninput = fold; | ||
+ | foldDiv.appendChild(range); | ||
+ | } | ||
+ | lookAtBarycenter(foldables[0]); | ||
+ | settings.insertBefore(foldDiv, | ||
+ | } | ||
+ | |||
+ | | ||
+ | // ---------------------- EXPLOSION ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | if (explodableModel) { | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | if ( obj.userData.explodable ) { | ||
+ | computeCentroid(obj); | ||
+ | } | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | explode(0.000001); | ||
+ | } | ||
+ | |||
+ | function computeCentroid(obj) { | ||
+ | centroid = new THREE.Vector3(); | ||
+ | obj.userData.points.forEach(function(pmpoint) { | ||
+ | centroid.add(pmpoint.vector); | ||
+ | }); | ||
+ | centroid.divideScalar(obj.userData.points.length); | ||
+ | obj.userData.centroid = centroid; | ||
+ | } | ||
+ | |||
+ | function explode(factor) { | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i]; | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | var c = obj.userData.centroid; | ||
+ | obj.position.set(c.x*factor, | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function triggerExplode(event){ | ||
+ | explodeScale = Number(event.currentTarget.value); | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | |||
+ | function setExplodingSpeed(event){ | ||
+ | explodingSpeed = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function triggerAutomaticExplode(event){ | ||
+ | if (event.currentTarget.checked){ | ||
+ | startExploding(); | ||
+ | } else { | ||
+ | clearIntervals(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function startExploding(){ | ||
+ | intervals.push(setInterval(explodingInterval, | ||
+ | } | ||
+ | |||
+ | |||
+ | function explodingInterval(){ | ||
+ | explodeScale += explodingSpeed; | ||
+ | if (explodeScale <= 6){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else{ | ||
+ | explode(6); | ||
+ | explodeScale = 6; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startUnexploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | |||
+ | function startUnexploding(){ | ||
+ | intervals.push(setInterval(unexplodingInterval, | ||
+ | } | ||
+ | |||
+ | function unexplodingInterval(){ | ||
+ | explodeScale -= explodingSpeed; | ||
+ | if (explodeScale >= 0){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else { | ||
+ | explode(0); | ||
+ | explodeScale = 0; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startExploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | function clearIntervals(){ | ||
+ | intervals.forEach(function(interval){ | ||
+ | clearInterval(interval); | ||
+ | }); | ||
+ | intervals = []; | ||
+ | timeouts.forEach(function(timeout){ | ||
+ | clearTimeout(timeout); | ||
+ | }); | ||
+ | timeouts = []; | ||
+ | } | ||
+ | |||
+ | // ---------------------- DISPLAY -------------------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | const objectTypeInnerHTMLs = { points: " | ||
+ | const objectTypeVisible = {}; | ||
+ | Object.assign(objectTypeVisible, | ||
+ | const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort(); | ||
+ | const shownObjectTypesList = document.getElementById(' | ||
+ | |||
+ | function setVisibility(bool, | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i].getObjectByName(objname); | ||
+ | if (obj) { | ||
+ | obj.visible = bool; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleObjectTypeVisibility(event){ | ||
+ | var name = event.currentTarget.name; | ||
+ | var checked = event.currentTarget.checked; | ||
+ | objectTypeVisible[name] = checked; | ||
+ | if (name == " | ||
+ | setVisibility(checked," | ||
+ | setVisibility(checked," | ||
+ | } else { | ||
+ | setVisibility(checked, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var key = sortedObjectTypeKeys[i]; | ||
+ | if (modelContains[key]) { | ||
+ | var objTypeNode = document.createElement(' | ||
+ | objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = key; | ||
+ | checkbox.onchange = toggleObjectTypeVisibility; | ||
+ | shownObjectTypesList.appendChild(checkbox); | ||
+ | shownObjectTypesList.appendChild(objTypeNode); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // ------------------------------------------------------ | ||
+ | |||
+ | function toggleObjectVisibility(event){ | ||
+ | var nr = Number(event.currentTarget.name); | ||
+ | scene.children[nr].visible = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | // append checkboxes for displaying or hiding objects | ||
+ | var shownObjectsList = document.getElementById(' | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | var objNode = document.createElement(' | ||
+ | objNode.innerHTML = obj.name + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = String(i); | ||
+ | checkbox.onchange = toggleObjectVisibility; | ||
+ | shownObjectsList.appendChild(checkbox); | ||
+ | shownObjectsList.appendChild(objNode); | ||
+ | } | ||
+ | |||
+ | // ---------------------- SVG ------------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function takeSvgScreenshot() { | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | svgRenderer.render(scene, | ||
+ | svgElement = XMLS.serializeToString(svgRenderer.domElement); | ||
+ | | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | |||
+ | if (document.getElementById(' | ||
+ | //show in new tab | ||
+ | var myWindow = window.open("","" | ||
+ | myWindow.document.body.innerHTML = svgElement; | ||
+ | } else{ | ||
+ | // download svg file | ||
+ | download(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function download(filename, | ||
+ | var element = document.createElement(' | ||
+ | element.setAttribute(' | ||
+ | element.setAttribute(' | ||
+ | |||
+ | element.style.display = ' | ||
+ | document.body.appendChild(element); | ||
+ | |||
+ | element.click(); | ||
+ | |||
+ | document.body.removeChild(element); | ||
+ | } | ||
+ | |||
+ | |||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | |||
+ | |||
+ | // ------------------ SHORTCUTS -------------------------------------------- | ||
+ | // ------------------------------------------------------------------------- | ||
+ | |||
+ | /** | ||
+ | * http:// | ||
+ | * Version : 2.01.B | ||
+ | * By Binny V A | ||
+ | * License : BSD | ||
+ | */ | ||
+ | shortcut = { | ||
+ | ' | ||
+ | ' | ||
+ | //Provide a set of default options | ||
+ | var default_options = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | if(!opt) opt = default_options; | ||
+ | else { | ||
+ | for(var dfo in default_options) { | ||
+ | if(typeof opt[dfo] == ' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var ele = opt.target; | ||
+ | if(typeof opt.target == ' | ||
+ | var ths = this; | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | |||
+ | //The function to be called at keypress | ||
+ | var func = function(e) { | ||
+ | e = e || window.event; | ||
+ | |||
+ | if(opt[' | ||
+ | var element; | ||
+ | if(e.target) element=e.target; | ||
+ | else if(e.srcElement) element=e.srcElement; | ||
+ | if(element.nodeType==3) element=element.parentNode; | ||
+ | |||
+ | if(element.tagName == ' | ||
+ | } | ||
+ | |||
+ | //Find Which key is pressed | ||
+ | if (e.keyCode) code = e.keyCode; | ||
+ | else if (e.which) code = e.which; | ||
+ | var character = String.fromCharCode(code).toLowerCase(); | ||
+ | |||
+ | if(code == 188) character=","; | ||
+ | if(code == 190) character=" | ||
+ | |||
+ | var keys = shortcut_combination.split(" | ||
+ | //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked | ||
+ | var kp = 0; | ||
+ | |||
+ | //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken | ||
+ | var shift_nums = { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | ";":":", | ||
+ | "'":" | ||
+ | ",":"<", | ||
+ | " | ||
+ | "/":"?", | ||
+ | " | ||
+ | } | ||
+ | // | ||
+ | var special_keys = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | |||
+ | var modifiers = { | ||
+ | shift: { wanted: | ||
+ | ctrl : { wanted: | ||
+ | alt | ||
+ | meta : { wanted: | ||
+ | }; | ||
+ | | ||
+ | if(e.ctrlKey) modifiers.ctrl.pressed = true; | ||
+ | if(e.shiftKey) modifiers.shift.pressed = true; | ||
+ | if(e.altKey) modifiers.alt.pressed = true; | ||
+ | if(e.metaKey) | ||
+ | | ||
+ | for(var i=0; k=keys[i], | ||
+ | // | ||
+ | if(k == ' | ||
+ | kp++; | ||
+ | modifiers.ctrl.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.shift.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.alt.wanted = true; | ||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.meta.wanted = true; | ||
+ | } else if(k.length > 1) { //If it is a special key | ||
+ | if(special_keys[k] == code) kp++; | ||
+ | |||
+ | } else if(opt[' | ||
+ | if(opt[' | ||
+ | |||
+ | } else { //The special keys did not match | ||
+ | if(character == k) kp++; | ||
+ | else { | ||
+ | if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase | ||
+ | character = shift_nums[character]; | ||
+ | if(character == k) kp++; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if(kp == keys.length && | ||
+ | modifiers.ctrl.pressed == modifiers.ctrl.wanted && | ||
+ | modifiers.shift.pressed == modifiers.shift.wanted && | ||
+ | modifiers.alt.pressed == modifiers.alt.wanted && | ||
+ | modifiers.meta.pressed == modifiers.meta.wanted) { | ||
+ | callback(e); | ||
+ | |||
+ | if(!opt[' | ||
+ | // | ||
+ | e.cancelBubble = true; | ||
+ | e.returnValue = false; | ||
+ | |||
+ | // | ||
+ | if (e.stopPropagation) { | ||
+ | e.stopPropagation(); | ||
+ | e.preventDefault(); | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | this.all_shortcuts[shortcut_combination] = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }; | ||
+ | //Attach the function with the event | ||
+ | if(ele.addEventListener) ele.addEventListener(opt[' | ||
+ | else if(ele.attachEvent) ele.attachEvent(' | ||
+ | else ele[' | ||
+ | }, | ||
+ | |||
+ | //Remove the shortcut - just specify the shortcut and I will remove the binding | ||
+ | ' | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | var binding = this.all_shortcuts[shortcut_combination]; | ||
+ | delete(this.all_shortcuts[shortcut_combination]) | ||
+ | if(!binding) return; | ||
+ | var type = binding[' | ||
+ | var ele = binding[' | ||
+ | var callback = binding[' | ||
+ | |||
+ | if(ele.detachEvent) ele.detachEvent(' | ||
+ | else if(ele.removeEventListener) ele.removeEventListener(type, | ||
+ | else ele[' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | shortcut.add(" | ||
+ | var event = new Event(' | ||
+ | if (settingsShown){ | ||
+ | document.getElementById(' | ||
+ | } else { | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | **Array of sizes**: As in the case of colors and labels, you may also specify individual sizes using an array: | ||
+ | |||
+ | <code perl> | ||
+ | > simplex(3)-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Tue Mar 29 16:03:37 2022 | ||
+ | unnamed | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <meta charset=utf-8> | ||
+ | < | ||
+ | < | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | */ | ||
+ | html {overflow: scroll;} | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | # | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_END | ||
+ | */ | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | <div id=' | ||
+ | <div class=group id=' | ||
+ | < | ||
+ | < | ||
+ | <div class=indented>< | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | <div class=suboption> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | <div class=suboption> | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | <select id=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <img id=' | ||
+ | <img id=' | ||
+ | <div id=" | ||
+ | </ | ||
+ | < | ||
+ | requirejs.config({ | ||
+ | paths: { | ||
+ | three: '/ | ||
+ | TrackballControls: | ||
+ | OrbitControls: | ||
+ | Projector: '/ | ||
+ | SVGRenderer: | ||
+ | WEBGL: '/ | ||
+ | }, | ||
+ | shim: { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | }); | ||
+ | | ||
+ | require([' | ||
+ | window.THREE = THREE; | ||
+ | require([' | ||
+ | | ||
+ | THREE.TrackballControls = TrackballControls; | ||
+ | THREE.OrbitControls = OrbitControls; | ||
+ | THREE.Projector = Projector; | ||
+ | THREE.SVGRenderer = SVGRenderer; | ||
+ | THREE.WEBGL = WEBGL; | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | |||
+ | const intervalLength = 25; // for automatic animations | ||
+ | const explodableModel = false; | ||
+ | const modelContains = { points: false, pointlabels: | ||
+ | const foldables = []; | ||
+ | |||
+ | var three = document.getElementById(" | ||
+ | var scene = new THREE.Scene(); | ||
+ | var renderer = new THREE.WebGLRenderer( { antialias: true } ); | ||
+ | var svgRenderer = new THREE.SVGRenderer( { antialias: true } ); | ||
+ | renderer.setPixelRatio( window.devicePixelRatio ); | ||
+ | renderer.setClearColor(0xFFFFFF, | ||
+ | svgRenderer.setClearColor(0xFFFFFF, | ||
+ | three.appendChild(renderer.domElement); | ||
+ | |||
+ | var frustumSize = 4; | ||
+ | var cameras = [new THREE.PerspectiveCamera(75, | ||
+ | cameras.forEach(function(cam) { | ||
+ | cam.position.set(0, | ||
+ | cam.lookAt(0, | ||
+ | cam.up.set(0, | ||
+ | }); | ||
+ | var controls = [new THREE.TrackballControls(cameras[0], | ||
+ | var camera, control; | ||
+ | |||
+ | controls[0].zoomSpeed = 0.2; | ||
+ | controls[0].rotateSpeed = 4; | ||
+ | |||
+ | |||
+ | // class to allow move points together with labels and spheres | ||
+ | var PMPoint = function (x,y,z) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addLabel = function(labelsprite) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addSphere = function(spheremesh) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.set = function(x, | ||
+ | | ||
+ | if (this.sprite) { | ||
+ | this.sprite.position.copy(this.vector); | ||
+ | } | ||
+ | if (this.sphere) { | ||
+ | this.sphere.position.copy(this.vector); | ||
+ | } | ||
+ | } | ||
+ | PMPoint.prototype.radius = function() { | ||
+ | if (this.sphere) { | ||
+ | return this.sphere.geometry.parameters.radius; | ||
+ | } else { | ||
+ | return 0; | ||
+ | } | ||
+ | }; | ||
+ | // select the target node | ||
+ | var target = document.querySelector('# | ||
+ | |||
+ | // create an observer instance | ||
+ | var observer = new MutationObserver(function(mutations) { | ||
+ | | ||
+ | if (mutation.removedNodes && mutation.removedNodes.length > 0) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | // configuration of the observer: | ||
+ | var config = { childList: true, characterData: | ||
+ | |||
+ | // pass in the target node, as well as the observer options | ||
+ | while (target) { | ||
+ | if (target.className==" | ||
+ | observer.observe(target, | ||
+ | break; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | var obj0 = new THREE.Object3D(); | ||
+ | obj0.name = " | ||
+ | obj0.userData.explodable = 1; | ||
+ | obj0.userData.points = []; | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 1)); | ||
+ | |||
+ | obj0.userData.pointradii = [0.02, 0.04, 0.06, 0.08]; | ||
+ | < | ||
+ | obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | obj0.userData.pointlabels = [" | ||
+ | obj0.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[2, 3, 1], [0, 3, 2], [1, 3, 0], [2, 1, 0]]; | ||
+ | < | ||
+ | obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj0); | ||
+ | scene.add(obj0); | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | function textSpriteMaterial(message, | ||
+ | if ( parameters === undefined ) parameters = {}; | ||
+ | var fontface = " | ||
+ | var fontsize = parameters.hasOwnProperty(" | ||
+ | fontsize = fontsize*10; | ||
+ | var lines = message.split(' | ||
+ | var size = 512; | ||
+ | for(var i = 0; i< | ||
+ | var tmp = lines[i].length; | ||
+ | while(tmp*fontsize > size){ | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | var canvas = document.createElement(' | ||
+ | canvas.width = size; | ||
+ | canvas.height = size; | ||
+ | var context = canvas.getContext(' | ||
+ | context.fillStyle = " | ||
+ | context.fill(); | ||
+ | context.font = fontsize + "px " + fontface; | ||
+ | | ||
+ | // text color | ||
+ | context.fillStyle = " | ||
+ | | ||
+ | context.fillText(lines[i], | ||
+ | } | ||
+ | | ||
+ | // canvas contents will be used for a texture | ||
+ | var texture = new THREE.Texture(canvas); | ||
+ | texture.needsUpdate = true; | ||
+ | | ||
+ | var spriteMaterial = new THREE.SpriteMaterial({map: | ||
+ | return spriteMaterial; | ||
+ | } | ||
+ | |||
+ | |||
+ | // ---------------------- INITIALIZING OBJECTS-------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function init_object(obj) { | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_points(obj); | ||
+ | modelContains.points = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_pointlabels(obj); | ||
+ | modelContains.pointlabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_lines(obj); | ||
+ | modelContains.lines = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_edgelabels(obj); | ||
+ | modelContains.edgelabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_arrowheads(obj); | ||
+ | modelContains.arrowheads = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_faces(obj); | ||
+ | modelContains.faces = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function init_points(obj) { | ||
+ | var pointgroup = new THREE.Group(); | ||
+ | pointgroup.name = " | ||
+ | var points = obj.userData.points; | ||
+ | var radii = obj.userData.pointradii; | ||
+ | var materials = obj.userData.pointmaterial; | ||
+ | var geometry, | ||
+ | if (!Array.isArray(radii)) { | ||
+ | geometry = new THREE.SphereBufferGeometry(radii); | ||
+ | } | ||
+ | if (!Array.isArray(materials)) { | ||
+ | material = materials; | ||
+ | } | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | if (Array.isArray(radii)) { | ||
+ | if (radii[i] == 0) { | ||
+ | continue; | ||
+ | } | ||
+ | geometry = new THREE.SphereBufferGeometry(radii[i]); | ||
+ | } | ||
+ | if (Array.isArray(materials)) { | ||
+ | material = materials[i]; | ||
+ | } | ||
+ | var sphere = new THREE.Mesh(geometry, | ||
+ | point.addSphere(sphere); | ||
+ | pointgroup.add(sphere); | ||
+ | } | ||
+ | obj.add(pointgroup); | ||
+ | } | ||
+ | |||
+ | function init_pointlabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var labels = obj.userData.pointlabels; | ||
+ | var pointlabels = new THREE.Group(); | ||
+ | pointlabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(pointlabels); | ||
+ | } | ||
+ | |||
+ | function init_lines(obj) { | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var points = obj.userData.points; | ||
+ | var materials = obj.userData.edgematerial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 ); | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | for (var i=0; i< | ||
+ | geometry.addGroup(2*i, | ||
+ | } | ||
+ | } | ||
+ | var lines = new THREE.LineSegments(geometry, | ||
+ | lines.name = " | ||
+ | obj.add(lines); | ||
+ | updateEdgesPosition(obj); | ||
+ | } | ||
+ | |||
+ | function init_edgelabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var labels = obj.userData.edgelabels; | ||
+ | var edgelabels = new THREE.Group(); | ||
+ | edgelabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(edgelabels); | ||
+ | } | ||
+ | |||
+ | function init_arrowheads(obj) { | ||
+ | var arrowheads = new THREE.Group(); | ||
+ | arrowheads.name = " | ||
+ | var arrowstyle = obj.userData.arrowstyle; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var edgematerials = obj.userData.edgematerial; | ||
+ | var points = obj.userData.points; | ||
+ | var material; | ||
+ | if (!Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials.color} ); | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var start = points[edgeindices[i]]; | ||
+ | var end = points[edgeindices[i+1]]; | ||
+ | var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius(); | ||
+ | if (dist <= 0) { | ||
+ | continue; | ||
+ | } | ||
+ | var dir = new THREE.Vector3().subVectors(end.vector, | ||
+ | dir.normalize(); | ||
+ | var axis = new THREE.Vector3().set(dir.z, | ||
+ | axis.normalize(); | ||
+ | var radians = Math.acos( dir.y ); | ||
+ | var radius = dist/25; | ||
+ | var height = dist/5; | ||
+ | var geometry = new THREE.ConeBufferGeometry(radius, | ||
+ | var position = new THREE.Vector3().addVectors(start.vector, | ||
+ | if (Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} ); | ||
+ | } | ||
+ | var cone = new THREE.Mesh( geometry, material ); | ||
+ | cone.quaternion.setFromAxisAngle(axis, | ||
+ | cone.position.copy(position);; | ||
+ | arrowheads.add(cone); | ||
+ | } | ||
+ | obj.add(arrowheads); | ||
+ | } | ||
+ | |||
+ | function init_faces(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var facets = obj.userData.facets; | ||
+ | obj.userData.triangleindices = []; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | for (var t=0; t< | ||
+ | obj.userData.triangleindices.push(facet[0], | ||
+ | } | ||
+ | } | ||
+ | var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute(bufarr, | ||
+ | | ||
+ | var materials = obj.userData.facetmaterial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var frontmaterials = []; | ||
+ | var backmaterials = []; | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | var tricount = 0; | ||
+ | var facet; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | geometry.addGroup(tricount, | ||
+ | tricount += (facet.length-2)*3; | ||
+ | } | ||
+ | for (var j=0; j< | ||
+ | var fmat = materials[j].clone() | ||
+ | fmat.side = THREE.FrontSide; | ||
+ | frontmaterials.push(fmat); | ||
+ | var bmat = materials[j].clone() | ||
+ | bmat.side = THREE.BackSide; | ||
+ | backmaterials.push(bmat); | ||
+ | obj.userData.facetmaterial = frontmaterials.concat(backmaterials); | ||
+ | } | ||
+ | } else if (materials instanceof THREE.Material) { | ||
+ | frontmaterials = materials.clone() | ||
+ | frontmaterials.side = THREE.FrontSide; | ||
+ | backmaterials = materials.clone() | ||
+ | backmaterials.side = THREE.BackSide; | ||
+ | obj.userData.facetmaterial = [frontmaterials, | ||
+ | } | ||
+ | // duplicating the object with front and back should avoid transparency issues | ||
+ | var backmesh = new THREE.Mesh(geometry, | ||
+ | // meshname is used to show/hide objects | ||
+ | backmesh.name = " | ||
+ | obj.add(backmesh); | ||
+ | var frontmesh = new THREE.Mesh(geometry, | ||
+ | frontmesh.name = " | ||
+ | obj.add(frontmesh); | ||
+ | updateFacesPosition(obj); | ||
+ | } | ||
+ | // // | ||
+ | |||
+ | |||
+ | function updateFacesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.triangleindices; | ||
+ | var faces = obj.getObjectByName(" | ||
+ | var ba = faces.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | faces.geometry.attributes.position.needsUpdate = true; | ||
+ | | ||
+ | } | ||
+ | |||
+ | function updateEdgesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.edgeindices; | ||
+ | var lines = obj.getObjectByName(" | ||
+ | var ba = lines.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | lines.geometry.attributes.position.needsUpdate = true; | ||
+ | } | ||
+ | |||
+ | function onWindowResize() { | ||
+ | renderer.setSize( three.clientWidth, | ||
+ | svgRenderer.setSize( three.clientWidth, | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | function updateCamera() { | ||
+ | var width = three.clientWidth; | ||
+ | var height = three.clientHeight; | ||
+ | var aspect = width / height; | ||
+ | if (camera.type == " | ||
+ | camera.left = frustumSize * aspect / - 2; | ||
+ | camera.right = frustumSize * aspect / 2; | ||
+ | camera.top = frustumSize / 2; | ||
+ | camera.bottom = - frustumSize / 2; | ||
+ | } else if (camera.type == " | ||
+ | camera.aspect = aspect; | ||
+ | } | ||
+ | camera.updateProjectionMatrix(); | ||
+ | } | ||
+ | |||
+ | function changeCamera(event) { | ||
+ | var selindex = event.currentTarget.selectedIndex; | ||
+ | camera = cameras[selindex]; | ||
+ | control = controls[selindex]; | ||
+ | control.enabled = true; | ||
+ | for (var i=0; i< | ||
+ | if (i!=selindex) { | ||
+ | controls[i].enabled = false; | ||
+ | } | ||
+ | } | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | var camtypenode = document.getElementById(' | ||
+ | camtypenode.onchange = changeCamera; | ||
+ | camtypenode.dispatchEvent(new Event(' | ||
+ | |||
+ | onWindowResize(); | ||
+ | window.addEventListener(' | ||
+ | |||
+ | |||
+ | var xRotationEnabled = false; | ||
+ | var yRotationEnabled = false; | ||
+ | var zRotationEnabled = false; | ||
+ | var rotationSpeedFactor = 1; | ||
+ | var settingsShown = false; | ||
+ | var labelsShown = true; | ||
+ | var intervals = []; | ||
+ | var timeouts = []; | ||
+ | var explodingSpeed = 0.05; | ||
+ | var explodeScale = 0.000001; | ||
+ | var XMLS = new XMLSerializer(); | ||
+ | var svgElement; | ||
+ | var renderId; | ||
+ | |||
+ | var render = function () { | ||
+ | |||
+ | renderId = requestAnimationFrame(render); | ||
+ | |||
+ | // comment in for automatic explosion | ||
+ | // | ||
+ | |||
+ | var phi = 0.02 * rotationSpeedFactor; | ||
+ | |||
+ | if (xRotationEnabled) { | ||
+ | scene.rotation.x += phi; | ||
+ | } | ||
+ | if (yRotationEnabled) { | ||
+ | scene.rotation.y += phi; | ||
+ | } | ||
+ | if (zRotationEnabled) { | ||
+ | scene.rotation.z += phi; | ||
+ | } | ||
+ | |||
+ | control.update(); | ||
+ | renderer.render(scene, | ||
+ | }; | ||
+ | |||
+ | if ( THREE.WEBGL.isWebGLAvailable() ) { | ||
+ | render(); | ||
+ | } else { | ||
+ | var warning = WEBGL.getWebGLErrorMessage(); | ||
+ | three.appendChild( warning ); | ||
+ | } | ||
+ | | ||
+ | function changeTransparency() { | ||
+ | var opacity = 1-Number(event.currentTarget.value); | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].opacity = opacity; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.opacity = opacity; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleDepthWrite(event) { | ||
+ | depthwrite = event.currentTarget.checked; | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].depthWrite = depthwrite; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.depthWrite = depthWrite; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function changeRotationX(event){ | ||
+ | xRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationY(event){ | ||
+ | yRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationZ(event){ | ||
+ | zRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | |||
+ | function changeRotationSpeedFactor(event){ | ||
+ | rotationSpeedFactor = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function resetScene(){ | ||
+ | scene.rotation.set(0, | ||
+ | camera.position.set(0, | ||
+ | camera.up.set(0, | ||
+ | } | ||
+ | |||
+ | function showSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = true; | ||
+ | } | ||
+ | |||
+ | function hideSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = false; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | var pos = 150* Math.PI; | ||
+ | |||
+ | function updateFactor() { | ||
+ | pos++; | ||
+ | return Math.sin(.01*pos)+1; | ||
+ | } | ||
+ | |||
+ | // ------------------------ FOLDING ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | // rotate point p around axis defined by points p1 and p2 by given angle | ||
+ | function rotate(p, p1, p2, angle ){ | ||
+ | angle = -angle; | ||
+ | var x = p.x, y = p.y, z = p.z, | ||
+ | a = p1.x, b = p1.y, c = p1.z, | ||
+ | u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z; | ||
+ | var result = []; | ||
+ | var L = u*u + v*v + w*w; | ||
+ | var sqrt = Math.sqrt; | ||
+ | var cos = Math.cos; | ||
+ | var sin = Math.sin; | ||
+ | |||
+ | result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/ | ||
+ | result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/ | ||
+ | result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/ | ||
+ | |||
+ | return result; | ||
+ | } | ||
+ | |||
+ | var fold = function(event){ | ||
+ | var obj = foldables[Number(event.currentTarget.name)]; | ||
+ | var foldvalue = Number(event.currentTarget.value); | ||
+ | var scale = foldvalue - obj.userData.oldscale; | ||
+ | |||
+ | for (var j=0; j< | ||
+ | rotateVertices(obj, | ||
+ | } | ||
+ | update(obj); | ||
+ | obj.userData.oldscale += scale; | ||
+ | lookAtBarycenter(obj); | ||
+ | } | ||
+ | |||
+ | function lookAtBarycenter(obj){ | ||
+ | control.target = barycenter(obj); | ||
+ | } | ||
+ | |||
+ | function barycenter(obj) { | ||
+ | var center = new THREE.Vector3(0, | ||
+ | var points = obj.userData.points; | ||
+ | for (var i=0; i< | ||
+ | center.add(points[i].vector); | ||
+ | } | ||
+ | center.divideScalar(points.length); | ||
+ | return center; | ||
+ | } | ||
+ | |||
+ | function rotateVertices(obj, | ||
+ | var axes = obj.userData.axes; | ||
+ | var subtrees = obj.userData.subtrees; | ||
+ | var points = obj.userData.points; | ||
+ | var angles = obj.userData.angles; | ||
+ | if (edge < axes.length){ | ||
+ | for (var j=0; j< | ||
+ | var rotP = rotate(points[subtrees[edge][j]].vector, | ||
+ | points[subtrees[edge][j]].set(rotP[0], | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function update(obj) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | if (foldables.length) { | ||
+ | var settings = document.getElementById(' | ||
+ | var foldDiv = document.createElement(' | ||
+ | foldDiv.id = ' | ||
+ | var title = document.createElement(' | ||
+ | title.innerHTML = ' | ||
+ | foldDiv.appendChild(title); | ||
+ | foldDiv.className = ' | ||
+ | for (var i=0; i< | ||
+ | var range = document.createElement(' | ||
+ | range.type = ' | ||
+ | range.min = 0; | ||
+ | range.max = 1; | ||
+ | range.value = 0; | ||
+ | range.step = 0.001; | ||
+ | range.name = String(i); | ||
+ | range.oninput = fold; | ||
+ | foldDiv.appendChild(range); | ||
+ | } | ||
+ | lookAtBarycenter(foldables[0]); | ||
+ | settings.insertBefore(foldDiv, | ||
+ | } | ||
+ | |||
+ | | ||
+ | // ---------------------- EXPLOSION ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | if (explodableModel) { | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | if ( obj.userData.explodable ) { | ||
+ | computeCentroid(obj); | ||
+ | } | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | explode(0.000001); | ||
+ | } | ||
+ | |||
+ | function computeCentroid(obj) { | ||
+ | centroid = new THREE.Vector3(); | ||
+ | obj.userData.points.forEach(function(pmpoint) { | ||
+ | centroid.add(pmpoint.vector); | ||
+ | }); | ||
+ | centroid.divideScalar(obj.userData.points.length); | ||
+ | obj.userData.centroid = centroid; | ||
+ | } | ||
+ | |||
+ | function explode(factor) { | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i]; | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | var c = obj.userData.centroid; | ||
+ | obj.position.set(c.x*factor, | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function triggerExplode(event){ | ||
+ | explodeScale = Number(event.currentTarget.value); | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | |||
+ | function setExplodingSpeed(event){ | ||
+ | explodingSpeed = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function triggerAutomaticExplode(event){ | ||
+ | if (event.currentTarget.checked){ | ||
+ | startExploding(); | ||
+ | } else { | ||
+ | clearIntervals(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function startExploding(){ | ||
+ | intervals.push(setInterval(explodingInterval, | ||
+ | } | ||
+ | |||
+ | |||
+ | function explodingInterval(){ | ||
+ | explodeScale += explodingSpeed; | ||
+ | if (explodeScale <= 6){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else{ | ||
+ | explode(6); | ||
+ | explodeScale = 6; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startUnexploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | |||
+ | function startUnexploding(){ | ||
+ | intervals.push(setInterval(unexplodingInterval, | ||
+ | } | ||
+ | |||
+ | function unexplodingInterval(){ | ||
+ | explodeScale -= explodingSpeed; | ||
+ | if (explodeScale >= 0){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else { | ||
+ | explode(0); | ||
+ | explodeScale = 0; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startExploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | function clearIntervals(){ | ||
+ | intervals.forEach(function(interval){ | ||
+ | clearInterval(interval); | ||
+ | }); | ||
+ | intervals = []; | ||
+ | timeouts.forEach(function(timeout){ | ||
+ | clearTimeout(timeout); | ||
+ | }); | ||
+ | timeouts = []; | ||
+ | } | ||
+ | |||
+ | // ---------------------- DISPLAY -------------------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | const objectTypeInnerHTMLs = { points: " | ||
+ | const objectTypeVisible = {}; | ||
+ | Object.assign(objectTypeVisible, | ||
+ | const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort(); | ||
+ | const shownObjectTypesList = document.getElementById(' | ||
+ | |||
+ | function setVisibility(bool, | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i].getObjectByName(objname); | ||
+ | if (obj) { | ||
+ | obj.visible = bool; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleObjectTypeVisibility(event){ | ||
+ | var name = event.currentTarget.name; | ||
+ | var checked = event.currentTarget.checked; | ||
+ | objectTypeVisible[name] = checked; | ||
+ | if (name == " | ||
+ | setVisibility(checked," | ||
+ | setVisibility(checked," | ||
+ | } else { | ||
+ | setVisibility(checked, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var key = sortedObjectTypeKeys[i]; | ||
+ | if (modelContains[key]) { | ||
+ | var objTypeNode = document.createElement(' | ||
+ | objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = key; | ||
+ | checkbox.onchange = toggleObjectTypeVisibility; | ||
+ | shownObjectTypesList.appendChild(checkbox); | ||
+ | shownObjectTypesList.appendChild(objTypeNode); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // ------------------------------------------------------ | ||
+ | |||
+ | function toggleObjectVisibility(event){ | ||
+ | var nr = Number(event.currentTarget.name); | ||
+ | scene.children[nr].visible = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | // append checkboxes for displaying or hiding objects | ||
+ | var shownObjectsList = document.getElementById(' | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | var objNode = document.createElement(' | ||
+ | objNode.innerHTML = obj.name + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = String(i); | ||
+ | checkbox.onchange = toggleObjectVisibility; | ||
+ | shownObjectsList.appendChild(checkbox); | ||
+ | shownObjectsList.appendChild(objNode); | ||
+ | } | ||
+ | |||
+ | // ---------------------- SVG ------------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function takeSvgScreenshot() { | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | svgRenderer.render(scene, | ||
+ | svgElement = XMLS.serializeToString(svgRenderer.domElement); | ||
+ | | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | |||
+ | if (document.getElementById(' | ||
+ | //show in new tab | ||
+ | var myWindow = window.open("","" | ||
+ | myWindow.document.body.innerHTML = svgElement; | ||
+ | } else{ | ||
+ | // download svg file | ||
+ | download(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function download(filename, | ||
+ | var element = document.createElement(' | ||
+ | element.setAttribute(' | ||
+ | element.setAttribute(' | ||
+ | |||
+ | element.style.display = ' | ||
+ | document.body.appendChild(element); | ||
+ | |||
+ | element.click(); | ||
+ | |||
+ | document.body.removeChild(element); | ||
+ | } | ||
+ | |||
+ | |||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | |||
+ | |||
+ | // ------------------ SHORTCUTS -------------------------------------------- | ||
+ | // ------------------------------------------------------------------------- | ||
+ | |||
+ | /** | ||
+ | * http:// | ||
+ | * Version : 2.01.B | ||
+ | * By Binny V A | ||
+ | * License : BSD | ||
+ | */ | ||
+ | shortcut = { | ||
+ | ' | ||
+ | ' | ||
+ | //Provide a set of default options | ||
+ | var default_options = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | if(!opt) opt = default_options; | ||
+ | else { | ||
+ | for(var dfo in default_options) { | ||
+ | if(typeof opt[dfo] == ' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var ele = opt.target; | ||
+ | if(typeof opt.target == ' | ||
+ | var ths = this; | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | |||
+ | //The function to be called at keypress | ||
+ | var func = function(e) { | ||
+ | e = e || window.event; | ||
+ | |||
+ | if(opt[' | ||
+ | var element; | ||
+ | if(e.target) element=e.target; | ||
+ | else if(e.srcElement) element=e.srcElement; | ||
+ | if(element.nodeType==3) element=element.parentNode; | ||
+ | |||
+ | if(element.tagName == ' | ||
+ | } | ||
+ | |||
+ | //Find Which key is pressed | ||
+ | if (e.keyCode) code = e.keyCode; | ||
+ | else if (e.which) code = e.which; | ||
+ | var character = String.fromCharCode(code).toLowerCase(); | ||
+ | |||
+ | if(code == 188) character=","; | ||
+ | if(code == 190) character=" | ||
+ | |||
+ | var keys = shortcut_combination.split(" | ||
+ | //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked | ||
+ | var kp = 0; | ||
+ | |||
+ | //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken | ||
+ | var shift_nums = { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | ";":":", | ||
+ | "'":" | ||
+ | ",":"<", | ||
+ | " | ||
+ | "/":"?", | ||
+ | " | ||
+ | } | ||
+ | // | ||
+ | var special_keys = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | |||
+ | var modifiers = { | ||
+ | shift: { wanted: | ||
+ | ctrl : { wanted: | ||
+ | alt | ||
+ | meta : { wanted: | ||
+ | }; | ||
+ | | ||
+ | if(e.ctrlKey) modifiers.ctrl.pressed = true; | ||
+ | if(e.shiftKey) modifiers.shift.pressed = true; | ||
+ | if(e.altKey) modifiers.alt.pressed = true; | ||
+ | if(e.metaKey) | ||
+ | | ||
+ | for(var i=0; k=keys[i], | ||
+ | // | ||
+ | if(k == ' | ||
+ | kp++; | ||
+ | modifiers.ctrl.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.shift.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.alt.wanted = true; | ||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.meta.wanted = true; | ||
+ | } else if(k.length > 1) { //If it is a special key | ||
+ | if(special_keys[k] == code) kp++; | ||
+ | |||
+ | } else if(opt[' | ||
+ | if(opt[' | ||
+ | |||
+ | } else { //The special keys did not match | ||
+ | if(character == k) kp++; | ||
+ | else { | ||
+ | if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase | ||
+ | character = shift_nums[character]; | ||
+ | if(character == k) kp++; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if(kp == keys.length && | ||
+ | modifiers.ctrl.pressed == modifiers.ctrl.wanted && | ||
+ | modifiers.shift.pressed == modifiers.shift.wanted && | ||
+ | modifiers.alt.pressed == modifiers.alt.wanted && | ||
+ | modifiers.meta.pressed == modifiers.meta.wanted) { | ||
+ | callback(e); | ||
+ | |||
+ | if(!opt[' | ||
+ | // | ||
+ | e.cancelBubble = true; | ||
+ | e.returnValue = false; | ||
+ | |||
+ | // | ||
+ | if (e.stopPropagation) { | ||
+ | e.stopPropagation(); | ||
+ | e.preventDefault(); | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | this.all_shortcuts[shortcut_combination] = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }; | ||
+ | //Attach the function with the event | ||
+ | if(ele.addEventListener) ele.addEventListener(opt[' | ||
+ | else if(ele.attachEvent) ele.attachEvent(' | ||
+ | else ele[' | ||
+ | }, | ||
+ | |||
+ | //Remove the shortcut - just specify the shortcut and I will remove the binding | ||
+ | ' | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | var binding = this.all_shortcuts[shortcut_combination]; | ||
+ | delete(this.all_shortcuts[shortcut_combination]) | ||
+ | if(!binding) return; | ||
+ | var type = binding[' | ||
+ | var ele = binding[' | ||
+ | var callback = binding[' | ||
+ | |||
+ | if(ele.detachEvent) ele.detachEvent(' | ||
+ | else if(ele.removeEventListener) ele.removeEventListener(type, | ||
+ | else ele[' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | shortcut.add(" | ||
+ | var event = new Event(' | ||
+ | if (settingsShown){ | ||
+ | document.getElementById(' | ||
+ | } else { | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | **Function**: | ||
+ | |||
+ | <code perl> | ||
+ | > cube(3)-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Tue Mar 29 16:03:37 2022 | ||
+ | unnamed | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <meta charset=utf-8> | ||
+ | < | ||
+ | < | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | */ | ||
+ | html {overflow: scroll;} | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | # | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_END | ||
+ | */ | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | <div id=' | ||
+ | <div class=group id=' | ||
+ | < | ||
+ | < | ||
+ | <div class=indented>< | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | <div class=suboption> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | <div class=suboption> | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | <select id=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <img id=' | ||
+ | <img id=' | ||
+ | <div id=" | ||
+ | </ | ||
+ | < | ||
+ | requirejs.config({ | ||
+ | paths: { | ||
+ | three: '/ | ||
+ | TrackballControls: | ||
+ | OrbitControls: | ||
+ | Projector: '/ | ||
+ | SVGRenderer: | ||
+ | WEBGL: '/ | ||
+ | }, | ||
+ | shim: { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | }); | ||
+ | | ||
+ | require([' | ||
+ | window.THREE = THREE; | ||
+ | require([' | ||
+ | | ||
+ | THREE.TrackballControls = TrackballControls; | ||
+ | THREE.OrbitControls = OrbitControls; | ||
+ | THREE.Projector = Projector; | ||
+ | THREE.SVGRenderer = SVGRenderer; | ||
+ | THREE.WEBGL = WEBGL; | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | |||
+ | const intervalLength = 25; // for automatic animations | ||
+ | const explodableModel = false; | ||
+ | const modelContains = { points: false, pointlabels: | ||
+ | const foldables = []; | ||
+ | |||
+ | var three = document.getElementById(" | ||
+ | var scene = new THREE.Scene(); | ||
+ | var renderer = new THREE.WebGLRenderer( { antialias: true } ); | ||
+ | var svgRenderer = new THREE.SVGRenderer( { antialias: true } ); | ||
+ | renderer.setPixelRatio( window.devicePixelRatio ); | ||
+ | renderer.setClearColor(0xFFFFFF, | ||
+ | svgRenderer.setClearColor(0xFFFFFF, | ||
+ | three.appendChild(renderer.domElement); | ||
+ | |||
+ | var frustumSize = 4; | ||
+ | var cameras = [new THREE.PerspectiveCamera(75, | ||
+ | cameras.forEach(function(cam) { | ||
+ | cam.position.set(0, | ||
+ | cam.lookAt(0, | ||
+ | cam.up.set(0, | ||
+ | }); | ||
+ | var controls = [new THREE.TrackballControls(cameras[0], | ||
+ | var camera, control; | ||
+ | |||
+ | controls[0].zoomSpeed = 0.2; | ||
+ | controls[0].rotateSpeed = 4; | ||
+ | |||
+ | |||
+ | // class to allow move points together with labels and spheres | ||
+ | var PMPoint = function (x,y,z) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addLabel = function(labelsprite) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addSphere = function(spheremesh) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.set = function(x, | ||
+ | | ||
+ | if (this.sprite) { | ||
+ | this.sprite.position.copy(this.vector); | ||
+ | } | ||
+ | if (this.sphere) { | ||
+ | this.sphere.position.copy(this.vector); | ||
+ | } | ||
+ | } | ||
+ | PMPoint.prototype.radius = function() { | ||
+ | if (this.sphere) { | ||
+ | return this.sphere.geometry.parameters.radius; | ||
+ | } else { | ||
+ | return 0; | ||
+ | } | ||
+ | }; | ||
+ | // select the target node | ||
+ | var target = document.querySelector('# | ||
+ | |||
+ | // create an observer instance | ||
+ | var observer = new MutationObserver(function(mutations) { | ||
+ | | ||
+ | if (mutation.removedNodes && mutation.removedNodes.length > 0) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | // configuration of the observer: | ||
+ | var config = { childList: true, characterData: | ||
+ | |||
+ | // pass in the target node, as well as the observer options | ||
+ | while (target) { | ||
+ | if (target.className==" | ||
+ | observer.observe(target, | ||
+ | break; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | var obj0 = new THREE.Object3D(); | ||
+ | obj0.name = " | ||
+ | obj0.userData.explodable = 1; | ||
+ | obj0.userData.points = []; | ||
+ | obj0.userData.points.push(new PMPoint(-1, -1, -1)); | ||
+ | obj0.userData.points.push(new PMPoint(1, -1, -1)); | ||
+ | obj0.userData.points.push(new PMPoint(-1, 1, -1)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 1, -1)); | ||
+ | obj0.userData.points.push(new PMPoint(-1, -1, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(1, -1, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(-1, 1, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 1, 1)); | ||
+ | |||
+ | obj0.userData.pointradii = [0.04, 0.02, 0.04, 0.02, 0.04, 0.02, 0.04, 0.02]; | ||
+ | < | ||
+ | obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | obj0.userData.pointlabels = [" | ||
+ | obj0.userData.edgeindices = [0, 1, 0, 2, 1, 3, 2, 3, 0, 4, 1, 5, 4, 5, 2, 6, 4, 6, 3, 7, 5, 7, 6, 7]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[0, 4, 6, 2], [7, 5, 1, 3], [5, 4, 0, 1], [2, 6, 7, 3], [0, 2, 3, 1], [6, 4, 5, 7]]; | ||
+ | < | ||
+ | obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj0); | ||
+ | scene.add(obj0); | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | function textSpriteMaterial(message, | ||
+ | if ( parameters === undefined ) parameters = {}; | ||
+ | var fontface = " | ||
+ | var fontsize = parameters.hasOwnProperty(" | ||
+ | fontsize = fontsize*10; | ||
+ | var lines = message.split(' | ||
+ | var size = 512; | ||
+ | for(var i = 0; i< | ||
+ | var tmp = lines[i].length; | ||
+ | while(tmp*fontsize > size){ | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | var canvas = document.createElement(' | ||
+ | canvas.width = size; | ||
+ | canvas.height = size; | ||
+ | var context = canvas.getContext(' | ||
+ | context.fillStyle = " | ||
+ | context.fill(); | ||
+ | context.font = fontsize + "px " + fontface; | ||
+ | | ||
+ | // text color | ||
+ | context.fillStyle = " | ||
+ | | ||
+ | context.fillText(lines[i], | ||
+ | } | ||
+ | | ||
+ | // canvas contents will be used for a texture | ||
+ | var texture = new THREE.Texture(canvas); | ||
+ | texture.needsUpdate = true; | ||
+ | | ||
+ | var spriteMaterial = new THREE.SpriteMaterial({map: | ||
+ | return spriteMaterial; | ||
+ | } | ||
+ | |||
+ | |||
+ | // ---------------------- INITIALIZING OBJECTS-------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function init_object(obj) { | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_points(obj); | ||
+ | modelContains.points = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_pointlabels(obj); | ||
+ | modelContains.pointlabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_lines(obj); | ||
+ | modelContains.lines = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_edgelabels(obj); | ||
+ | modelContains.edgelabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_arrowheads(obj); | ||
+ | modelContains.arrowheads = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_faces(obj); | ||
+ | modelContains.faces = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function init_points(obj) { | ||
+ | var pointgroup = new THREE.Group(); | ||
+ | pointgroup.name = " | ||
+ | var points = obj.userData.points; | ||
+ | var radii = obj.userData.pointradii; | ||
+ | var materials = obj.userData.pointmaterial; | ||
+ | var geometry, | ||
+ | if (!Array.isArray(radii)) { | ||
+ | geometry = new THREE.SphereBufferGeometry(radii); | ||
+ | } | ||
+ | if (!Array.isArray(materials)) { | ||
+ | material = materials; | ||
+ | } | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | if (Array.isArray(radii)) { | ||
+ | if (radii[i] == 0) { | ||
+ | continue; | ||
+ | } | ||
+ | geometry = new THREE.SphereBufferGeometry(radii[i]); | ||
+ | } | ||
+ | if (Array.isArray(materials)) { | ||
+ | material = materials[i]; | ||
+ | } | ||
+ | var sphere = new THREE.Mesh(geometry, | ||
+ | point.addSphere(sphere); | ||
+ | pointgroup.add(sphere); | ||
+ | } | ||
+ | obj.add(pointgroup); | ||
+ | } | ||
+ | |||
+ | function init_pointlabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var labels = obj.userData.pointlabels; | ||
+ | var pointlabels = new THREE.Group(); | ||
+ | pointlabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(pointlabels); | ||
+ | } | ||
+ | |||
+ | function init_lines(obj) { | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var points = obj.userData.points; | ||
+ | var materials = obj.userData.edgematerial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 ); | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | for (var i=0; i< | ||
+ | geometry.addGroup(2*i, | ||
+ | } | ||
+ | } | ||
+ | var lines = new THREE.LineSegments(geometry, | ||
+ | lines.name = " | ||
+ | obj.add(lines); | ||
+ | updateEdgesPosition(obj); | ||
+ | } | ||
+ | |||
+ | function init_edgelabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var labels = obj.userData.edgelabels; | ||
+ | var edgelabels = new THREE.Group(); | ||
+ | edgelabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(edgelabels); | ||
+ | } | ||
+ | |||
+ | function init_arrowheads(obj) { | ||
+ | var arrowheads = new THREE.Group(); | ||
+ | arrowheads.name = " | ||
+ | var arrowstyle = obj.userData.arrowstyle; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var edgematerials = obj.userData.edgematerial; | ||
+ | var points = obj.userData.points; | ||
+ | var material; | ||
+ | if (!Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials.color} ); | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var start = points[edgeindices[i]]; | ||
+ | var end = points[edgeindices[i+1]]; | ||
+ | var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius(); | ||
+ | if (dist <= 0) { | ||
+ | continue; | ||
+ | } | ||
+ | var dir = new THREE.Vector3().subVectors(end.vector, | ||
+ | dir.normalize(); | ||
+ | var axis = new THREE.Vector3().set(dir.z, | ||
+ | axis.normalize(); | ||
+ | var radians = Math.acos( dir.y ); | ||
+ | var radius = dist/25; | ||
+ | var height = dist/5; | ||
+ | var geometry = new THREE.ConeBufferGeometry(radius, | ||
+ | var position = new THREE.Vector3().addVectors(start.vector, | ||
+ | if (Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} ); | ||
+ | } | ||
+ | var cone = new THREE.Mesh( geometry, material ); | ||
+ | cone.quaternion.setFromAxisAngle(axis, | ||
+ | cone.position.copy(position);; | ||
+ | arrowheads.add(cone); | ||
+ | } | ||
+ | obj.add(arrowheads); | ||
+ | } | ||
+ | |||
+ | function init_faces(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var facets = obj.userData.facets; | ||
+ | obj.userData.triangleindices = []; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | for (var t=0; t< | ||
+ | obj.userData.triangleindices.push(facet[0], | ||
+ | } | ||
+ | } | ||
+ | var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute(bufarr, | ||
+ | | ||
+ | var materials = obj.userData.facetmaterial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var frontmaterials = []; | ||
+ | var backmaterials = []; | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | var tricount = 0; | ||
+ | var facet; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | geometry.addGroup(tricount, | ||
+ | tricount += (facet.length-2)*3; | ||
+ | } | ||
+ | for (var j=0; j< | ||
+ | var fmat = materials[j].clone() | ||
+ | fmat.side = THREE.FrontSide; | ||
+ | frontmaterials.push(fmat); | ||
+ | var bmat = materials[j].clone() | ||
+ | bmat.side = THREE.BackSide; | ||
+ | backmaterials.push(bmat); | ||
+ | obj.userData.facetmaterial = frontmaterials.concat(backmaterials); | ||
+ | } | ||
+ | } else if (materials instanceof THREE.Material) { | ||
+ | frontmaterials = materials.clone() | ||
+ | frontmaterials.side = THREE.FrontSide; | ||
+ | backmaterials = materials.clone() | ||
+ | backmaterials.side = THREE.BackSide; | ||
+ | obj.userData.facetmaterial = [frontmaterials, | ||
+ | } | ||
+ | // duplicating the object with front and back should avoid transparency issues | ||
+ | var backmesh = new THREE.Mesh(geometry, | ||
+ | // meshname is used to show/hide objects | ||
+ | backmesh.name = " | ||
+ | obj.add(backmesh); | ||
+ | var frontmesh = new THREE.Mesh(geometry, | ||
+ | frontmesh.name = " | ||
+ | obj.add(frontmesh); | ||
+ | updateFacesPosition(obj); | ||
+ | } | ||
+ | // // | ||
+ | |||
+ | |||
+ | function updateFacesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.triangleindices; | ||
+ | var faces = obj.getObjectByName(" | ||
+ | var ba = faces.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | faces.geometry.attributes.position.needsUpdate = true; | ||
+ | | ||
+ | } | ||
+ | |||
+ | function updateEdgesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.edgeindices; | ||
+ | var lines = obj.getObjectByName(" | ||
+ | var ba = lines.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | lines.geometry.attributes.position.needsUpdate = true; | ||
+ | } | ||
+ | |||
+ | function onWindowResize() { | ||
+ | renderer.setSize( three.clientWidth, | ||
+ | svgRenderer.setSize( three.clientWidth, | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | function updateCamera() { | ||
+ | var width = three.clientWidth; | ||
+ | var height = three.clientHeight; | ||
+ | var aspect = width / height; | ||
+ | if (camera.type == " | ||
+ | camera.left = frustumSize * aspect / - 2; | ||
+ | camera.right = frustumSize * aspect / 2; | ||
+ | camera.top = frustumSize / 2; | ||
+ | camera.bottom = - frustumSize / 2; | ||
+ | } else if (camera.type == " | ||
+ | camera.aspect = aspect; | ||
+ | } | ||
+ | camera.updateProjectionMatrix(); | ||
+ | } | ||
+ | |||
+ | function changeCamera(event) { | ||
+ | var selindex = event.currentTarget.selectedIndex; | ||
+ | camera = cameras[selindex]; | ||
+ | control = controls[selindex]; | ||
+ | control.enabled = true; | ||
+ | for (var i=0; i< | ||
+ | if (i!=selindex) { | ||
+ | controls[i].enabled = false; | ||
+ | } | ||
+ | } | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | var camtypenode = document.getElementById(' | ||
+ | camtypenode.onchange = changeCamera; | ||
+ | camtypenode.dispatchEvent(new Event(' | ||
+ | |||
+ | onWindowResize(); | ||
+ | window.addEventListener(' | ||
+ | |||
+ | |||
+ | var xRotationEnabled = false; | ||
+ | var yRotationEnabled = false; | ||
+ | var zRotationEnabled = false; | ||
+ | var rotationSpeedFactor = 1; | ||
+ | var settingsShown = false; | ||
+ | var labelsShown = true; | ||
+ | var intervals = []; | ||
+ | var timeouts = []; | ||
+ | var explodingSpeed = 0.05; | ||
+ | var explodeScale = 0.000001; | ||
+ | var XMLS = new XMLSerializer(); | ||
+ | var svgElement; | ||
+ | var renderId; | ||
+ | |||
+ | var render = function () { | ||
+ | |||
+ | renderId = requestAnimationFrame(render); | ||
+ | |||
+ | // comment in for automatic explosion | ||
+ | // | ||
+ | |||
+ | var phi = 0.02 * rotationSpeedFactor; | ||
+ | |||
+ | if (xRotationEnabled) { | ||
+ | scene.rotation.x += phi; | ||
+ | } | ||
+ | if (yRotationEnabled) { | ||
+ | scene.rotation.y += phi; | ||
+ | } | ||
+ | if (zRotationEnabled) { | ||
+ | scene.rotation.z += phi; | ||
+ | } | ||
+ | |||
+ | control.update(); | ||
+ | renderer.render(scene, | ||
+ | }; | ||
+ | |||
+ | if ( THREE.WEBGL.isWebGLAvailable() ) { | ||
+ | render(); | ||
+ | } else { | ||
+ | var warning = WEBGL.getWebGLErrorMessage(); | ||
+ | three.appendChild( warning ); | ||
+ | } | ||
+ | | ||
+ | function changeTransparency() { | ||
+ | var opacity = 1-Number(event.currentTarget.value); | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].opacity = opacity; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.opacity = opacity; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleDepthWrite(event) { | ||
+ | depthwrite = event.currentTarget.checked; | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].depthWrite = depthwrite; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.depthWrite = depthWrite; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function changeRotationX(event){ | ||
+ | xRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationY(event){ | ||
+ | yRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationZ(event){ | ||
+ | zRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | |||
+ | function changeRotationSpeedFactor(event){ | ||
+ | rotationSpeedFactor = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function resetScene(){ | ||
+ | scene.rotation.set(0, | ||
+ | camera.position.set(0, | ||
+ | camera.up.set(0, | ||
+ | } | ||
+ | |||
+ | function showSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = true; | ||
+ | } | ||
+ | |||
+ | function hideSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = false; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | var pos = 150* Math.PI; | ||
+ | |||
+ | function updateFactor() { | ||
+ | pos++; | ||
+ | return Math.sin(.01*pos)+1; | ||
+ | } | ||
+ | |||
+ | // ------------------------ FOLDING ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | // rotate point p around axis defined by points p1 and p2 by given angle | ||
+ | function rotate(p, p1, p2, angle ){ | ||
+ | angle = -angle; | ||
+ | var x = p.x, y = p.y, z = p.z, | ||
+ | a = p1.x, b = p1.y, c = p1.z, | ||
+ | u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z; | ||
+ | var result = []; | ||
+ | var L = u*u + v*v + w*w; | ||
+ | var sqrt = Math.sqrt; | ||
+ | var cos = Math.cos; | ||
+ | var sin = Math.sin; | ||
+ | |||
+ | result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/ | ||
+ | result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/ | ||
+ | result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/ | ||
+ | |||
+ | return result; | ||
+ | } | ||
+ | |||
+ | var fold = function(event){ | ||
+ | var obj = foldables[Number(event.currentTarget.name)]; | ||
+ | var foldvalue = Number(event.currentTarget.value); | ||
+ | var scale = foldvalue - obj.userData.oldscale; | ||
+ | |||
+ | for (var j=0; j< | ||
+ | rotateVertices(obj, | ||
+ | } | ||
+ | update(obj); | ||
+ | obj.userData.oldscale += scale; | ||
+ | lookAtBarycenter(obj); | ||
+ | } | ||
+ | |||
+ | function lookAtBarycenter(obj){ | ||
+ | control.target = barycenter(obj); | ||
+ | } | ||
+ | |||
+ | function barycenter(obj) { | ||
+ | var center = new THREE.Vector3(0, | ||
+ | var points = obj.userData.points; | ||
+ | for (var i=0; i< | ||
+ | center.add(points[i].vector); | ||
+ | } | ||
+ | center.divideScalar(points.length); | ||
+ | return center; | ||
+ | } | ||
+ | |||
+ | function rotateVertices(obj, | ||
+ | var axes = obj.userData.axes; | ||
+ | var subtrees = obj.userData.subtrees; | ||
+ | var points = obj.userData.points; | ||
+ | var angles = obj.userData.angles; | ||
+ | if (edge < axes.length){ | ||
+ | for (var j=0; j< | ||
+ | var rotP = rotate(points[subtrees[edge][j]].vector, | ||
+ | points[subtrees[edge][j]].set(rotP[0], | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function update(obj) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | if (foldables.length) { | ||
+ | var settings = document.getElementById(' | ||
+ | var foldDiv = document.createElement(' | ||
+ | foldDiv.id = ' | ||
+ | var title = document.createElement(' | ||
+ | title.innerHTML = ' | ||
+ | foldDiv.appendChild(title); | ||
+ | foldDiv.className = ' | ||
+ | for (var i=0; i< | ||
+ | var range = document.createElement(' | ||
+ | range.type = ' | ||
+ | range.min = 0; | ||
+ | range.max = 1; | ||
+ | range.value = 0; | ||
+ | range.step = 0.001; | ||
+ | range.name = String(i); | ||
+ | range.oninput = fold; | ||
+ | foldDiv.appendChild(range); | ||
+ | } | ||
+ | lookAtBarycenter(foldables[0]); | ||
+ | settings.insertBefore(foldDiv, | ||
+ | } | ||
+ | |||
+ | | ||
+ | // ---------------------- EXPLOSION ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | if (explodableModel) { | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | if ( obj.userData.explodable ) { | ||
+ | computeCentroid(obj); | ||
+ | } | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | explode(0.000001); | ||
+ | } | ||
+ | |||
+ | function computeCentroid(obj) { | ||
+ | centroid = new THREE.Vector3(); | ||
+ | obj.userData.points.forEach(function(pmpoint) { | ||
+ | centroid.add(pmpoint.vector); | ||
+ | }); | ||
+ | centroid.divideScalar(obj.userData.points.length); | ||
+ | obj.userData.centroid = centroid; | ||
+ | } | ||
+ | |||
+ | function explode(factor) { | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i]; | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | var c = obj.userData.centroid; | ||
+ | obj.position.set(c.x*factor, | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function triggerExplode(event){ | ||
+ | explodeScale = Number(event.currentTarget.value); | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | |||
+ | function setExplodingSpeed(event){ | ||
+ | explodingSpeed = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function triggerAutomaticExplode(event){ | ||
+ | if (event.currentTarget.checked){ | ||
+ | startExploding(); | ||
+ | } else { | ||
+ | clearIntervals(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function startExploding(){ | ||
+ | intervals.push(setInterval(explodingInterval, | ||
+ | } | ||
+ | |||
+ | |||
+ | function explodingInterval(){ | ||
+ | explodeScale += explodingSpeed; | ||
+ | if (explodeScale <= 6){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else{ | ||
+ | explode(6); | ||
+ | explodeScale = 6; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startUnexploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | |||
+ | function startUnexploding(){ | ||
+ | intervals.push(setInterval(unexplodingInterval, | ||
+ | } | ||
+ | |||
+ | function unexplodingInterval(){ | ||
+ | explodeScale -= explodingSpeed; | ||
+ | if (explodeScale >= 0){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else { | ||
+ | explode(0); | ||
+ | explodeScale = 0; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startExploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | function clearIntervals(){ | ||
+ | intervals.forEach(function(interval){ | ||
+ | clearInterval(interval); | ||
+ | }); | ||
+ | intervals = []; | ||
+ | timeouts.forEach(function(timeout){ | ||
+ | clearTimeout(timeout); | ||
+ | }); | ||
+ | timeouts = []; | ||
+ | } | ||
+ | |||
+ | // ---------------------- DISPLAY -------------------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | const objectTypeInnerHTMLs = { points: " | ||
+ | const objectTypeVisible = {}; | ||
+ | Object.assign(objectTypeVisible, | ||
+ | const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort(); | ||
+ | const shownObjectTypesList = document.getElementById(' | ||
+ | |||
+ | function setVisibility(bool, | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i].getObjectByName(objname); | ||
+ | if (obj) { | ||
+ | obj.visible = bool; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleObjectTypeVisibility(event){ | ||
+ | var name = event.currentTarget.name; | ||
+ | var checked = event.currentTarget.checked; | ||
+ | objectTypeVisible[name] = checked; | ||
+ | if (name == " | ||
+ | setVisibility(checked," | ||
+ | setVisibility(checked," | ||
+ | } else { | ||
+ | setVisibility(checked, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var key = sortedObjectTypeKeys[i]; | ||
+ | if (modelContains[key]) { | ||
+ | var objTypeNode = document.createElement(' | ||
+ | objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = key; | ||
+ | checkbox.onchange = toggleObjectTypeVisibility; | ||
+ | shownObjectTypesList.appendChild(checkbox); | ||
+ | shownObjectTypesList.appendChild(objTypeNode); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // ------------------------------------------------------ | ||
+ | |||
+ | function toggleObjectVisibility(event){ | ||
+ | var nr = Number(event.currentTarget.name); | ||
+ | scene.children[nr].visible = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | // append checkboxes for displaying or hiding objects | ||
+ | var shownObjectsList = document.getElementById(' | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | var objNode = document.createElement(' | ||
+ | objNode.innerHTML = obj.name + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = String(i); | ||
+ | checkbox.onchange = toggleObjectVisibility; | ||
+ | shownObjectsList.appendChild(checkbox); | ||
+ | shownObjectsList.appendChild(objNode); | ||
+ | } | ||
+ | |||
+ | // ---------------------- SVG ------------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function takeSvgScreenshot() { | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | svgRenderer.render(scene, | ||
+ | svgElement = XMLS.serializeToString(svgRenderer.domElement); | ||
+ | | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | |||
+ | if (document.getElementById(' | ||
+ | //show in new tab | ||
+ | var myWindow = window.open("","" | ||
+ | myWindow.document.body.innerHTML = svgElement; | ||
+ | } else{ | ||
+ | // download svg file | ||
+ | download(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function download(filename, | ||
+ | var element = document.createElement(' | ||
+ | element.setAttribute(' | ||
+ | element.setAttribute(' | ||
+ | |||
+ | element.style.display = ' | ||
+ | document.body.appendChild(element); | ||
+ | |||
+ | element.click(); | ||
+ | |||
+ | document.body.removeChild(element); | ||
+ | } | ||
+ | |||
+ | |||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | |||
+ | |||
+ | // ------------------ SHORTCUTS -------------------------------------------- | ||
+ | // ------------------------------------------------------------------------- | ||
+ | |||
+ | /** | ||
+ | * http:// | ||
+ | * Version : 2.01.B | ||
+ | * By Binny V A | ||
+ | * License : BSD | ||
+ | */ | ||
+ | shortcut = { | ||
+ | ' | ||
+ | ' | ||
+ | //Provide a set of default options | ||
+ | var default_options = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | if(!opt) opt = default_options; | ||
+ | else { | ||
+ | for(var dfo in default_options) { | ||
+ | if(typeof opt[dfo] == ' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var ele = opt.target; | ||
+ | if(typeof opt.target == ' | ||
+ | var ths = this; | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | |||
+ | //The function to be called at keypress | ||
+ | var func = function(e) { | ||
+ | e = e || window.event; | ||
+ | |||
+ | if(opt[' | ||
+ | var element; | ||
+ | if(e.target) element=e.target; | ||
+ | else if(e.srcElement) element=e.srcElement; | ||
+ | if(element.nodeType==3) element=element.parentNode; | ||
+ | |||
+ | if(element.tagName == ' | ||
+ | } | ||
+ | |||
+ | //Find Which key is pressed | ||
+ | if (e.keyCode) code = e.keyCode; | ||
+ | else if (e.which) code = e.which; | ||
+ | var character = String.fromCharCode(code).toLowerCase(); | ||
+ | |||
+ | if(code == 188) character=","; | ||
+ | if(code == 190) character=" | ||
+ | |||
+ | var keys = shortcut_combination.split(" | ||
+ | //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked | ||
+ | var kp = 0; | ||
+ | |||
+ | //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken | ||
+ | var shift_nums = { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | ";":":", | ||
+ | "'":" | ||
+ | ",":"<", | ||
+ | " | ||
+ | "/":"?", | ||
+ | " | ||
+ | } | ||
+ | // | ||
+ | var special_keys = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | |||
+ | var modifiers = { | ||
+ | shift: { wanted: | ||
+ | ctrl : { wanted: | ||
+ | alt | ||
+ | meta : { wanted: | ||
+ | }; | ||
+ | | ||
+ | if(e.ctrlKey) modifiers.ctrl.pressed = true; | ||
+ | if(e.shiftKey) modifiers.shift.pressed = true; | ||
+ | if(e.altKey) modifiers.alt.pressed = true; | ||
+ | if(e.metaKey) | ||
+ | | ||
+ | for(var i=0; k=keys[i], | ||
+ | // | ||
+ | if(k == ' | ||
+ | kp++; | ||
+ | modifiers.ctrl.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.shift.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.alt.wanted = true; | ||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.meta.wanted = true; | ||
+ | } else if(k.length > 1) { //If it is a special key | ||
+ | if(special_keys[k] == code) kp++; | ||
+ | |||
+ | } else if(opt[' | ||
+ | if(opt[' | ||
+ | |||
+ | } else { //The special keys did not match | ||
+ | if(character == k) kp++; | ||
+ | else { | ||
+ | if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase | ||
+ | character = shift_nums[character]; | ||
+ | if(character == k) kp++; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if(kp == keys.length && | ||
+ | modifiers.ctrl.pressed == modifiers.ctrl.wanted && | ||
+ | modifiers.shift.pressed == modifiers.shift.wanted && | ||
+ | modifiers.alt.pressed == modifiers.alt.wanted && | ||
+ | modifiers.meta.pressed == modifiers.meta.wanted) { | ||
+ | callback(e); | ||
+ | |||
+ | if(!opt[' | ||
+ | // | ||
+ | e.cancelBubble = true; | ||
+ | e.returnValue = false; | ||
+ | |||
+ | // | ||
+ | if (e.stopPropagation) { | ||
+ | e.stopPropagation(); | ||
+ | e.preventDefault(); | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | this.all_shortcuts[shortcut_combination] = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }; | ||
+ | //Attach the function with the event | ||
+ | if(ele.addEventListener) ele.addEventListener(opt[' | ||
+ | else if(ele.attachEvent) ele.attachEvent(' | ||
+ | else ele[' | ||
+ | }, | ||
+ | |||
+ | //Remove the shortcut - just specify the shortcut and I will remove the binding | ||
+ | ' | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | var binding = this.all_shortcuts[shortcut_combination]; | ||
+ | delete(this.all_shortcuts[shortcut_combination]) | ||
+ | if(!binding) return; | ||
+ | var type = binding[' | ||
+ | var ele = binding[' | ||
+ | var callback = binding[' | ||
+ | |||
+ | if(ele.detachEvent) ele.detachEvent(' | ||
+ | else if(ele.removeEventListener) ele.removeEventListener(type, | ||
+ | else ele[' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | shortcut.add(" | ||
+ | var event = new Event(' | ||
+ | if (settingsShown){ | ||
+ | document.getElementById(' | ||
+ | } else { | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | If you do not want to display the vertices at all, you can use the // | ||
+ | |||
+ | <code perl> | ||
+ | > cube(3)-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Tue Mar 29 16:03:37 2022 | ||
+ | unnamed | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <meta charset=utf-8> | ||
+ | < | ||
+ | < | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | */ | ||
+ | html {overflow: scroll;} | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | # | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_END | ||
+ | */ | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | <div id=' | ||
+ | <div class=group id=' | ||
+ | < | ||
+ | < | ||
+ | <div class=indented>< | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | <div class=suboption> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | <div class=suboption> | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | <select id=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <img id=' | ||
+ | <img id=' | ||
+ | <div id=" | ||
+ | </ | ||
+ | < | ||
+ | requirejs.config({ | ||
+ | paths: { | ||
+ | three: '/ | ||
+ | TrackballControls: | ||
+ | OrbitControls: | ||
+ | Projector: '/ | ||
+ | SVGRenderer: | ||
+ | WEBGL: '/ | ||
+ | }, | ||
+ | shim: { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | }); | ||
+ | | ||
+ | require([' | ||
+ | window.THREE = THREE; | ||
+ | require([' | ||
+ | | ||
+ | THREE.TrackballControls = TrackballControls; | ||
+ | THREE.OrbitControls = OrbitControls; | ||
+ | THREE.Projector = Projector; | ||
+ | THREE.SVGRenderer = SVGRenderer; | ||
+ | THREE.WEBGL = WEBGL; | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | |||
+ | const intervalLength = 25; // for automatic animations | ||
+ | const explodableModel = false; | ||
+ | const modelContains = { points: false, pointlabels: | ||
+ | const foldables = []; | ||
+ | |||
+ | var three = document.getElementById(" | ||
+ | var scene = new THREE.Scene(); | ||
+ | var renderer = new THREE.WebGLRenderer( { antialias: true } ); | ||
+ | var svgRenderer = new THREE.SVGRenderer( { antialias: true } ); | ||
+ | renderer.setPixelRatio( window.devicePixelRatio ); | ||
+ | renderer.setClearColor(0xFFFFFF, | ||
+ | svgRenderer.setClearColor(0xFFFFFF, | ||
+ | three.appendChild(renderer.domElement); | ||
+ | |||
+ | var frustumSize = 4; | ||
+ | var cameras = [new THREE.PerspectiveCamera(75, | ||
+ | cameras.forEach(function(cam) { | ||
+ | cam.position.set(0, | ||
+ | cam.lookAt(0, | ||
+ | cam.up.set(0, | ||
+ | }); | ||
+ | var controls = [new THREE.TrackballControls(cameras[0], | ||
+ | var camera, control; | ||
+ | |||
+ | controls[0].zoomSpeed = 0.2; | ||
+ | controls[0].rotateSpeed = 4; | ||
+ | |||
+ | |||
+ | // class to allow move points together with labels and spheres | ||
+ | var PMPoint = function (x,y,z) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addLabel = function(labelsprite) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addSphere = function(spheremesh) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.set = function(x, | ||
+ | | ||
+ | if (this.sprite) { | ||
+ | this.sprite.position.copy(this.vector); | ||
+ | } | ||
+ | if (this.sphere) { | ||
+ | this.sphere.position.copy(this.vector); | ||
+ | } | ||
+ | } | ||
+ | PMPoint.prototype.radius = function() { | ||
+ | if (this.sphere) { | ||
+ | return this.sphere.geometry.parameters.radius; | ||
+ | } else { | ||
+ | return 0; | ||
+ | } | ||
+ | }; | ||
+ | // select the target node | ||
+ | var target = document.querySelector('# | ||
+ | |||
+ | // create an observer instance | ||
+ | var observer = new MutationObserver(function(mutations) { | ||
+ | | ||
+ | if (mutation.removedNodes && mutation.removedNodes.length > 0) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | // configuration of the observer: | ||
+ | var config = { childList: true, characterData: | ||
+ | |||
+ | // pass in the target node, as well as the observer options | ||
+ | while (target) { | ||
+ | if (target.className==" | ||
+ | observer.observe(target, | ||
+ | break; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | var obj0 = new THREE.Object3D(); | ||
+ | obj0.name = " | ||
+ | obj0.userData.explodable = 1; | ||
+ | obj0.userData.points = []; | ||
+ | obj0.userData.points.push(new PMPoint(-1, -1, -1)); | ||
+ | obj0.userData.points.push(new PMPoint(1, -1, -1)); | ||
+ | obj0.userData.points.push(new PMPoint(-1, 1, -1)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 1, -1)); | ||
+ | obj0.userData.points.push(new PMPoint(-1, -1, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(1, -1, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(-1, 1, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 1, 1)); | ||
+ | |||
+ | obj0.userData.edgeindices = [0, 1, 0, 2, 1, 3, 2, 3, 0, 4, 1, 5, 4, 5, 2, 6, 4, 6, 3, 7, 5, 7, 6, 7]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[0, 4, 6, 2], [7, 5, 1, 3], [5, 4, 0, 1], [2, 6, 7, 3], [0, 2, 3, 1], [6, 4, 5, 7]]; | ||
+ | < | ||
+ | obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj0); | ||
+ | scene.add(obj0); | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | function textSpriteMaterial(message, | ||
+ | if ( parameters === undefined ) parameters = {}; | ||
+ | var fontface = " | ||
+ | var fontsize = parameters.hasOwnProperty(" | ||
+ | fontsize = fontsize*10; | ||
+ | var lines = message.split(' | ||
+ | var size = 512; | ||
+ | for(var i = 0; i< | ||
+ | var tmp = lines[i].length; | ||
+ | while(tmp*fontsize > size){ | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | var canvas = document.createElement(' | ||
+ | canvas.width = size; | ||
+ | canvas.height = size; | ||
+ | var context = canvas.getContext(' | ||
+ | context.fillStyle = " | ||
+ | context.fill(); | ||
+ | context.font = fontsize + "px " + fontface; | ||
+ | | ||
+ | // text color | ||
+ | context.fillStyle = " | ||
+ | | ||
+ | context.fillText(lines[i], | ||
+ | } | ||
+ | | ||
+ | // canvas contents will be used for a texture | ||
+ | var texture = new THREE.Texture(canvas); | ||
+ | texture.needsUpdate = true; | ||
+ | | ||
+ | var spriteMaterial = new THREE.SpriteMaterial({map: | ||
+ | return spriteMaterial; | ||
+ | } | ||
+ | |||
+ | |||
+ | // ---------------------- INITIALIZING OBJECTS-------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function init_object(obj) { | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_points(obj); | ||
+ | modelContains.points = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_pointlabels(obj); | ||
+ | modelContains.pointlabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_lines(obj); | ||
+ | modelContains.lines = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_edgelabels(obj); | ||
+ | modelContains.edgelabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_arrowheads(obj); | ||
+ | modelContains.arrowheads = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_faces(obj); | ||
+ | modelContains.faces = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function init_points(obj) { | ||
+ | var pointgroup = new THREE.Group(); | ||
+ | pointgroup.name = " | ||
+ | var points = obj.userData.points; | ||
+ | var radii = obj.userData.pointradii; | ||
+ | var materials = obj.userData.pointmaterial; | ||
+ | var geometry, | ||
+ | if (!Array.isArray(radii)) { | ||
+ | geometry = new THREE.SphereBufferGeometry(radii); | ||
+ | } | ||
+ | if (!Array.isArray(materials)) { | ||
+ | material = materials; | ||
+ | } | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | if (Array.isArray(radii)) { | ||
+ | if (radii[i] == 0) { | ||
+ | continue; | ||
+ | } | ||
+ | geometry = new THREE.SphereBufferGeometry(radii[i]); | ||
+ | } | ||
+ | if (Array.isArray(materials)) { | ||
+ | material = materials[i]; | ||
+ | } | ||
+ | var sphere = new THREE.Mesh(geometry, | ||
+ | point.addSphere(sphere); | ||
+ | pointgroup.add(sphere); | ||
+ | } | ||
+ | obj.add(pointgroup); | ||
+ | } | ||
+ | |||
+ | function init_pointlabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var labels = obj.userData.pointlabels; | ||
+ | var pointlabels = new THREE.Group(); | ||
+ | pointlabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(pointlabels); | ||
+ | } | ||
+ | |||
+ | function init_lines(obj) { | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var points = obj.userData.points; | ||
+ | var materials = obj.userData.edgematerial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 ); | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | for (var i=0; i< | ||
+ | geometry.addGroup(2*i, | ||
+ | } | ||
+ | } | ||
+ | var lines = new THREE.LineSegments(geometry, | ||
+ | lines.name = " | ||
+ | obj.add(lines); | ||
+ | updateEdgesPosition(obj); | ||
+ | } | ||
+ | |||
+ | function init_edgelabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var labels = obj.userData.edgelabels; | ||
+ | var edgelabels = new THREE.Group(); | ||
+ | edgelabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(edgelabels); | ||
+ | } | ||
+ | |||
+ | function init_arrowheads(obj) { | ||
+ | var arrowheads = new THREE.Group(); | ||
+ | arrowheads.name = " | ||
+ | var arrowstyle = obj.userData.arrowstyle; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var edgematerials = obj.userData.edgematerial; | ||
+ | var points = obj.userData.points; | ||
+ | var material; | ||
+ | if (!Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials.color} ); | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var start = points[edgeindices[i]]; | ||
+ | var end = points[edgeindices[i+1]]; | ||
+ | var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius(); | ||
+ | if (dist <= 0) { | ||
+ | continue; | ||
+ | } | ||
+ | var dir = new THREE.Vector3().subVectors(end.vector, | ||
+ | dir.normalize(); | ||
+ | var axis = new THREE.Vector3().set(dir.z, | ||
+ | axis.normalize(); | ||
+ | var radians = Math.acos( dir.y ); | ||
+ | var radius = dist/25; | ||
+ | var height = dist/5; | ||
+ | var geometry = new THREE.ConeBufferGeometry(radius, | ||
+ | var position = new THREE.Vector3().addVectors(start.vector, | ||
+ | if (Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} ); | ||
+ | } | ||
+ | var cone = new THREE.Mesh( geometry, material ); | ||
+ | cone.quaternion.setFromAxisAngle(axis, | ||
+ | cone.position.copy(position);; | ||
+ | arrowheads.add(cone); | ||
+ | } | ||
+ | obj.add(arrowheads); | ||
+ | } | ||
+ | |||
+ | function init_faces(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var facets = obj.userData.facets; | ||
+ | obj.userData.triangleindices = []; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | for (var t=0; t< | ||
+ | obj.userData.triangleindices.push(facet[0], | ||
+ | } | ||
+ | } | ||
+ | var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute(bufarr, | ||
+ | | ||
+ | var materials = obj.userData.facetmaterial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var frontmaterials = []; | ||
+ | var backmaterials = []; | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | var tricount = 0; | ||
+ | var facet; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | geometry.addGroup(tricount, | ||
+ | tricount += (facet.length-2)*3; | ||
+ | } | ||
+ | for (var j=0; j< | ||
+ | var fmat = materials[j].clone() | ||
+ | fmat.side = THREE.FrontSide; | ||
+ | frontmaterials.push(fmat); | ||
+ | var bmat = materials[j].clone() | ||
+ | bmat.side = THREE.BackSide; | ||
+ | backmaterials.push(bmat); | ||
+ | obj.userData.facetmaterial = frontmaterials.concat(backmaterials); | ||
+ | } | ||
+ | } else if (materials instanceof THREE.Material) { | ||
+ | frontmaterials = materials.clone() | ||
+ | frontmaterials.side = THREE.FrontSide; | ||
+ | backmaterials = materials.clone() | ||
+ | backmaterials.side = THREE.BackSide; | ||
+ | obj.userData.facetmaterial = [frontmaterials, | ||
+ | } | ||
+ | // duplicating the object with front and back should avoid transparency issues | ||
+ | var backmesh = new THREE.Mesh(geometry, | ||
+ | // meshname is used to show/hide objects | ||
+ | backmesh.name = " | ||
+ | obj.add(backmesh); | ||
+ | var frontmesh = new THREE.Mesh(geometry, | ||
+ | frontmesh.name = " | ||
+ | obj.add(frontmesh); | ||
+ | updateFacesPosition(obj); | ||
+ | } | ||
+ | // // | ||
+ | |||
+ | |||
+ | function updateFacesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.triangleindices; | ||
+ | var faces = obj.getObjectByName(" | ||
+ | var ba = faces.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | faces.geometry.attributes.position.needsUpdate = true; | ||
+ | | ||
+ | } | ||
+ | |||
+ | function updateEdgesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.edgeindices; | ||
+ | var lines = obj.getObjectByName(" | ||
+ | var ba = lines.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | lines.geometry.attributes.position.needsUpdate = true; | ||
+ | } | ||
+ | |||
+ | function onWindowResize() { | ||
+ | renderer.setSize( three.clientWidth, | ||
+ | svgRenderer.setSize( three.clientWidth, | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | function updateCamera() { | ||
+ | var width = three.clientWidth; | ||
+ | var height = three.clientHeight; | ||
+ | var aspect = width / height; | ||
+ | if (camera.type == " | ||
+ | camera.left = frustumSize * aspect / - 2; | ||
+ | camera.right = frustumSize * aspect / 2; | ||
+ | camera.top = frustumSize / 2; | ||
+ | camera.bottom = - frustumSize / 2; | ||
+ | } else if (camera.type == " | ||
+ | camera.aspect = aspect; | ||
+ | } | ||
+ | camera.updateProjectionMatrix(); | ||
+ | } | ||
+ | |||
+ | function changeCamera(event) { | ||
+ | var selindex = event.currentTarget.selectedIndex; | ||
+ | camera = cameras[selindex]; | ||
+ | control = controls[selindex]; | ||
+ | control.enabled = true; | ||
+ | for (var i=0; i< | ||
+ | if (i!=selindex) { | ||
+ | controls[i].enabled = false; | ||
+ | } | ||
+ | } | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | var camtypenode = document.getElementById(' | ||
+ | camtypenode.onchange = changeCamera; | ||
+ | camtypenode.dispatchEvent(new Event(' | ||
+ | |||
+ | onWindowResize(); | ||
+ | window.addEventListener(' | ||
+ | |||
+ | |||
+ | var xRotationEnabled = false; | ||
+ | var yRotationEnabled = false; | ||
+ | var zRotationEnabled = false; | ||
+ | var rotationSpeedFactor = 1; | ||
+ | var settingsShown = false; | ||
+ | var labelsShown = true; | ||
+ | var intervals = []; | ||
+ | var timeouts = []; | ||
+ | var explodingSpeed = 0.05; | ||
+ | var explodeScale = 0.000001; | ||
+ | var XMLS = new XMLSerializer(); | ||
+ | var svgElement; | ||
+ | var renderId; | ||
+ | |||
+ | var render = function () { | ||
+ | |||
+ | renderId = requestAnimationFrame(render); | ||
+ | |||
+ | // comment in for automatic explosion | ||
+ | // | ||
+ | |||
+ | var phi = 0.02 * rotationSpeedFactor; | ||
+ | |||
+ | if (xRotationEnabled) { | ||
+ | scene.rotation.x += phi; | ||
+ | } | ||
+ | if (yRotationEnabled) { | ||
+ | scene.rotation.y += phi; | ||
+ | } | ||
+ | if (zRotationEnabled) { | ||
+ | scene.rotation.z += phi; | ||
+ | } | ||
+ | |||
+ | control.update(); | ||
+ | renderer.render(scene, | ||
+ | }; | ||
+ | |||
+ | if ( THREE.WEBGL.isWebGLAvailable() ) { | ||
+ | render(); | ||
+ | } else { | ||
+ | var warning = WEBGL.getWebGLErrorMessage(); | ||
+ | three.appendChild( warning ); | ||
+ | } | ||
+ | | ||
+ | function changeTransparency() { | ||
+ | var opacity = 1-Number(event.currentTarget.value); | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].opacity = opacity; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.opacity = opacity; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleDepthWrite(event) { | ||
+ | depthwrite = event.currentTarget.checked; | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].depthWrite = depthwrite; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.depthWrite = depthWrite; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function changeRotationX(event){ | ||
+ | xRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationY(event){ | ||
+ | yRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationZ(event){ | ||
+ | zRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | |||
+ | function changeRotationSpeedFactor(event){ | ||
+ | rotationSpeedFactor = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function resetScene(){ | ||
+ | scene.rotation.set(0, | ||
+ | camera.position.set(0, | ||
+ | camera.up.set(0, | ||
+ | } | ||
+ | |||
+ | function showSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = true; | ||
+ | } | ||
+ | |||
+ | function hideSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = false; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | var pos = 150* Math.PI; | ||
+ | |||
+ | function updateFactor() { | ||
+ | pos++; | ||
+ | return Math.sin(.01*pos)+1; | ||
+ | } | ||
+ | |||
+ | // ------------------------ FOLDING ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | // rotate point p around axis defined by points p1 and p2 by given angle | ||
+ | function rotate(p, p1, p2, angle ){ | ||
+ | angle = -angle; | ||
+ | var x = p.x, y = p.y, z = p.z, | ||
+ | a = p1.x, b = p1.y, c = p1.z, | ||
+ | u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z; | ||
+ | var result = []; | ||
+ | var L = u*u + v*v + w*w; | ||
+ | var sqrt = Math.sqrt; | ||
+ | var cos = Math.cos; | ||
+ | var sin = Math.sin; | ||
+ | |||
+ | result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/ | ||
+ | result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/ | ||
+ | result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/ | ||
+ | |||
+ | return result; | ||
+ | } | ||
+ | |||
+ | var fold = function(event){ | ||
+ | var obj = foldables[Number(event.currentTarget.name)]; | ||
+ | var foldvalue = Number(event.currentTarget.value); | ||
+ | var scale = foldvalue - obj.userData.oldscale; | ||
+ | |||
+ | for (var j=0; j< | ||
+ | rotateVertices(obj, | ||
+ | } | ||
+ | update(obj); | ||
+ | obj.userData.oldscale += scale; | ||
+ | lookAtBarycenter(obj); | ||
+ | } | ||
+ | |||
+ | function lookAtBarycenter(obj){ | ||
+ | control.target = barycenter(obj); | ||
+ | } | ||
+ | |||
+ | function barycenter(obj) { | ||
+ | var center = new THREE.Vector3(0, | ||
+ | var points = obj.userData.points; | ||
+ | for (var i=0; i< | ||
+ | center.add(points[i].vector); | ||
+ | } | ||
+ | center.divideScalar(points.length); | ||
+ | return center; | ||
+ | } | ||
+ | |||
+ | function rotateVertices(obj, | ||
+ | var axes = obj.userData.axes; | ||
+ | var subtrees = obj.userData.subtrees; | ||
+ | var points = obj.userData.points; | ||
+ | var angles = obj.userData.angles; | ||
+ | if (edge < axes.length){ | ||
+ | for (var j=0; j< | ||
+ | var rotP = rotate(points[subtrees[edge][j]].vector, | ||
+ | points[subtrees[edge][j]].set(rotP[0], | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function update(obj) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | if (foldables.length) { | ||
+ | var settings = document.getElementById(' | ||
+ | var foldDiv = document.createElement(' | ||
+ | foldDiv.id = ' | ||
+ | var title = document.createElement(' | ||
+ | title.innerHTML = ' | ||
+ | foldDiv.appendChild(title); | ||
+ | foldDiv.className = ' | ||
+ | for (var i=0; i< | ||
+ | var range = document.createElement(' | ||
+ | range.type = ' | ||
+ | range.min = 0; | ||
+ | range.max = 1; | ||
+ | range.value = 0; | ||
+ | range.step = 0.001; | ||
+ | range.name = String(i); | ||
+ | range.oninput = fold; | ||
+ | foldDiv.appendChild(range); | ||
+ | } | ||
+ | lookAtBarycenter(foldables[0]); | ||
+ | settings.insertBefore(foldDiv, | ||
+ | } | ||
+ | |||
+ | | ||
+ | // ---------------------- EXPLOSION ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | if (explodableModel) { | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | if ( obj.userData.explodable ) { | ||
+ | computeCentroid(obj); | ||
+ | } | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | explode(0.000001); | ||
+ | } | ||
+ | |||
+ | function computeCentroid(obj) { | ||
+ | centroid = new THREE.Vector3(); | ||
+ | obj.userData.points.forEach(function(pmpoint) { | ||
+ | centroid.add(pmpoint.vector); | ||
+ | }); | ||
+ | centroid.divideScalar(obj.userData.points.length); | ||
+ | obj.userData.centroid = centroid; | ||
+ | } | ||
+ | |||
+ | function explode(factor) { | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i]; | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | var c = obj.userData.centroid; | ||
+ | obj.position.set(c.x*factor, | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function triggerExplode(event){ | ||
+ | explodeScale = Number(event.currentTarget.value); | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | |||
+ | function setExplodingSpeed(event){ | ||
+ | explodingSpeed = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function triggerAutomaticExplode(event){ | ||
+ | if (event.currentTarget.checked){ | ||
+ | startExploding(); | ||
+ | } else { | ||
+ | clearIntervals(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function startExploding(){ | ||
+ | intervals.push(setInterval(explodingInterval, | ||
+ | } | ||
+ | |||
+ | |||
+ | function explodingInterval(){ | ||
+ | explodeScale += explodingSpeed; | ||
+ | if (explodeScale <= 6){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else{ | ||
+ | explode(6); | ||
+ | explodeScale = 6; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startUnexploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | |||
+ | function startUnexploding(){ | ||
+ | intervals.push(setInterval(unexplodingInterval, | ||
+ | } | ||
+ | |||
+ | function unexplodingInterval(){ | ||
+ | explodeScale -= explodingSpeed; | ||
+ | if (explodeScale >= 0){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else { | ||
+ | explode(0); | ||
+ | explodeScale = 0; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startExploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | function clearIntervals(){ | ||
+ | intervals.forEach(function(interval){ | ||
+ | clearInterval(interval); | ||
+ | }); | ||
+ | intervals = []; | ||
+ | timeouts.forEach(function(timeout){ | ||
+ | clearTimeout(timeout); | ||
+ | }); | ||
+ | timeouts = []; | ||
+ | } | ||
+ | |||
+ | // ---------------------- DISPLAY -------------------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | const objectTypeInnerHTMLs = { points: " | ||
+ | const objectTypeVisible = {}; | ||
+ | Object.assign(objectTypeVisible, | ||
+ | const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort(); | ||
+ | const shownObjectTypesList = document.getElementById(' | ||
+ | |||
+ | function setVisibility(bool, | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i].getObjectByName(objname); | ||
+ | if (obj) { | ||
+ | obj.visible = bool; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleObjectTypeVisibility(event){ | ||
+ | var name = event.currentTarget.name; | ||
+ | var checked = event.currentTarget.checked; | ||
+ | objectTypeVisible[name] = checked; | ||
+ | if (name == " | ||
+ | setVisibility(checked," | ||
+ | setVisibility(checked," | ||
+ | } else { | ||
+ | setVisibility(checked, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var key = sortedObjectTypeKeys[i]; | ||
+ | if (modelContains[key]) { | ||
+ | var objTypeNode = document.createElement(' | ||
+ | objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = key; | ||
+ | checkbox.onchange = toggleObjectTypeVisibility; | ||
+ | shownObjectTypesList.appendChild(checkbox); | ||
+ | shownObjectTypesList.appendChild(objTypeNode); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // ------------------------------------------------------ | ||
+ | |||
+ | function toggleObjectVisibility(event){ | ||
+ | var nr = Number(event.currentTarget.name); | ||
+ | scene.children[nr].visible = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | // append checkboxes for displaying or hiding objects | ||
+ | var shownObjectsList = document.getElementById(' | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | var objNode = document.createElement(' | ||
+ | objNode.innerHTML = obj.name + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = String(i); | ||
+ | checkbox.onchange = toggleObjectVisibility; | ||
+ | shownObjectsList.appendChild(checkbox); | ||
+ | shownObjectsList.appendChild(objNode); | ||
+ | } | ||
+ | |||
+ | // ---------------------- SVG ------------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function takeSvgScreenshot() { | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | svgRenderer.render(scene, | ||
+ | svgElement = XMLS.serializeToString(svgRenderer.domElement); | ||
+ | | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | |||
+ | if (document.getElementById(' | ||
+ | //show in new tab | ||
+ | var myWindow = window.open("","" | ||
+ | myWindow.document.body.innerHTML = svgElement; | ||
+ | } else{ | ||
+ | // download svg file | ||
+ | download(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function download(filename, | ||
+ | var element = document.createElement(' | ||
+ | element.setAttribute(' | ||
+ | element.setAttribute(' | ||
+ | |||
+ | element.style.display = ' | ||
+ | document.body.appendChild(element); | ||
+ | |||
+ | element.click(); | ||
+ | |||
+ | document.body.removeChild(element); | ||
+ | } | ||
+ | |||
+ | |||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | |||
+ | |||
+ | // ------------------ SHORTCUTS -------------------------------------------- | ||
+ | // ------------------------------------------------------------------------- | ||
+ | |||
+ | /** | ||
+ | * http:// | ||
+ | * Version : 2.01.B | ||
+ | * By Binny V A | ||
+ | * License : BSD | ||
+ | */ | ||
+ | shortcut = { | ||
+ | ' | ||
+ | ' | ||
+ | //Provide a set of default options | ||
+ | var default_options = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | if(!opt) opt = default_options; | ||
+ | else { | ||
+ | for(var dfo in default_options) { | ||
+ | if(typeof opt[dfo] == ' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var ele = opt.target; | ||
+ | if(typeof opt.target == ' | ||
+ | var ths = this; | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | |||
+ | //The function to be called at keypress | ||
+ | var func = function(e) { | ||
+ | e = e || window.event; | ||
+ | |||
+ | if(opt[' | ||
+ | var element; | ||
+ | if(e.target) element=e.target; | ||
+ | else if(e.srcElement) element=e.srcElement; | ||
+ | if(element.nodeType==3) element=element.parentNode; | ||
+ | |||
+ | if(element.tagName == ' | ||
+ | } | ||
+ | |||
+ | //Find Which key is pressed | ||
+ | if (e.keyCode) code = e.keyCode; | ||
+ | else if (e.which) code = e.which; | ||
+ | var character = String.fromCharCode(code).toLowerCase(); | ||
+ | |||
+ | if(code == 188) character=","; | ||
+ | if(code == 190) character=" | ||
+ | |||
+ | var keys = shortcut_combination.split(" | ||
+ | //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked | ||
+ | var kp = 0; | ||
+ | |||
+ | //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken | ||
+ | var shift_nums = { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | ";":":", | ||
+ | "'":" | ||
+ | ",":"<", | ||
+ | " | ||
+ | "/":"?", | ||
+ | " | ||
+ | } | ||
+ | // | ||
+ | var special_keys = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | |||
+ | var modifiers = { | ||
+ | shift: { wanted: | ||
+ | ctrl : { wanted: | ||
+ | alt | ||
+ | meta : { wanted: | ||
+ | }; | ||
+ | | ||
+ | if(e.ctrlKey) modifiers.ctrl.pressed = true; | ||
+ | if(e.shiftKey) modifiers.shift.pressed = true; | ||
+ | if(e.altKey) modifiers.alt.pressed = true; | ||
+ | if(e.metaKey) | ||
+ | | ||
+ | for(var i=0; k=keys[i], | ||
+ | // | ||
+ | if(k == ' | ||
+ | kp++; | ||
+ | modifiers.ctrl.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.shift.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.alt.wanted = true; | ||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.meta.wanted = true; | ||
+ | } else if(k.length > 1) { //If it is a special key | ||
+ | if(special_keys[k] == code) kp++; | ||
+ | |||
+ | } else if(opt[' | ||
+ | if(opt[' | ||
+ | |||
+ | } else { //The special keys did not match | ||
+ | if(character == k) kp++; | ||
+ | else { | ||
+ | if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase | ||
+ | character = shift_nums[character]; | ||
+ | if(character == k) kp++; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if(kp == keys.length && | ||
+ | modifiers.ctrl.pressed == modifiers.ctrl.wanted && | ||
+ | modifiers.shift.pressed == modifiers.shift.wanted && | ||
+ | modifiers.alt.pressed == modifiers.alt.wanted && | ||
+ | modifiers.meta.pressed == modifiers.meta.wanted) { | ||
+ | callback(e); | ||
+ | |||
+ | if(!opt[' | ||
+ | // | ||
+ | e.cancelBubble = true; | ||
+ | e.returnValue = false; | ||
+ | |||
+ | // | ||
+ | if (e.stopPropagation) { | ||
+ | e.stopPropagation(); | ||
+ | e.preventDefault(); | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | this.all_shortcuts[shortcut_combination] = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }; | ||
+ | //Attach the function with the event | ||
+ | if(ele.addEventListener) ele.addEventListener(opt[' | ||
+ | else if(ele.attachEvent) ele.attachEvent(' | ||
+ | else ele[' | ||
+ | }, | ||
+ | |||
+ | //Remove the shortcut - just specify the shortcut and I will remove the binding | ||
+ | ' | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | var binding = this.all_shortcuts[shortcut_combination]; | ||
+ | delete(this.all_shortcuts[shortcut_combination]) | ||
+ | if(!binding) return; | ||
+ | var type = binding[' | ||
+ | var ele = binding[' | ||
+ | var callback = binding[' | ||
+ | |||
+ | if(ele.detachEvent) ele.detachEvent(' | ||
+ | else if(ele.removeEventListener) ele.removeEventListener(type, | ||
+ | else ele[' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | shortcut.add(" | ||
+ | var event = new Event(' | ||
+ | if (settingsShown){ | ||
+ | document.getElementById(' | ||
+ | } else { | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | ==== Visualizing multiple polytopes ==== | ||
+ | |||
+ | The following sequence creates a 0/1-cube and a translate. The final command triggers the joint visualization of both. | ||
+ | |||
+ | <code perl> | ||
+ | > $c1=cube(3, | ||
+ | > $c2=transform($c1, | ||
+ | > compose($c1-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Tue Mar 29 16:03:37 2022 | ||
+ | c1 | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <meta charset=utf-8> | ||
+ | < | ||
+ | < | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | */ | ||
+ | html {overflow: scroll;} | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | # | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_END | ||
+ | */ | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | <div id=' | ||
+ | <div class=group id=' | ||
+ | < | ||
+ | < | ||
+ | <div class=indented>< | ||
+ | <div class=suboption> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | < | ||
+ | <div class=indented>< | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | <div class=suboption> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | <div class=suboption> | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | <select id=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <img id=' | ||
+ | <img id=' | ||
+ | <div id=" | ||
+ | </ | ||
+ | < | ||
+ | requirejs.config({ | ||
+ | paths: { | ||
+ | three: '/ | ||
+ | TrackballControls: | ||
+ | OrbitControls: | ||
+ | Projector: '/ | ||
+ | SVGRenderer: | ||
+ | WEBGL: '/ | ||
+ | }, | ||
+ | shim: { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | }); | ||
+ | | ||
+ | require([' | ||
+ | window.THREE = THREE; | ||
+ | require([' | ||
+ | | ||
+ | THREE.TrackballControls = TrackballControls; | ||
+ | THREE.OrbitControls = OrbitControls; | ||
+ | THREE.Projector = Projector; | ||
+ | THREE.SVGRenderer = SVGRenderer; | ||
+ | THREE.WEBGL = WEBGL; | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | |||
+ | const intervalLength = 25; // for automatic animations | ||
+ | const explodableModel = true; | ||
+ | const modelContains = { points: false, pointlabels: | ||
+ | const foldables = []; | ||
+ | |||
+ | var three = document.getElementById(" | ||
+ | var scene = new THREE.Scene(); | ||
+ | var renderer = new THREE.WebGLRenderer( { antialias: true } ); | ||
+ | var svgRenderer = new THREE.SVGRenderer( { antialias: true } ); | ||
+ | renderer.setPixelRatio( window.devicePixelRatio ); | ||
+ | renderer.setClearColor(0xFFFFFF, | ||
+ | svgRenderer.setClearColor(0xFFFFFF, | ||
+ | three.appendChild(renderer.domElement); | ||
+ | |||
+ | var frustumSize = 4; | ||
+ | var cameras = [new THREE.PerspectiveCamera(75, | ||
+ | cameras.forEach(function(cam) { | ||
+ | cam.position.set(0, | ||
+ | cam.lookAt(0, | ||
+ | cam.up.set(0, | ||
+ | }); | ||
+ | var controls = [new THREE.TrackballControls(cameras[0], | ||
+ | var camera, control; | ||
+ | |||
+ | controls[0].zoomSpeed = 0.2; | ||
+ | controls[0].rotateSpeed = 4; | ||
+ | |||
+ | |||
+ | // class to allow move points together with labels and spheres | ||
+ | var PMPoint = function (x,y,z) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addLabel = function(labelsprite) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addSphere = function(spheremesh) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.set = function(x, | ||
+ | | ||
+ | if (this.sprite) { | ||
+ | this.sprite.position.copy(this.vector); | ||
+ | } | ||
+ | if (this.sphere) { | ||
+ | this.sphere.position.copy(this.vector); | ||
+ | } | ||
+ | } | ||
+ | PMPoint.prototype.radius = function() { | ||
+ | if (this.sphere) { | ||
+ | return this.sphere.geometry.parameters.radius; | ||
+ | } else { | ||
+ | return 0; | ||
+ | } | ||
+ | }; | ||
+ | // select the target node | ||
+ | var target = document.querySelector('# | ||
+ | |||
+ | // create an observer instance | ||
+ | var observer = new MutationObserver(function(mutations) { | ||
+ | | ||
+ | if (mutation.removedNodes && mutation.removedNodes.length > 0) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | // configuration of the observer: | ||
+ | var config = { childList: true, characterData: | ||
+ | |||
+ | // pass in the target node, as well as the observer options | ||
+ | while (target) { | ||
+ | if (target.className==" | ||
+ | observer.observe(target, | ||
+ | break; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | var obj0 = new THREE.Object3D(); | ||
+ | obj0.name = " | ||
+ | obj0.userData.explodable = 1; | ||
+ | obj0.userData.points = []; | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 0, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 1, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 1, 1)); | ||
+ | |||
+ | obj0.userData.pointradii = 0.02; | ||
+ | < | ||
+ | obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | obj0.userData.pointlabels = [" | ||
+ | obj0.userData.edgeindices = [0, 1, 0, 2, 1, 3, 2, 3, 0, 4, 1, 5, 4, 5, 2, 6, 4, 6, 3, 7, 5, 7, 6, 7]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[0, 4, 6, 2], [7, 5, 1, 3], [5, 4, 0, 1], [2, 6, 7, 3], [0, 2, 3, 1], [6, 4, 5, 7]]; | ||
+ | < | ||
+ | obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj0); | ||
+ | scene.add(obj0); | ||
+ | |||
+ | var obj1 = new THREE.Object3D(); | ||
+ | obj1.name = " | ||
+ | obj1.userData.explodable = 1; | ||
+ | obj1.userData.points = []; | ||
+ | obj1.userData.points.push(new PMPoint(-1, 0, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(-1, 1, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 1, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(-1, 0, 1)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 0, 1)); | ||
+ | obj1.userData.points.push(new PMPoint(-1, 1, 1)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 1, 1)); | ||
+ | |||
+ | obj1.userData.pointradii = 0.02; | ||
+ | < | ||
+ | obj1.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | obj1.userData.pointlabels = [" | ||
+ | obj1.userData.edgeindices = [0, 1, 0, 2, 1, 3, 2, 3, 0, 4, 1, 5, 4, 5, 2, 6, 4, 6, 3, 7, 5, 7, 6, 7]; | ||
+ | < | ||
+ | obj1.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj1.userData.facets = [[0, 4, 6, 2], [7, 5, 1, 3], [5, 4, 0, 1], [2, 6, 7, 3], [0, 2, 3, 1], [6, 4, 5, 7]]; | ||
+ | < | ||
+ | obj1.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj1); | ||
+ | scene.add(obj1); | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | function textSpriteMaterial(message, | ||
+ | if ( parameters === undefined ) parameters = {}; | ||
+ | var fontface = " | ||
+ | var fontsize = parameters.hasOwnProperty(" | ||
+ | fontsize = fontsize*10; | ||
+ | var lines = message.split(' | ||
+ | var size = 512; | ||
+ | for(var i = 0; i< | ||
+ | var tmp = lines[i].length; | ||
+ | while(tmp*fontsize > size){ | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | var canvas = document.createElement(' | ||
+ | canvas.width = size; | ||
+ | canvas.height = size; | ||
+ | var context = canvas.getContext(' | ||
+ | context.fillStyle = " | ||
+ | context.fill(); | ||
+ | context.font = fontsize + "px " + fontface; | ||
+ | | ||
+ | // text color | ||
+ | context.fillStyle = " | ||
+ | | ||
+ | context.fillText(lines[i], | ||
+ | } | ||
+ | | ||
+ | // canvas contents will be used for a texture | ||
+ | var texture = new THREE.Texture(canvas); | ||
+ | texture.needsUpdate = true; | ||
+ | | ||
+ | var spriteMaterial = new THREE.SpriteMaterial({map: | ||
+ | return spriteMaterial; | ||
+ | } | ||
+ | |||
+ | |||
+ | // ---------------------- INITIALIZING OBJECTS-------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function init_object(obj) { | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_points(obj); | ||
+ | modelContains.points = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_pointlabels(obj); | ||
+ | modelContains.pointlabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_lines(obj); | ||
+ | modelContains.lines = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_edgelabels(obj); | ||
+ | modelContains.edgelabels = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_arrowheads(obj); | ||
+ | modelContains.arrowheads = true; | ||
+ | } | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | init_faces(obj); | ||
+ | modelContains.faces = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function init_points(obj) { | ||
+ | var pointgroup = new THREE.Group(); | ||
+ | pointgroup.name = " | ||
+ | var points = obj.userData.points; | ||
+ | var radii = obj.userData.pointradii; | ||
+ | var materials = obj.userData.pointmaterial; | ||
+ | var geometry, | ||
+ | if (!Array.isArray(radii)) { | ||
+ | geometry = new THREE.SphereBufferGeometry(radii); | ||
+ | } | ||
+ | if (!Array.isArray(materials)) { | ||
+ | material = materials; | ||
+ | } | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | if (Array.isArray(radii)) { | ||
+ | if (radii[i] == 0) { | ||
+ | continue; | ||
+ | } | ||
+ | geometry = new THREE.SphereBufferGeometry(radii[i]); | ||
+ | } | ||
+ | if (Array.isArray(materials)) { | ||
+ | material = materials[i]; | ||
+ | } | ||
+ | var sphere = new THREE.Mesh(geometry, | ||
+ | point.addSphere(sphere); | ||
+ | pointgroup.add(sphere); | ||
+ | } | ||
+ | obj.add(pointgroup); | ||
+ | } | ||
+ | |||
+ | function init_pointlabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var labels = obj.userData.pointlabels; | ||
+ | var pointlabels = new THREE.Group(); | ||
+ | pointlabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var point = points[i]; | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | point.addLabel(sprite); | ||
+ | pointlabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(pointlabels); | ||
+ | } | ||
+ | |||
+ | function init_lines(obj) { | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var points = obj.userData.points; | ||
+ | var materials = obj.userData.edgematerial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 ); | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | for (var i=0; i< | ||
+ | geometry.addGroup(2*i, | ||
+ | } | ||
+ | } | ||
+ | var lines = new THREE.LineSegments(geometry, | ||
+ | lines.name = " | ||
+ | obj.add(lines); | ||
+ | updateEdgesPosition(obj); | ||
+ | } | ||
+ | |||
+ | function init_edgelabels(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var labels = obj.userData.edgelabels; | ||
+ | var edgelabels = new THREE.Group(); | ||
+ | edgelabels.name = " | ||
+ | if (Array.isArray(labels)) { | ||
+ | for (var i=0; i< | ||
+ | var spriteMaterial = textSpriteMaterial( labels[i] ); | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } else { | ||
+ | var spriteMaterial = textSpriteMaterial( labels ); | ||
+ | for (var i=0; i< | ||
+ | var sprite = new THREE.Sprite(spriteMaterial); | ||
+ | sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[2*i]].vector, | ||
+ | edgelabels.add(sprite); | ||
+ | } | ||
+ | } | ||
+ | obj.add(edgelabels); | ||
+ | } | ||
+ | |||
+ | function init_arrowheads(obj) { | ||
+ | var arrowheads = new THREE.Group(); | ||
+ | arrowheads.name = " | ||
+ | var arrowstyle = obj.userData.arrowstyle; | ||
+ | var edgeindices = obj.userData.edgeindices; | ||
+ | var edgematerials = obj.userData.edgematerial; | ||
+ | var points = obj.userData.points; | ||
+ | var material; | ||
+ | if (!Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials.color} ); | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var start = points[edgeindices[i]]; | ||
+ | var end = points[edgeindices[i+1]]; | ||
+ | var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius(); | ||
+ | if (dist <= 0) { | ||
+ | continue; | ||
+ | } | ||
+ | var dir = new THREE.Vector3().subVectors(end.vector, | ||
+ | dir.normalize(); | ||
+ | var axis = new THREE.Vector3().set(dir.z, | ||
+ | axis.normalize(); | ||
+ | var radians = Math.acos( dir.y ); | ||
+ | var radius = dist/25; | ||
+ | var height = dist/5; | ||
+ | var geometry = new THREE.ConeBufferGeometry(radius, | ||
+ | var position = new THREE.Vector3().addVectors(start.vector, | ||
+ | if (Array.isArray(edgematerials)) { | ||
+ | material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} ); | ||
+ | } | ||
+ | var cone = new THREE.Mesh( geometry, material ); | ||
+ | cone.quaternion.setFromAxisAngle(axis, | ||
+ | cone.position.copy(position);; | ||
+ | arrowheads.add(cone); | ||
+ | } | ||
+ | obj.add(arrowheads); | ||
+ | } | ||
+ | |||
+ | function init_faces(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var facets = obj.userData.facets; | ||
+ | obj.userData.triangleindices = []; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | for (var t=0; t< | ||
+ | obj.userData.triangleindices.push(facet[0], | ||
+ | } | ||
+ | } | ||
+ | var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 ); | ||
+ | var bufattr = new THREE.Float32BufferAttribute(bufarr, | ||
+ | | ||
+ | var materials = obj.userData.facetmaterial; | ||
+ | var geometry = new THREE.BufferGeometry(); | ||
+ | var frontmaterials = []; | ||
+ | var backmaterials = []; | ||
+ | geometry.setAttribute(' | ||
+ | if (Array.isArray(materials)) { | ||
+ | var tricount = 0; | ||
+ | var facet; | ||
+ | for (var i=0; i< | ||
+ | facet = facets[i]; | ||
+ | geometry.addGroup(tricount, | ||
+ | tricount += (facet.length-2)*3; | ||
+ | } | ||
+ | for (var j=0; j< | ||
+ | var fmat = materials[j].clone() | ||
+ | fmat.side = THREE.FrontSide; | ||
+ | frontmaterials.push(fmat); | ||
+ | var bmat = materials[j].clone() | ||
+ | bmat.side = THREE.BackSide; | ||
+ | backmaterials.push(bmat); | ||
+ | obj.userData.facetmaterial = frontmaterials.concat(backmaterials); | ||
+ | } | ||
+ | } else if (materials instanceof THREE.Material) { | ||
+ | frontmaterials = materials.clone() | ||
+ | frontmaterials.side = THREE.FrontSide; | ||
+ | backmaterials = materials.clone() | ||
+ | backmaterials.side = THREE.BackSide; | ||
+ | obj.userData.facetmaterial = [frontmaterials, | ||
+ | } | ||
+ | // duplicating the object with front and back should avoid transparency issues | ||
+ | var backmesh = new THREE.Mesh(geometry, | ||
+ | // meshname is used to show/hide objects | ||
+ | backmesh.name = " | ||
+ | obj.add(backmesh); | ||
+ | var frontmesh = new THREE.Mesh(geometry, | ||
+ | frontmesh.name = " | ||
+ | obj.add(frontmesh); | ||
+ | updateFacesPosition(obj); | ||
+ | } | ||
+ | // // | ||
+ | |||
+ | |||
+ | function updateFacesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.triangleindices; | ||
+ | var faces = obj.getObjectByName(" | ||
+ | var ba = faces.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | faces.geometry.attributes.position.needsUpdate = true; | ||
+ | | ||
+ | } | ||
+ | |||
+ | function updateEdgesPosition(obj) { | ||
+ | var points = obj.userData.points; | ||
+ | var indices = obj.userData.edgeindices; | ||
+ | var lines = obj.getObjectByName(" | ||
+ | var ba = lines.geometry.getAttribute(" | ||
+ | for (var i=0; i< | ||
+ | ba.setXYZ(i, | ||
+ | } | ||
+ | lines.geometry.attributes.position.needsUpdate = true; | ||
+ | } | ||
+ | |||
+ | function onWindowResize() { | ||
+ | renderer.setSize( three.clientWidth, | ||
+ | svgRenderer.setSize( three.clientWidth, | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | function updateCamera() { | ||
+ | var width = three.clientWidth; | ||
+ | var height = three.clientHeight; | ||
+ | var aspect = width / height; | ||
+ | if (camera.type == " | ||
+ | camera.left = frustumSize * aspect / - 2; | ||
+ | camera.right = frustumSize * aspect / 2; | ||
+ | camera.top = frustumSize / 2; | ||
+ | camera.bottom = - frustumSize / 2; | ||
+ | } else if (camera.type == " | ||
+ | camera.aspect = aspect; | ||
+ | } | ||
+ | camera.updateProjectionMatrix(); | ||
+ | } | ||
+ | |||
+ | function changeCamera(event) { | ||
+ | var selindex = event.currentTarget.selectedIndex; | ||
+ | camera = cameras[selindex]; | ||
+ | control = controls[selindex]; | ||
+ | control.enabled = true; | ||
+ | for (var i=0; i< | ||
+ | if (i!=selindex) { | ||
+ | controls[i].enabled = false; | ||
+ | } | ||
+ | } | ||
+ | updateCamera(); | ||
+ | } | ||
+ | |||
+ | var camtypenode = document.getElementById(' | ||
+ | camtypenode.onchange = changeCamera; | ||
+ | camtypenode.dispatchEvent(new Event(' | ||
+ | |||
+ | onWindowResize(); | ||
+ | window.addEventListener(' | ||
+ | |||
+ | |||
+ | var xRotationEnabled = false; | ||
+ | var yRotationEnabled = false; | ||
+ | var zRotationEnabled = false; | ||
+ | var rotationSpeedFactor = 1; | ||
+ | var settingsShown = false; | ||
+ | var labelsShown = true; | ||
+ | var intervals = []; | ||
+ | var timeouts = []; | ||
+ | var explodingSpeed = 0.05; | ||
+ | var explodeScale = 0.000001; | ||
+ | var XMLS = new XMLSerializer(); | ||
+ | var svgElement; | ||
+ | var renderId; | ||
+ | |||
+ | var render = function () { | ||
+ | |||
+ | renderId = requestAnimationFrame(render); | ||
+ | |||
+ | // comment in for automatic explosion | ||
+ | // | ||
+ | |||
+ | var phi = 0.02 * rotationSpeedFactor; | ||
+ | |||
+ | if (xRotationEnabled) { | ||
+ | scene.rotation.x += phi; | ||
+ | } | ||
+ | if (yRotationEnabled) { | ||
+ | scene.rotation.y += phi; | ||
+ | } | ||
+ | if (zRotationEnabled) { | ||
+ | scene.rotation.z += phi; | ||
+ | } | ||
+ | |||
+ | control.update(); | ||
+ | renderer.render(scene, | ||
+ | }; | ||
+ | |||
+ | if ( THREE.WEBGL.isWebGLAvailable() ) { | ||
+ | render(); | ||
+ | } else { | ||
+ | var warning = WEBGL.getWebGLErrorMessage(); | ||
+ | three.appendChild( warning ); | ||
+ | } | ||
+ | | ||
+ | function changeTransparency() { | ||
+ | var opacity = 1-Number(event.currentTarget.value); | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].opacity = opacity; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.opacity = opacity; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleDepthWrite(event) { | ||
+ | depthwrite = event.currentTarget.checked; | ||
+ | for (var i=0; i< | ||
+ | child = scene.children[i]; | ||
+ | if ( child.userData.hasOwnProperty(" | ||
+ | if (Array.isArray(child.userData.facetmaterial)) { | ||
+ | for (var j=0; j< | ||
+ | child.userData.facetmaterial[j].depthWrite = depthwrite; | ||
+ | } | ||
+ | } else { | ||
+ | child.userData.facetmaterial.depthWrite = depthWrite; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function changeRotationX(event){ | ||
+ | xRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationY(event){ | ||
+ | yRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | function changeRotationZ(event){ | ||
+ | zRotationEnabled = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | |||
+ | function changeRotationSpeedFactor(event){ | ||
+ | rotationSpeedFactor = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function resetScene(){ | ||
+ | scene.rotation.set(0, | ||
+ | camera.position.set(0, | ||
+ | camera.up.set(0, | ||
+ | } | ||
+ | |||
+ | function showSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = true; | ||
+ | } | ||
+ | |||
+ | function hideSettings(event){ | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | settingsShown = false; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | var pos = 150* Math.PI; | ||
+ | |||
+ | function updateFactor() { | ||
+ | pos++; | ||
+ | return Math.sin(.01*pos)+1; | ||
+ | } | ||
+ | |||
+ | // ------------------------ FOLDING ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | // rotate point p around axis defined by points p1 and p2 by given angle | ||
+ | function rotate(p, p1, p2, angle ){ | ||
+ | angle = -angle; | ||
+ | var x = p.x, y = p.y, z = p.z, | ||
+ | a = p1.x, b = p1.y, c = p1.z, | ||
+ | u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z; | ||
+ | var result = []; | ||
+ | var L = u*u + v*v + w*w; | ||
+ | var sqrt = Math.sqrt; | ||
+ | var cos = Math.cos; | ||
+ | var sin = Math.sin; | ||
+ | |||
+ | result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/ | ||
+ | result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/ | ||
+ | result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/ | ||
+ | |||
+ | return result; | ||
+ | } | ||
+ | |||
+ | var fold = function(event){ | ||
+ | var obj = foldables[Number(event.currentTarget.name)]; | ||
+ | var foldvalue = Number(event.currentTarget.value); | ||
+ | var scale = foldvalue - obj.userData.oldscale; | ||
+ | |||
+ | for (var j=0; j< | ||
+ | rotateVertices(obj, | ||
+ | } | ||
+ | update(obj); | ||
+ | obj.userData.oldscale += scale; | ||
+ | lookAtBarycenter(obj); | ||
+ | } | ||
+ | |||
+ | function lookAtBarycenter(obj){ | ||
+ | control.target = barycenter(obj); | ||
+ | } | ||
+ | |||
+ | function barycenter(obj) { | ||
+ | var center = new THREE.Vector3(0, | ||
+ | var points = obj.userData.points; | ||
+ | for (var i=0; i< | ||
+ | center.add(points[i].vector); | ||
+ | } | ||
+ | center.divideScalar(points.length); | ||
+ | return center; | ||
+ | } | ||
+ | |||
+ | function rotateVertices(obj, | ||
+ | var axes = obj.userData.axes; | ||
+ | var subtrees = obj.userData.subtrees; | ||
+ | var points = obj.userData.points; | ||
+ | var angles = obj.userData.angles; | ||
+ | if (edge < axes.length){ | ||
+ | for (var j=0; j< | ||
+ | var rotP = rotate(points[subtrees[edge][j]].vector, | ||
+ | points[subtrees[edge][j]].set(rotP[0], | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function update(obj) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | if (foldables.length) { | ||
+ | var settings = document.getElementById(' | ||
+ | var foldDiv = document.createElement(' | ||
+ | foldDiv.id = ' | ||
+ | var title = document.createElement(' | ||
+ | title.innerHTML = ' | ||
+ | foldDiv.appendChild(title); | ||
+ | foldDiv.className = ' | ||
+ | for (var i=0; i< | ||
+ | var range = document.createElement(' | ||
+ | range.type = ' | ||
+ | range.min = 0; | ||
+ | range.max = 1; | ||
+ | range.value = 0; | ||
+ | range.step = 0.001; | ||
+ | range.name = String(i); | ||
+ | range.oninput = fold; | ||
+ | foldDiv.appendChild(range); | ||
+ | } | ||
+ | lookAtBarycenter(foldables[0]); | ||
+ | settings.insertBefore(foldDiv, | ||
+ | } | ||
+ | |||
+ | | ||
+ | // ---------------------- EXPLOSION ------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | if (explodableModel) { | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | if ( obj.userData.explodable ) { | ||
+ | computeCentroid(obj); | ||
+ | } | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | explode(0.000001); | ||
+ | } | ||
+ | |||
+ | function computeCentroid(obj) { | ||
+ | centroid = new THREE.Vector3(); | ||
+ | obj.userData.points.forEach(function(pmpoint) { | ||
+ | centroid.add(pmpoint.vector); | ||
+ | }); | ||
+ | centroid.divideScalar(obj.userData.points.length); | ||
+ | obj.userData.centroid = centroid; | ||
+ | } | ||
+ | |||
+ | function explode(factor) { | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i]; | ||
+ | if (obj.userData.hasOwnProperty(" | ||
+ | var c = obj.userData.centroid; | ||
+ | obj.position.set(c.x*factor, | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function triggerExplode(event){ | ||
+ | explodeScale = Number(event.currentTarget.value); | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | |||
+ | function setExplodingSpeed(event){ | ||
+ | explodingSpeed = Number(event.currentTarget.value); | ||
+ | } | ||
+ | |||
+ | function triggerAutomaticExplode(event){ | ||
+ | if (event.currentTarget.checked){ | ||
+ | startExploding(); | ||
+ | } else { | ||
+ | clearIntervals(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function startExploding(){ | ||
+ | intervals.push(setInterval(explodingInterval, | ||
+ | } | ||
+ | |||
+ | |||
+ | function explodingInterval(){ | ||
+ | explodeScale += explodingSpeed; | ||
+ | if (explodeScale <= 6){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else{ | ||
+ | explode(6); | ||
+ | explodeScale = 6; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startUnexploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | |||
+ | function startUnexploding(){ | ||
+ | intervals.push(setInterval(unexplodingInterval, | ||
+ | } | ||
+ | |||
+ | function unexplodingInterval(){ | ||
+ | explodeScale -= explodingSpeed; | ||
+ | if (explodeScale >= 0){ | ||
+ | explode(explodeScale); | ||
+ | } | ||
+ | else { | ||
+ | explode(0); | ||
+ | explodeScale = 0; | ||
+ | clearIntervals(); | ||
+ | timeouts.push(setTimeout(startExploding, | ||
+ | } | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | |||
+ | function clearIntervals(){ | ||
+ | intervals.forEach(function(interval){ | ||
+ | clearInterval(interval); | ||
+ | }); | ||
+ | intervals = []; | ||
+ | timeouts.forEach(function(timeout){ | ||
+ | clearTimeout(timeout); | ||
+ | }); | ||
+ | timeouts = []; | ||
+ | } | ||
+ | |||
+ | // ---------------------- DISPLAY -------------------------------------------------- | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | const objectTypeInnerHTMLs = { points: " | ||
+ | const objectTypeVisible = {}; | ||
+ | Object.assign(objectTypeVisible, | ||
+ | const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort(); | ||
+ | const shownObjectTypesList = document.getElementById(' | ||
+ | |||
+ | function setVisibility(bool, | ||
+ | for (var i=0; i< | ||
+ | var obj = scene.children[i].getObjectByName(objname); | ||
+ | if (obj) { | ||
+ | obj.visible = bool; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function toggleObjectTypeVisibility(event){ | ||
+ | var name = event.currentTarget.name; | ||
+ | var checked = event.currentTarget.checked; | ||
+ | objectTypeVisible[name] = checked; | ||
+ | if (name == " | ||
+ | setVisibility(checked," | ||
+ | setVisibility(checked," | ||
+ | } else { | ||
+ | setVisibility(checked, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | for (var i=0; i< | ||
+ | var key = sortedObjectTypeKeys[i]; | ||
+ | if (modelContains[key]) { | ||
+ | var objTypeNode = document.createElement(' | ||
+ | objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = key; | ||
+ | checkbox.onchange = toggleObjectTypeVisibility; | ||
+ | shownObjectTypesList.appendChild(checkbox); | ||
+ | shownObjectTypesList.appendChild(objTypeNode); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // ------------------------------------------------------ | ||
+ | |||
+ | function toggleObjectVisibility(event){ | ||
+ | var nr = Number(event.currentTarget.name); | ||
+ | scene.children[nr].visible = event.currentTarget.checked; | ||
+ | } | ||
+ | |||
+ | // append checkboxes for displaying or hiding objects | ||
+ | var shownObjectsList = document.getElementById(' | ||
+ | for (var i=0; i< | ||
+ | obj = scene.children[i]; | ||
+ | var objNode = document.createElement(' | ||
+ | objNode.innerHTML = obj.name + '< | ||
+ | var checkbox = document.createElement(' | ||
+ | checkbox.type = ' | ||
+ | checkbox.checked = true; | ||
+ | checkbox.name = String(i); | ||
+ | checkbox.onchange = toggleObjectVisibility; | ||
+ | shownObjectsList.appendChild(checkbox); | ||
+ | shownObjectsList.appendChild(objNode); | ||
+ | } | ||
+ | |||
+ | // ---------------------- SVG ------------------------------------------------------ | ||
+ | // --------------------------------------------------------------------------------- | ||
+ | |||
+ | function takeSvgScreenshot() { | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(false," | ||
+ | } | ||
+ | svgRenderer.render(scene, | ||
+ | svgElement = XMLS.serializeToString(svgRenderer.domElement); | ||
+ | | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | if (objectTypeVisible[" | ||
+ | setVisibility(true," | ||
+ | } | ||
+ | |||
+ | if (document.getElementById(' | ||
+ | //show in new tab | ||
+ | var myWindow = window.open("","" | ||
+ | myWindow.document.body.innerHTML = svgElement; | ||
+ | } else{ | ||
+ | // download svg file | ||
+ | download(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function download(filename, | ||
+ | var element = document.createElement(' | ||
+ | element.setAttribute(' | ||
+ | element.setAttribute(' | ||
+ | |||
+ | element.style.display = ' | ||
+ | document.body.appendChild(element); | ||
+ | |||
+ | element.click(); | ||
+ | |||
+ | document.body.removeChild(element); | ||
+ | } | ||
+ | |||
+ | |||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | document.getElementById(' | ||
+ | |||
+ | |||
+ | // ------------------ SHORTCUTS -------------------------------------------- | ||
+ | // ------------------------------------------------------------------------- | ||
+ | |||
+ | /** | ||
+ | * http:// | ||
+ | * Version : 2.01.B | ||
+ | * By Binny V A | ||
+ | * License : BSD | ||
+ | */ | ||
+ | shortcut = { | ||
+ | ' | ||
+ | ' | ||
+ | //Provide a set of default options | ||
+ | var default_options = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | if(!opt) opt = default_options; | ||
+ | else { | ||
+ | for(var dfo in default_options) { | ||
+ | if(typeof opt[dfo] == ' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var ele = opt.target; | ||
+ | if(typeof opt.target == ' | ||
+ | var ths = this; | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | |||
+ | //The function to be called at keypress | ||
+ | var func = function(e) { | ||
+ | e = e || window.event; | ||
+ | |||
+ | if(opt[' | ||
+ | var element; | ||
+ | if(e.target) element=e.target; | ||
+ | else if(e.srcElement) element=e.srcElement; | ||
+ | if(element.nodeType==3) element=element.parentNode; | ||
+ | |||
+ | if(element.tagName == ' | ||
+ | } | ||
+ | |||
+ | //Find Which key is pressed | ||
+ | if (e.keyCode) code = e.keyCode; | ||
+ | else if (e.which) code = e.which; | ||
+ | var character = String.fromCharCode(code).toLowerCase(); | ||
+ | |||
+ | if(code == 188) character=","; | ||
+ | if(code == 190) character=" | ||
+ | |||
+ | var keys = shortcut_combination.split(" | ||
+ | //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked | ||
+ | var kp = 0; | ||
+ | |||
+ | //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken | ||
+ | var shift_nums = { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | ";":":", | ||
+ | "'":" | ||
+ | ",":"<", | ||
+ | " | ||
+ | "/":"?", | ||
+ | " | ||
+ | } | ||
+ | // | ||
+ | var special_keys = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | |||
+ | var modifiers = { | ||
+ | shift: { wanted: | ||
+ | ctrl : { wanted: | ||
+ | alt | ||
+ | meta : { wanted: | ||
+ | }; | ||
+ | | ||
+ | if(e.ctrlKey) modifiers.ctrl.pressed = true; | ||
+ | if(e.shiftKey) modifiers.shift.pressed = true; | ||
+ | if(e.altKey) modifiers.alt.pressed = true; | ||
+ | if(e.metaKey) | ||
+ | | ||
+ | for(var i=0; k=keys[i], | ||
+ | // | ||
+ | if(k == ' | ||
+ | kp++; | ||
+ | modifiers.ctrl.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.shift.wanted = true; | ||
+ | |||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.alt.wanted = true; | ||
+ | } else if(k == ' | ||
+ | kp++; | ||
+ | modifiers.meta.wanted = true; | ||
+ | } else if(k.length > 1) { //If it is a special key | ||
+ | if(special_keys[k] == code) kp++; | ||
+ | |||
+ | } else if(opt[' | ||
+ | if(opt[' | ||
+ | |||
+ | } else { //The special keys did not match | ||
+ | if(character == k) kp++; | ||
+ | else { | ||
+ | if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase | ||
+ | character = shift_nums[character]; | ||
+ | if(character == k) kp++; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if(kp == keys.length && | ||
+ | modifiers.ctrl.pressed == modifiers.ctrl.wanted && | ||
+ | modifiers.shift.pressed == modifiers.shift.wanted && | ||
+ | modifiers.alt.pressed == modifiers.alt.wanted && | ||
+ | modifiers.meta.pressed == modifiers.meta.wanted) { | ||
+ | callback(e); | ||
+ | |||
+ | if(!opt[' | ||
+ | // | ||
+ | e.cancelBubble = true; | ||
+ | e.returnValue = false; | ||
+ | |||
+ | // | ||
+ | if (e.stopPropagation) { | ||
+ | e.stopPropagation(); | ||
+ | e.preventDefault(); | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | this.all_shortcuts[shortcut_combination] = { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }; | ||
+ | //Attach the function with the event | ||
+ | if(ele.addEventListener) ele.addEventListener(opt[' | ||
+ | else if(ele.attachEvent) ele.attachEvent(' | ||
+ | else ele[' | ||
+ | }, | ||
+ | |||
+ | //Remove the shortcut - just specify the shortcut and I will remove the binding | ||
+ | ' | ||
+ | shortcut_combination = shortcut_combination.toLowerCase(); | ||
+ | var binding = this.all_shortcuts[shortcut_combination]; | ||
+ | delete(this.all_shortcuts[shortcut_combination]) | ||
+ | if(!binding) return; | ||
+ | var type = binding[' | ||
+ | var ele = binding[' | ||
+ | var callback = binding[' | ||
+ | |||
+ | if(ele.detachEvent) ele.detachEvent(' | ||
+ | else if(ele.removeEventListener) ele.removeEventListener(type, | ||
+ | else ele[' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | shortcut.add(" | ||
+ | var event = new Event(' | ||
+ | if (settingsShown){ | ||
+ | document.getElementById(' | ||
+ | } else { | ||
+ | document.getElementById(' | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | If '' | ||
+ | |||
+ | ===== application topaz ===== | ||
+ | |||
+ | For information on how to visualize simlicial complexes and other topology-related objects, see [[apps_topaz# | ||
+ | |||
+ | ===== Backends ===== | ||
+ | |||
+ | ' | ||
+ | |||
+ | ==== TikZ and Sketch ==== | ||
+ | |||
+ | Sketch is a script language which produces TikZ output. It is quite sophisticated. There is a interface from polymake to Sketch. | ||
+ | |||
+ | <code perl> | ||
+ | > $my_polytope = cube(3); | ||
+ | > sketch($my_polytope-> | ||
+ | </ | ||
+ | When you downloaded the Sketch interpreter ([[http:// | ||
+ | |||
+ | <code perl> | ||
+ | sketch myfile.sketch > myfile.tikz | ||
+ | </ | ||
+ | The drawback is that the produced TikZ code is quite cryptic and not really readable or editable anymore. If you do want to create TikZ code which is easier to edit afterwards, you might want to use polymake' | ||
+ | |||
+ | <code perl> | ||
+ | > tikz($my_polytope-> | ||
+ | </ | ||
+ | For a different viewing angle you may use jReality. Rotate the polytope into the position you want and click the '' | ||
+ | |||
+ | ==== jReality ==== | ||
+ | |||
+ | The jReality viewer offers a versatile perspective for your favourite tools on 4 Panel which may be enabled/ | ||
+ | |||
+ | === Appearance === | ||
+ | |||
+ | There are several objects which control the appearance of a geometry in jreality: | ||
+ | |||
+ | - geometry attributes, | ||
+ | - appearances at a specific scene graph nodes, and | ||
+ | - the content appearance. | ||
+ | |||
+ | The most versatile point to set different parameters for the appearance is via geometry attributes. This is needed, for example, if every vertex of the displayed geometry should have its own thickness or color like in VISUAL_GRAPH-> | ||
+ | |||
+ | An appearance at a scene graph node (every VISUAL object is put into one of these) may have its own appearance which stores single values for colors/ | ||
+ | |||
+ | The content appearance comes into play if no other appearances exist in the content subtree, i.e. neither specific node appearances nor geometry attributes. The sizes/ | ||
+ | |||
+ | So to be able to change the colors of the faces/ | ||
+ | |||
+ | === Save View === | ||
+ | |||
+ | Clicking the "Save View" button on the bottom of the jReality window attaches a " | ||
+ | |||
+ | ==== ThreeJS ==== | ||
+ | |||
+ | This is the default backend for 3D visuals and their only one in Jupyter-Notebooks. Due to ThreeJS' | ||
+ | |||