no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
— | user_guide:tutorials:latest:ilp_and_hilbertbases [2023/11/06 10:57] (current) – created - external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ===== ILP and Hilbert bases ===== | ||
+ | |||
+ | ==== A first example ==== | ||
+ | |||
+ | First we will construct a new rational polytope: | ||
+ | |||
+ | <code perl> | ||
+ | > $p=new Polytope< | ||
+ | > $p-> | ||
+ | > 1 0 0 0 | ||
+ | > 1 1 0 0 | ||
+ | > 1 0 1 0 | ||
+ | > 1 1 1 0 | ||
+ | > 1 0 0 1 | ||
+ | > 1 1 0 1 | ||
+ | > 1 0 1 1 | ||
+ | > 1 1 1 1 | ||
+ | > . | ||
+ | </ | ||
+ | Note that points in '' | ||
+ | |||
+ | Now we can examine some properties of '' | ||
+ | |||
+ | <code perl> | ||
+ | > print $p-> | ||
+ | 6 | ||
+ | > print $p-> | ||
+ | true | ||
+ | </ | ||
+ | As you might already have noticed, our polytope is just a 3-dimensional cube. So there would have been an easier way to create it using the client '' | ||
+ | |||
+ | <code perl> | ||
+ | > $c = cube(3,0); | ||
+ | </ | ||
+ | (You can check out the details of any function in the [[documentation: | ||
+ | |||
+ | And we can also verify that the two polytopes are actually equal: | ||
+ | |||
+ | <code perl> | ||
+ | > print equal_polyhedra($p, | ||
+ | true | ||
+ | </ | ||
+ | ==== Another example ==== | ||
+ | |||
+ | Now let us proceed with a somewhat more interesting example: The convex hull of 20 randomly chosen points on the 2-dimensional sphere. | ||
+ | |||
+ | <code perl> | ||
+ | > $rs = rand_sphere(3, | ||
+ | </ | ||
+ | '' | ||
+ | |||
+ | <code perl> | ||
+ | > $rs-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Thu Mar 3 00:34:23 2022 | ||
+ | rs | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <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.440503, | ||
+ | obj0.userData.points.push(new PMPoint(0.665111, | ||
+ | obj0.userData.points.push(new PMPoint(0.249757, | ||
+ | obj0.userData.points.push(new PMPoint(-0.577844, | ||
+ | obj0.userData.points.push(new PMPoint(-0.112342, | ||
+ | obj0.userData.points.push(new PMPoint(0.541203, | ||
+ | obj0.userData.points.push(new PMPoint(-0.456164, | ||
+ | obj0.userData.points.push(new PMPoint(-0.652696, | ||
+ | obj0.userData.points.push(new PMPoint(-0.307662, | ||
+ | obj0.userData.points.push(new PMPoint(-0.194799, | ||
+ | obj0.userData.points.push(new PMPoint(0.0373143, | ||
+ | obj0.userData.points.push(new PMPoint(0.693347, | ||
+ | obj0.userData.points.push(new PMPoint(0.662852, | ||
+ | obj0.userData.points.push(new PMPoint(-0.660007, | ||
+ | obj0.userData.points.push(new PMPoint(-0.0512853, | ||
+ | obj0.userData.points.push(new PMPoint(-0.791998, | ||
+ | obj0.userData.points.push(new PMPoint(0.737893, | ||
+ | obj0.userData.points.push(new PMPoint(0.0472492, | ||
+ | obj0.userData.points.push(new PMPoint(-0.750783, | ||
+ | obj0.userData.points.push(new PMPoint(0.331489, | ||
+ | |||
+ | obj0.userData.pointradii = 0.02; | ||
+ | < | ||
+ | obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | obj0.userData.pointlabels = [" | ||
+ | obj0.userData.edgeindices = [1, 2, 0, 4, 4, 5, 1, 6, 2, 6, 3, 6, 4, 7, 2, 8, 3, 8, 6, 8, 0, 9, 1, 9, 6, 9, 1, 10, 6, 10, 9, 10, 5, 11, 1, 12, 2, 12, 5, 12, 11, 12, 0, 13, 4, 13, 7, 13, 9, 13, 2, 14, 4, 14, 5, 14, 7, 14, 8, 14, 3, 15, 6, 15, 7, 15, 9, 15, 13, 15, 0, 16, 1, 16, 9, 16, 11, 16, 12, 16, 0, 17, 4, 17, 5, 17, 11, 17, 16, 17, 3, 18, 7, 18, 8, 18, 14, 18, 15, 18, 2, 19, 5, 19, 12, 19, 14, 19]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[5, 11, 17], [12, 11, 5], [12, 5, 19], [12, 19, 2], [19, 14, 2], [4, 17, 0], [14, 4, 7], [14, 18, 8], [14, 7, 18], [0, 9, 13], [13, 9, 15], [15, 9, 6], [18, 15, 3], [7, 13, 15], [18, 7, 15], [15, 6, 3], [8, 18, 3], [6, 8, 3], [4, 13, 7], [4, 0, 13], [9, 10, 6], [2, 14, 8], [6, 2, 8], [5, 4, 14], [5, 17, 4], [5, 14, 19], [9, 1, 10], [1, 6, 10], [1, 2, 6], [1, 12, 2], [0, 16, 9], [17, 16, 0], [16, 1, 9], [16, 12, 1], [17, 11, 16], [16, 11, 12]]; | ||
+ | < | ||
+ | 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 | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | Now we will create yet another new polytope by scaling our random sphere by a factor lambda. (Otherwise there are rather few integral points contained in it.) | ||
+ | |||
+ | To this end, we have to multiply every coordinate (except for the homogenising 1 in the beginning) of every vertex by lamda. Then we can create a new polytope by specifying its vertices. | ||
+ | |||
+ | <code perl> | ||
+ | > $lambda=2; | ||
+ | > $s=new Matrix< | ||
+ | > print $s; | ||
+ | 1 0 0 0 | ||
+ | 0 2 0 0 | ||
+ | 0 0 2 0 | ||
+ | 0 0 0 2 | ||
+ | > $scaled_rs=new Polytope< | ||
+ | </ | ||
+ | '' | ||
+ | |||
+ | <code perl> | ||
+ | > $scaled_rs-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Thu Mar 3 00:34:23 2022 | ||
+ | scaled_rs | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <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.881007, | ||
+ | obj0.userData.points.push(new PMPoint(1.33022, | ||
+ | obj0.userData.points.push(new PMPoint(0.499515, | ||
+ | obj0.userData.points.push(new PMPoint(-1.15569, | ||
+ | obj0.userData.points.push(new PMPoint(-0.224685, | ||
+ | obj0.userData.points.push(new PMPoint(1.08241, | ||
+ | obj0.userData.points.push(new PMPoint(-0.912329, | ||
+ | obj0.userData.points.push(new PMPoint(-1.30539, | ||
+ | obj0.userData.points.push(new PMPoint(-0.615324, | ||
+ | obj0.userData.points.push(new PMPoint(-0.389597, | ||
+ | obj0.userData.points.push(new PMPoint(0.0746285, | ||
+ | obj0.userData.points.push(new PMPoint(1.38669, | ||
+ | obj0.userData.points.push(new PMPoint(1.3257, | ||
+ | obj0.userData.points.push(new PMPoint(-1.32001, | ||
+ | obj0.userData.points.push(new PMPoint(-0.102571, | ||
+ | obj0.userData.points.push(new PMPoint(-1.584, | ||
+ | obj0.userData.points.push(new PMPoint(1.47579, | ||
+ | obj0.userData.points.push(new PMPoint(0.0944984, | ||
+ | obj0.userData.points.push(new PMPoint(-1.50157, | ||
+ | obj0.userData.points.push(new PMPoint(0.662978, | ||
+ | |||
+ | obj0.userData.edgeindices = [1, 2, 0, 4, 4, 5, 1, 6, 2, 6, 3, 6, 4, 7, 2, 8, 3, 8, 6, 8, 0, 9, 1, 9, 6, 9, 1, 10, 6, 10, 9, 10, 5, 11, 1, 12, 2, 12, 5, 12, 11, 12, 0, 13, 4, 13, 7, 13, 9, 13, 2, 14, 4, 14, 5, 14, 7, 14, 8, 14, 3, 15, 6, 15, 7, 15, 9, 15, 13, 15, 0, 16, 1, 16, 9, 16, 11, 16, 12, 16, 0, 17, 4, 17, 5, 17, 11, 17, 16, 17, 3, 18, 7, 18, 8, 18, 14, 18, 15, 18, 2, 19, 5, 19, 12, 19, 14, 19]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[5, 11, 17], [12, 11, 5], [12, 5, 19], [12, 19, 2], [19, 14, 2], [4, 17, 0], [14, 4, 7], [14, 18, 8], [14, 7, 18], [0, 9, 13], [13, 9, 15], [15, 9, 6], [18, 15, 3], [7, 13, 15], [18, 7, 15], [15, 6, 3], [8, 18, 3], [6, 8, 3], [4, 13, 7], [4, 0, 13], [9, 10, 6], [2, 14, 8], [6, 2, 8], [5, 4, 14], [5, 17, 4], [5, 14, 19], [9, 1, 10], [1, 6, 10], [1, 2, 6], [1, 12, 2], [0, 16, 9], [17, 16, 0], [16, 1, 9], [16, 12, 1], [17, 11, 16], [16, 11, 12]]; | ||
+ | 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, -1, -1)); | ||
+ | obj1.userData.points.push(new PMPoint(-1, -1, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(-1, 0, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(-1, 0, 1)); | ||
+ | obj1.userData.points.push(new PMPoint(-1, 1, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(-1, 1, 1)); | ||
+ | obj1.userData.points.push(new PMPoint(0, -1, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(0, -1, 1)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 0, -1)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 0, 1)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 1, -1)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 1, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 1, 1)); | ||
+ | obj1.userData.points.push(new PMPoint(1, 0, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(1, 0, 1)); | ||
+ | obj1.userData.points.push(new PMPoint(1, 1, -1)); | ||
+ | obj1.userData.points.push(new PMPoint(1, 1, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(1, 1, 1)); | ||
+ | obj1.userData.points.push(new PMPoint(-0.881007, | ||
+ | obj1.userData.points.push(new PMPoint(1.33022, | ||
+ | obj1.userData.points.push(new PMPoint(0.499515, | ||
+ | obj1.userData.points.push(new PMPoint(-1.15569, | ||
+ | obj1.userData.points.push(new PMPoint(-0.224685, | ||
+ | obj1.userData.points.push(new PMPoint(1.08241, | ||
+ | obj1.userData.points.push(new PMPoint(-0.912329, | ||
+ | obj1.userData.points.push(new PMPoint(-1.30539, | ||
+ | obj1.userData.points.push(new PMPoint(-0.615324, | ||
+ | obj1.userData.points.push(new PMPoint(-0.389597, | ||
+ | obj1.userData.points.push(new PMPoint(0.0746285, | ||
+ | obj1.userData.points.push(new PMPoint(1.38669, | ||
+ | obj1.userData.points.push(new PMPoint(1.3257, | ||
+ | obj1.userData.points.push(new PMPoint(-1.32001, | ||
+ | obj1.userData.points.push(new PMPoint(-0.102571, | ||
+ | obj1.userData.points.push(new PMPoint(-1.584, | ||
+ | obj1.userData.points.push(new PMPoint(1.47579, | ||
+ | obj1.userData.points.push(new PMPoint(0.0944984, | ||
+ | obj1.userData.points.push(new PMPoint(-1.50157, | ||
+ | obj1.userData.points.push(new PMPoint(0.662978, | ||
+ | |||
+ | obj1.userData.pointradii = 0.02; | ||
+ | < | ||
+ | obj1.userData.pointmaterial = [new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | 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 | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | Now will construct the integer hull of '' | ||
+ | |||
+ | <code perl> | ||
+ | > $integer_hull=new Polytope< | ||
+ | > $integer_hull-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Thu Mar 3 00:34:23 2022 | ||
+ | integer_hull | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <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(-1, -1, -1)); | ||
+ | obj0.userData.points.push(new PMPoint(-1, -1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(-1, 0, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(-1, 1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(-1, 1, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(0, -1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, -1, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 1, -1)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 0, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 1, -1)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 1, 1)); | ||
+ | |||
+ | obj0.userData.edgeindices = [0, 1, 1, 2, 0, 3, 2, 4, 3, 4, 0, 5, 1, 6, 2, 6, 5, 6, 0, 7, 3, 7, 5, 8, 6, 9, 8, 9, 0, 10, 7, 10, 8, 10, 4, 11, 9, 11, 10, 11]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[6, 5, 8, 9], [7, 0, 3], [0, 5, 6, 1], [6, 2, 1], [2, 4, 3, 0, 1], [8, 5, 0, 10], [10, 0, 7], [6, 9, 11, 4, 2], [9, 8, 10, 11], [11, 10, 7, 3, 4]]; | ||
+ | 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(0, 0, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(-1, -1, -1)); | ||
+ | obj1.userData.points.push(new PMPoint(-1, -1, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(-1, 0, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(-1, 0, 1)); | ||
+ | obj1.userData.points.push(new PMPoint(-1, 1, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(-1, 1, 1)); | ||
+ | obj1.userData.points.push(new PMPoint(0, -1, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(0, -1, 1)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 0, -1)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 0, 1)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 1, -1)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 1, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 1, 1)); | ||
+ | obj1.userData.points.push(new PMPoint(1, 0, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(1, 0, 1)); | ||
+ | obj1.userData.points.push(new PMPoint(1, 1, -1)); | ||
+ | obj1.userData.points.push(new PMPoint(1, 1, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(1, 1, 1)); | ||
+ | |||
+ | obj1.userData.pointradii = 0.02; | ||
+ | < | ||
+ | obj1.userData.pointmaterial = [new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, | ||
+ | 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 | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | In order to obtain the integer hull we simply define a new polytope '' | ||
+ | |||
+ | Note that if we give '' | ||
+ | |||
+ | If you specify '' | ||
+ | |||
+ | ==== Linear Programming ==== | ||
+ | |||
+ | Now that we have constructed a nice integral polytope we want to apply some linear program to it. | ||
+ | |||
+ | First we define a '' | ||
+ | |||
+ | <code perl> | ||
+ | > $objective=new LinearProgram< | ||
+ | </ | ||
+ | Then we define a new polytope, which is a copy of our old one ('' | ||
+ | |||
+ | <code perl> | ||
+ | > $ilp=new Polytope< | ||
+ | </ | ||
+ | {{: | ||
+ | |||
+ | And now we can perform some computations: | ||
+ | |||
+ | <code perl> | ||
+ | > print $ilp-> | ||
+ | 3 | ||
+ | > print $ilp-> | ||
+ | {11} | ||
+ | > $ilp-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Thu Mar 3 00:34:24 2022 | ||
+ | ilp | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <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, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(-1, 0, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(-1, 1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(-1, 1, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(0, -1, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, -1, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 1, -1)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 0, 1)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 1, -1)); | ||
+ | obj0.userData.points.push(new PMPoint(1, 1, 1)); | ||
+ | |||
+ | obj0.userData.pointradii = 0.02; | ||
+ | < | ||
+ | obj0.userData.pointmaterial = [new THREE.MeshBasicMaterial( { color: 0xFFFF00, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, | ||
+ | obj0.userData.pointlabels = [" | ||
+ | obj0.userData.edgeindices = [0, 1, 1, 2, 0, 3, 2, 4, 3, 4, 0, 5, 1, 6, 2, 6, 5, 6, 0, 7, 3, 7, 5, 8, 6, 9, 8, 9, 0, 10, 7, 10, 8, 10, 4, 11, 9, 11, 10, 11]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[0, 10, 8, 5], [7, 10, 0], [0, 5, 6, 1], [1, 6, 2], [0, 1, 2, 4, 3], [3, 7, 0], [5, 8, 9, 6], [9, 11, 4, 2, 6], [8, 10, 11, 9], [11, 10, 7, 3, 4]]; | ||
+ | < | ||
+ | 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 | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | Hence the LP attains its maximal value 2 on the 2-face spanned by the vertices 6, 9 and 10. | ||
+ | |||
+ | '' | ||
+ | |||
+ | Note though that since we started out with a random polytope these results may vary if we perform the same computations another time on a different random polytope. | ||
+ | |||
+ | <code perl> | ||
+ | > print $ilp-> | ||
+ | 1 -1 -1 -1 | ||
+ | 1 -1 -1 0 | ||
+ | 1 -1 0 1 | ||
+ | 1 -1 1 0 | ||
+ | 1 -1 1 1 | ||
+ | 1 0 -1 0 | ||
+ | 1 0 -1 1 | ||
+ | 1 0 1 -1 | ||
+ | 1 1 0 0 | ||
+ | 1 1 0 1 | ||
+ | 1 1 1 -1 | ||
+ | 1 1 1 1 | ||
+ | </ | ||
+ | ==== Hilbert bases ==== | ||
+ | |||
+ | Finally, we can have '' | ||
+ | |||
+ | <code perl> | ||
+ | > print $ilp-> | ||
+ | 1 -1 -1 -1 | ||
+ | 1 -1 -1 0 | ||
+ | 1 -1 0 0 | ||
+ | 1 -1 0 1 | ||
+ | 1 -1 1 0 | ||
+ | 1 -1 1 1 | ||
+ | 1 0 -1 0 | ||
+ | 1 0 -1 1 | ||
+ | 1 0 0 -1 | ||
+ | 1 0 0 0 | ||
+ | 1 0 0 1 | ||
+ | 1 0 1 -1 | ||
+ | 1 0 1 0 | ||
+ | 1 0 1 1 | ||
+ | 1 1 0 0 | ||
+ | 1 1 0 1 | ||
+ | 1 1 1 -1 | ||
+ | 1 1 1 0 | ||
+ | 1 1 1 1 | ||
+ | </ | ||