Differences
This shows you the differences between two versions of the page.
— | user_guide:tutorials:latest:apps_tropical [2023/11/06 10:57] (current) – created - external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Tutorial: Tropical arithmetics and tropical geometry ====== | ||
+ | |||
+ | This tutorial showcases the main features of application tropical, such as | ||
+ | |||
+ | * Tropical arithmetics | ||
+ | * Tropical convex hull computations | ||
+ | * Tropical cycles and hypersurfaces. | ||
+ | * Tropical intersection theory | ||
+ | |||
+ | To use the full palette of tools for tropical geometry, switch to the corresponding application by typing the following in the '' | ||
+ | |||
+ | <code perl> | ||
+ | > application ' | ||
+ | </ | ||
+ | === Disclaimer: Min or Max - you have to choose! === | ||
+ | |||
+ | Most objects and data types related to tropical computations have a template parameter which tells it whether Min or Max is used as tropical addition. There is **no default** for this, so you have to choose! | ||
+ | |||
+ | === a-tint === | ||
+ | |||
+ | For a while now, polymake comes bundled with the extension [[https:// | ||
+ | |||
+ | === Further reading === | ||
+ | |||
+ | If you want to learn more you might want to check out: | ||
+ | |||
+ | * Simon Hampe & Michael Joswig: < | ||
+ | |||
+ | ===== Tropical arithmetics ===== | ||
+ | |||
+ | You can create an element of the tropical semiring (over the rationals) simply by writing something like this: | ||
+ | |||
+ | <code perl> | ||
+ | > $a = new TropicalNumber< | ||
+ | > $b = new TropicalNumber< | ||
+ | > $c = new TropicalNumber< | ||
+ | </ | ||
+ | You can now do basic arithmetic - that is **tropical** addition and multiplication with these. Note that tropical numbers with different tropical additions don't mix! | ||
+ | |||
+ | <code perl> | ||
+ | > print $a * $a; | ||
+ | 8 | ||
+ | > print $b + $c*$b; | ||
+ | 4 | ||
+ | > # print $a + $b; # this won't work! | ||
+ | </ | ||
+ | Tropical vector/ | ||
+ | |||
+ | <code perl> | ||
+ | > $m = new Matrix< | ||
+ | > $v = new Vector< | ||
+ | > print $m + $m; | ||
+ | 0 1 2 | ||
+ | 0 -inf 3 | ||
+ | 0 0 -inf | ||
+ | > print $m * $v; | ||
+ | 4 5 1 | ||
+ | > print tdet($m); | ||
+ | 4 | ||
+ | </ | ||
+ | Finally, you can also create tropical polynomials. This can be done with the special toTropicalPolynomial parser: | ||
+ | |||
+ | <code perl> | ||
+ | > $q = toTropicalPolynomial(" | ||
+ | > print $q; | ||
+ | x_0^2 + x_1*x_2 | ||
+ | </ | ||
+ | ===== Homogeneous and extended coordinates ===== | ||
+ | |||
+ | All higher tropical objects (trop. polytopes, cycles, ...) live in the //tropical projective torus// $ \mathbb R^n/\mathbb R\mathbf 1\cong \mathbb R^{n-1}$ (or in its natural compactification, | ||
+ | |||
+ | At the same time many properties (e.g. '' | ||
+ | |||
+ | Note that this contrasts to conventional real/ | ||
+ | |||
+ | **Example**: | ||
+ | |||
+ | === Helper functions === | ||
+ | |||
+ | Since it can be tedious to write everything in tropically homogeneous coordinates, | ||
+ | |||
+ | Both have signature '' | ||
+ | |||
+ | Some examples: | ||
+ | |||
+ | <code perl> | ||
+ | > print thomog([[1, | ||
+ | 1 0 3 4 | ||
+ | 0 0 5 6 | ||
+ | > print thomog([[2, | ||
+ | 2 0 3 4 | ||
+ | > print tdehomog([[1, | ||
+ | 1 1 2 | ||
+ | > print tdehomog([[2, | ||
+ | -1 1 2 | ||
+ | </ | ||
+ | ===== Tropical convex hull computations ===== | ||
+ | |||
+ | The basic object for tropical convex hull computations is '' | ||
+ | |||
+ | A tropical polytope should always be created via '' | ||
+ | |||
+ | <code perl> | ||
+ | > $c = new Polytope< | ||
+ | > print $c-> | ||
+ | 0 0 0 | ||
+ | 0 2 1 | ||
+ | > print rows_labeled($c-> | ||
+ | 0:1 0 1 1 | ||
+ | 1:0 0 -1 0 | ||
+ | 2:1 0 0 0 | ||
+ | 3:1 0 2 1 | ||
+ | 4:0 0 0 -1 | ||
+ | 5:0 0 1 1 | ||
+ | > print $c-> | ||
+ | {0 1 2} | ||
+ | {0 1 5} | ||
+ | {0 2 4} | ||
+ | {0 3 4} | ||
+ | {0 3 5} | ||
+ | {1 2 4} | ||
+ | {3 4 5} | ||
+ | > print $c-> | ||
+ | {0 2} | ||
+ | {0 3} | ||
+ | </ | ||
+ | There are many visualization backends in < | ||
+ | |||
+ | <code perl> | ||
+ | > svg($c-> | ||
+ | </ | ||
+ | {{ tutorials: | ||
+ | In case you're just interested in either the subdivision of the full torus, or the polyhedral structure of the tropical polytope, the following will give you those structures as '' | ||
+ | |||
+ | <code perl> | ||
+ | > $t = $c-> | ||
+ | > $p = $c-> | ||
+ | > print $p-> | ||
+ | 1 1 1 | ||
+ | 1 0 0 | ||
+ | 1 2 1 | ||
+ | > print $p-> | ||
+ | {0 2} | ||
+ | {0 3} | ||
+ | </ | ||
+ | Note that by default, the affine chart is {x_0 = 0}. You can choose any chart {x_i = 0} by passing i as an argument to '' | ||
+ | |||
+ | Polymake computes the full subdivision of both the torus and the polytope as a '' | ||
+ | |||
+ | <code perl> | ||
+ | > svg($c-> | ||
+ | > svg($c-> | ||
+ | </ | ||
+ | {{ tutorials: | ||
+ | {{ tutorials: | ||
+ | Each node in the lattice is a cell of the subdivision. The top row describes the vertices and rays of the subdivision. The bottom row is the covector of that cell with respect to the '' | ||
+ | |||
+ | ===== Tropical cycles ===== | ||
+ | |||
+ | The main object here is '' | ||
+ | |||
+ | A tropical cycle can be created, like a '' | ||
+ | |||
+ | <code perl> | ||
+ | > $x = new Cycle< | ||
+ | </ | ||
+ | This creates the standard tropical (max-)line in the plane. There are two caveats to observe here: | ||
+ | |||
+ | - The use of '' | ||
+ | - You can also define a cycle using '' | ||
+ | |||
+ | Entering projective coordinates can be a little tedious, since it usually just means adding a zero in front of your affine coordinates. There is a convenience function that does this for you. The following creates the excact same cycle as above: | ||
+ | |||
+ | <code perl> | ||
+ | > $x = new Cycle< | ||
+ | </ | ||
+ | One can now ask for basic properties of the cycle, e.g., if it's balanced: | ||
+ | |||
+ | <code perl> | ||
+ | > print is_balanced($x); | ||
+ | true | ||
+ | </ | ||
+ | === Hypersurfaces === | ||
+ | |||
+ | Most of the time you probably won't want to input your tropical cycle directly as above. Polymake has a special data type '' | ||
+ | |||
+ | <code perl> | ||
+ | > $H = new Hypersurface< | ||
+ | > print $H-> | ||
+ | 1 0 0 0 | ||
+ | 0 0 -1 -1 | ||
+ | 0 0 1 0 | ||
+ | 0 0 0 1 | ||
+ | > print $H-> | ||
+ | {0 2} | ||
+ | {0 1} | ||
+ | {0 3} | ||
+ | > print $H-> | ||
+ | 1 1 1 | ||
+ | </ | ||
+ | ===== Tropical intersection theory ===== | ||
+ | |||
+ | Functionality related to tropical intersection theory is provided by the bundled extension atint by Simon Hampe, see [[https:// | ||
+ | |||
+ | === Basic examples === | ||
+ | |||
+ | == Computing the divisor of a tropical polynomial in $ \mathbb R^n$ == | ||
+ | |||
+ | <code perl> | ||
+ | > $f = toTropicalPolynomial(" | ||
+ | > $div = divisor(projective_torus< | ||
+ | > svg($div-> | ||
+ | </ | ||
+ | {{ tutorials: | ||
+ | Here, '' | ||
+ | |||
+ | == Visualizing a curve in a tropical surface == | ||
+ | |||
+ | Let's create the standard tropical hyperplane in 3-space: | ||
+ | |||
+ | <code perl> | ||
+ | > $l = uniform_linear_space< | ||
+ | </ | ||
+ | Furthermore, | ||
+ | |||
+ | <code perl> | ||
+ | > $div = divisor($l, rational_fct_from_affine_numerator(toTropicalPolynomial(" | ||
+ | </ | ||
+ | We now want to visualize these together and since we want to put the resulting picture in a slide show, we want the picture to look a bit nicer, e.g. we want to intersect both the surface and the curve with the same bounding box (we don't want the curve to continue " | ||
+ | |||
+ | <code perl> | ||
+ | > print $l-> | ||
+ | 1 0 0 0 | ||
+ | 1 0 0 0 | ||
+ | > print $div-> | ||
+ | 1 -1 -1 -1 | ||
+ | 1 3 0 0 | ||
+ | </ | ||
+ | The method bounding_box returns 2 opposing vertices of the smallest acceptable bounding box for the hyperplane' | ||
+ | |||
+ | <code perl> | ||
+ | > $bbfacets = polytope:: | ||
+ | </ | ||
+ | For zero or undefined offset it is advisable to set '' | ||
+ | |||
+ | <code perl> | ||
+ | > compose($l-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Thu Mar 3 00:27:42 2022 | ||
+ | l | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <meta charset=utf-8> | ||
+ | < | ||
+ | < | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | */ | ||
+ | html {overflow: scroll;} | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | # | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | | ||
+ | } | ||
+ | /* | ||
+ | // COMMON_CODE_BLOCK_END | ||
+ | */ | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | <div id=' | ||
+ | <div class=group id=' | ||
+ | < | ||
+ | < | ||
+ | <div class=indented>< | ||
+ | <div class=suboption> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | < | ||
+ | <div class=indented>< | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | <div class=suboption> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | <div class=suboption> | ||
+ | <div class=indented> | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | <select id=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <div class=group id=' | ||
+ | < | ||
+ | <div class=indented> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <img id=' | ||
+ | <img id=' | ||
+ | <div id=" | ||
+ | </ | ||
+ | < | ||
+ | requirejs.config({ | ||
+ | paths: { | ||
+ | three: '/ | ||
+ | TrackballControls: | ||
+ | OrbitControls: | ||
+ | Projector: '/ | ||
+ | SVGRenderer: | ||
+ | WEBGL: '/ | ||
+ | }, | ||
+ | shim: { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | }); | ||
+ | | ||
+ | require([' | ||
+ | window.THREE = THREE; | ||
+ | require([' | ||
+ | | ||
+ | THREE.TrackballControls = TrackballControls; | ||
+ | THREE.OrbitControls = OrbitControls; | ||
+ | THREE.Projector = Projector; | ||
+ | THREE.SVGRenderer = SVGRenderer; | ||
+ | THREE.WEBGL = WEBGL; | ||
+ | |||
+ | // COMMON_CODE_BLOCK_BEGIN | ||
+ | |||
+ | const intervalLength = 25; // for automatic animations | ||
+ | const explodableModel = true; | ||
+ | const modelContains = { points: false, pointlabels: | ||
+ | const foldables = []; | ||
+ | |||
+ | var three = document.getElementById(" | ||
+ | var scene = new THREE.Scene(); | ||
+ | var renderer = new THREE.WebGLRenderer( { antialias: true } ); | ||
+ | var svgRenderer = new THREE.SVGRenderer( { antialias: true } ); | ||
+ | renderer.setPixelRatio( window.devicePixelRatio ); | ||
+ | renderer.setClearColor(0xFFFFFF, | ||
+ | svgRenderer.setClearColor(0xFFFFFF, | ||
+ | three.appendChild(renderer.domElement); | ||
+ | |||
+ | var frustumSize = 4; | ||
+ | var cameras = [new THREE.PerspectiveCamera(75, | ||
+ | cameras.forEach(function(cam) { | ||
+ | cam.position.set(0, | ||
+ | cam.lookAt(0, | ||
+ | cam.up.set(0, | ||
+ | }); | ||
+ | var controls = [new THREE.TrackballControls(cameras[0], | ||
+ | var camera, control; | ||
+ | |||
+ | controls[0].zoomSpeed = 0.2; | ||
+ | controls[0].rotateSpeed = 4; | ||
+ | |||
+ | |||
+ | // class to allow move points together with labels and spheres | ||
+ | var PMPoint = function (x,y,z) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addLabel = function(labelsprite) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.addSphere = function(spheremesh) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | PMPoint.prototype.set = function(x, | ||
+ | | ||
+ | if (this.sprite) { | ||
+ | this.sprite.position.copy(this.vector); | ||
+ | } | ||
+ | if (this.sphere) { | ||
+ | this.sphere.position.copy(this.vector); | ||
+ | } | ||
+ | } | ||
+ | PMPoint.prototype.radius = function() { | ||
+ | if (this.sphere) { | ||
+ | return this.sphere.geometry.parameters.radius; | ||
+ | } else { | ||
+ | return 0; | ||
+ | } | ||
+ | }; | ||
+ | // select the target node | ||
+ | var target = document.querySelector('# | ||
+ | |||
+ | // create an observer instance | ||
+ | var observer = new MutationObserver(function(mutations) { | ||
+ | | ||
+ | if (mutation.removedNodes && mutation.removedNodes.length > 0) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | // configuration of the observer: | ||
+ | var config = { childList: true, characterData: | ||
+ | |||
+ | // pass in the target node, as well as the observer options | ||
+ | while (target) { | ||
+ | if (target.className==" | ||
+ | observer.observe(target, | ||
+ | break; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | |||
+ | // COMMON_CODE_BLOCK_END | ||
+ | |||
+ | var obj0 = new THREE.Object3D(); | ||
+ | obj0.name = " | ||
+ | obj0.userData.explodable = 1; | ||
+ | obj0.userData.points = []; | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(-2.1, | ||
+ | obj0.userData.points.push(new PMPoint(4.4, | ||
+ | obj0.userData.points.push(new PMPoint(4.4, | ||
+ | |||
+ | obj0.userData.edgeindices = [0, 1, 0, 2, 1, 3, 2, 3]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[0, 2, 3, 1]]; | ||
+ | < | ||
+ | obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj0); | ||
+ | scene.add(obj0); | ||
+ | |||
+ | var obj1 = new THREE.Object3D(); | ||
+ | obj1.name = " | ||
+ | obj1.userData.explodable = 1; | ||
+ | obj1.userData.points = []; | ||
+ | obj1.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 1.1, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(-2.1, | ||
+ | obj1.userData.points.push(new PMPoint(-2.1, | ||
+ | |||
+ | obj1.userData.edgeindices = [0, 1, 0, 2, 1, 3, 2, 3]; | ||
+ | < | ||
+ | obj1.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj1.userData.facets = [[0, 1, 3, 2]]; | ||
+ | < | ||
+ | obj1.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj1); | ||
+ | scene.add(obj1); | ||
+ | |||
+ | var obj2 = new THREE.Object3D(); | ||
+ | obj2.name = " | ||
+ | obj2.userData.explodable = 1; | ||
+ | obj2.userData.points = []; | ||
+ | obj2.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj2.userData.points.push(new PMPoint(0, 0, 1.1)); | ||
+ | obj2.userData.points.push(new PMPoint(-2.1, | ||
+ | obj2.userData.points.push(new PMPoint(-2.1, | ||
+ | |||
+ | obj2.userData.edgeindices = [0, 1, 1, 2, 0, 3, 2, 3]; | ||
+ | < | ||
+ | obj2.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj2.userData.facets = [[0, 1, 2, 3]]; | ||
+ | < | ||
+ | obj2.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj2); | ||
+ | scene.add(obj2); | ||
+ | |||
+ | var obj3 = new THREE.Object3D(); | ||
+ | obj3.name = " | ||
+ | obj3.userData.explodable = 1; | ||
+ | obj3.userData.points = []; | ||
+ | obj3.userData.points.push(new PMPoint(0, 1.1, 0)); | ||
+ | obj3.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj3.userData.points.push(new PMPoint(4.4, | ||
+ | obj3.userData.points.push(new PMPoint(4.4, | ||
+ | |||
+ | obj3.userData.edgeindices = [0, 1, 1, 2, 0, 3, 2, 3]; | ||
+ | < | ||
+ | obj3.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj3.userData.facets = [[1, 0, 3, 2]]; | ||
+ | < | ||
+ | obj3.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj3); | ||
+ | scene.add(obj3); | ||
+ | |||
+ | var obj4 = new THREE.Object3D(); | ||
+ | obj4.name = " | ||
+ | obj4.userData.explodable = 1; | ||
+ | obj4.userData.points = []; | ||
+ | obj4.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj4.userData.points.push(new PMPoint(0, 0, 1.1)); | ||
+ | obj4.userData.points.push(new PMPoint(4.4, | ||
+ | obj4.userData.points.push(new PMPoint(4.4, | ||
+ | |||
+ | obj4.userData.edgeindices = [0, 1, 0, 2, 1, 3, 2, 3]; | ||
+ | < | ||
+ | obj4.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj4.userData.facets = [[0, 1, 3, 2]]; | ||
+ | < | ||
+ | obj4.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj4); | ||
+ | scene.add(obj4); | ||
+ | |||
+ | var obj5 = new THREE.Object3D(); | ||
+ | obj5.name = " | ||
+ | obj5.userData.explodable = 1; | ||
+ | obj5.userData.points = []; | ||
+ | obj5.userData.points.push(new PMPoint(0, 1.1, 0)); | ||
+ | obj5.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj5.userData.points.push(new PMPoint(0, 0, 1.1)); | ||
+ | obj5.userData.points.push(new PMPoint(0, 1.1, 1.1)); | ||
+ | |||
+ | obj5.userData.edgeindices = [0, 1, 1, 2, 0, 3, 2, 3]; | ||
+ | < | ||
+ | obj5.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj5.userData.facets = [[0, 3, 2, 1]]; | ||
+ | < | ||
+ | obj5.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj5); | ||
+ | scene.add(obj5); | ||
+ | |||
+ | var obj6 = new THREE.Object3D(); | ||
+ | obj6.name = " | ||
+ | obj6.userData.explodable = 1; | ||
+ | obj6.userData.points = []; | ||
+ | obj6.userData.points.push(new PMPoint(-1, -1, -1)); | ||
+ | obj6.userData.points.push(new PMPoint(3, 0, 0)); | ||
+ | |||
+ | obj6.userData.edgeindices = [1, 0]; | ||
+ | < | ||
+ | obj6.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0xFF0000, linewidth: 1.5, transparent: | ||
+ | init_object(obj6); | ||
+ | scene.add(obj6); | ||
+ | |||
+ | var obj7 = new THREE.Object3D(); | ||
+ | obj7.name = " | ||
+ | obj7.userData.explodable = 1; | ||
+ | obj7.userData.points = []; | ||
+ | obj7.userData.points.push(new PMPoint(-1, -1, -1)); | ||
+ | obj7.userData.points.push(new PMPoint(-1.73333, | ||
+ | |||
+ | obj7.userData.edgeindices = [1, 0]; | ||
+ | < | ||
+ | obj7.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0xFF0000, linewidth: 1.5, transparent: | ||
+ | init_object(obj7); | ||
+ | scene.add(obj7); | ||
+ | |||
+ | var obj8 = new THREE.Object3D(); | ||
+ | obj8.name = " | ||
+ | obj8.userData.explodable = 1; | ||
+ | obj8.userData.points = []; | ||
+ | obj8.userData.points.push(new PMPoint(-1, -1, -1)); | ||
+ | obj8.userData.points.push(new PMPoint(-1.7, | ||
+ | |||
+ | obj8.userData.edgeindices = [1, 0]; | ||
+ | < | ||
+ | obj8.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0xFF0000, linewidth: 1.5, transparent: | ||
+ | init_object(obj8); | ||
+ | scene.add(obj8); | ||
+ | |||
+ | var obj9 = new THREE.Object3D(); | ||
+ | obj9.name = " | ||
+ | obj9.userData.explodable = 1; | ||
+ | obj9.userData.points = []; | ||
+ | obj9.userData.points.push(new PMPoint(-1, -1, -1)); | ||
+ | obj9.userData.points.push(new PMPoint(-1.7, | ||
+ | |||
+ | obj9.userData.edgeindices = [1, 0]; | ||
+ | < | ||
+ | obj9.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0xFF0000, linewidth: 1.5, transparent: | ||
+ | init_object(obj9); | ||
+ | scene.add(obj9); | ||
+ | |||
+ | var obj10 = new THREE.Object3D(); | ||
+ | obj10.name = " | ||
+ | obj10.userData.explodable = 1; | ||
+ | obj10.userData.points = []; | ||
+ | obj10.userData.points.push(new PMPoint(3, 0, 0)); | ||
+ | obj10.userData.points.push(new PMPoint(4.4, | ||
+ | |||
+ | obj10.userData.edgeindices = [1, 0]; | ||
+ | < | ||
+ | obj10.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0xFF0000, linewidth: 1.5, transparent: | ||
+ | init_object(obj10); | ||
+ | scene.add(obj10); | ||
+ | |||
+ | var obj11 = new THREE.Object3D(); | ||
+ | obj11.name = " | ||
+ | obj11.userData.explodable = 1; | ||
+ | obj11.userData.points = []; | ||
+ | obj11.userData.points.push(new PMPoint(3, 0, 0)); | ||
+ | obj11.userData.points.push(new PMPoint(4.4, | ||
+ | |||
+ | obj11.userData.edgeindices = [1, 0]; | ||
+ | < | ||
+ | obj11.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0xFF0000, linewidth: 1.5, transparent: | ||
+ | init_object(obj11); | ||
+ | scene.add(obj11); | ||
+ | |||
+ | // 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 | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | Alternatively, | ||
+ | |||
+ | <code perl> | ||
+ | > #$m = new Matrix< | ||
+ | > #$mf = polytope:: | ||
+ | > $mf = polytope:: | ||
+ | > compose($l-> | ||
+ | </ | ||
+ | < | ||
+ | <!-- | ||
+ | polymake for knusper | ||
+ | Thu Mar 3 00:27:42 2022 | ||
+ | l | ||
+ | --> | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | <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(5, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj0.userData.points.push(new PMPoint(5, -5, -5)); | ||
+ | obj0.userData.points.push(new PMPoint(-5, -5, -5)); | ||
+ | |||
+ | obj0.userData.edgeindices = [0, 1, 0, 2, 1, 3, 2, 3]; | ||
+ | < | ||
+ | obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj0.userData.facets = [[1, 0, 2, 3]]; | ||
+ | < | ||
+ | obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj0); | ||
+ | scene.add(obj0); | ||
+ | |||
+ | var obj1 = new THREE.Object3D(); | ||
+ | obj1.name = " | ||
+ | obj1.userData.explodable = 1; | ||
+ | obj1.userData.points = []; | ||
+ | obj1.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(0, 5, 0)); | ||
+ | obj1.userData.points.push(new PMPoint(-5, 5, -5)); | ||
+ | obj1.userData.points.push(new PMPoint(-5, -5, -5)); | ||
+ | |||
+ | obj1.userData.edgeindices = [0, 1, 1, 2, 0, 3, 2, 3]; | ||
+ | < | ||
+ | obj1.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj1.userData.facets = [[0, 1, 2, 3]]; | ||
+ | < | ||
+ | obj1.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj1); | ||
+ | scene.add(obj1); | ||
+ | |||
+ | var obj2 = new THREE.Object3D(); | ||
+ | obj2.name = " | ||
+ | obj2.userData.explodable = 1; | ||
+ | obj2.userData.points = []; | ||
+ | obj2.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj2.userData.points.push(new PMPoint(0, 0, 5)); | ||
+ | obj2.userData.points.push(new PMPoint(-5, -5, 5)); | ||
+ | obj2.userData.points.push(new PMPoint(-5, -5, -5)); | ||
+ | |||
+ | obj2.userData.edgeindices = [0, 1, 1, 2, 0, 3, 2, 3]; | ||
+ | < | ||
+ | obj2.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj2.userData.facets = [[0, 1, 2, 3]]; | ||
+ | < | ||
+ | obj2.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj2); | ||
+ | scene.add(obj2); | ||
+ | |||
+ | var obj3 = new THREE.Object3D(); | ||
+ | obj3.name = " | ||
+ | obj3.userData.explodable = 1; | ||
+ | obj3.userData.points = []; | ||
+ | obj3.userData.points.push(new PMPoint(5, 0, 0)); | ||
+ | obj3.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj3.userData.points.push(new PMPoint(0, 5, 0)); | ||
+ | obj3.userData.points.push(new PMPoint(5, 5, 0)); | ||
+ | |||
+ | obj3.userData.edgeindices = [0, 1, 1, 2, 0, 3, 2, 3]; | ||
+ | < | ||
+ | obj3.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj3.userData.facets = [[0, 3, 2, 1]]; | ||
+ | < | ||
+ | obj3.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj3); | ||
+ | scene.add(obj3); | ||
+ | |||
+ | var obj4 = new THREE.Object3D(); | ||
+ | obj4.name = " | ||
+ | obj4.userData.explodable = 1; | ||
+ | obj4.userData.points = []; | ||
+ | obj4.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj4.userData.points.push(new PMPoint(5, 0, 0)); | ||
+ | obj4.userData.points.push(new PMPoint(0, 0, 5)); | ||
+ | obj4.userData.points.push(new PMPoint(5, 0, 5)); | ||
+ | |||
+ | obj4.userData.edgeindices = [0, 1, 0, 2, 1, 3, 2, 3]; | ||
+ | < | ||
+ | obj4.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj4.userData.facets = [[0, 2, 3, 1]]; | ||
+ | < | ||
+ | obj4.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj4); | ||
+ | scene.add(obj4); | ||
+ | |||
+ | var obj5 = new THREE.Object3D(); | ||
+ | obj5.name = " | ||
+ | obj5.userData.explodable = 1; | ||
+ | obj5.userData.points = []; | ||
+ | obj5.userData.points.push(new PMPoint(0, 5, 0)); | ||
+ | obj5.userData.points.push(new PMPoint(0, 0, 0)); | ||
+ | obj5.userData.points.push(new PMPoint(0, 0, 5)); | ||
+ | obj5.userData.points.push(new PMPoint(0, 5, 5)); | ||
+ | |||
+ | obj5.userData.edgeindices = [0, 1, 1, 2, 0, 3, 2, 3]; | ||
+ | < | ||
+ | obj5.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1.5, transparent: | ||
+ | obj5.userData.facets = [[0, 3, 2, 1]]; | ||
+ | < | ||
+ | obj5.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, | ||
+ | init_object(obj5); | ||
+ | scene.add(obj5); | ||
+ | |||
+ | var obj6 = new THREE.Object3D(); | ||
+ | obj6.name = " | ||
+ | obj6.userData.explodable = 1; | ||
+ | obj6.userData.points = []; | ||
+ | obj6.userData.points.push(new PMPoint(-1, -1, -1)); | ||
+ | obj6.userData.points.push(new PMPoint(3, 0, 0)); | ||
+ | |||
+ | obj6.userData.edgeindices = [1, 0]; | ||
+ | < | ||
+ | obj6.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0xFF0000, linewidth: 1.5, transparent: | ||
+ | init_object(obj6); | ||
+ | scene.add(obj6); | ||
+ | |||
+ | var obj7 = new THREE.Object3D(); | ||
+ | obj7.name = " | ||
+ | obj7.userData.explodable = 1; | ||
+ | obj7.userData.points = []; | ||
+ | obj7.userData.points.push(new PMPoint(-1, -1, -1)); | ||
+ | obj7.userData.points.push(new PMPoint(-3.66667, | ||
+ | |||
+ | obj7.userData.edgeindices = [1, 0]; | ||
+ | < | ||
+ | obj7.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0xFF0000, linewidth: 1.5, transparent: | ||
+ | init_object(obj7); | ||
+ | scene.add(obj7); | ||
+ | |||
+ | var obj8 = new THREE.Object3D(); | ||
+ | obj8.name = " | ||
+ | obj8.userData.explodable = 1; | ||
+ | obj8.userData.points = []; | ||
+ | obj8.userData.points.push(new PMPoint(-1, -1, -1)); | ||
+ | obj8.userData.points.push(new PMPoint(-3, 5, -3)); | ||
+ | |||
+ | obj8.userData.edgeindices = [1, 0]; | ||
+ | < | ||
+ | obj8.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0xFF0000, linewidth: 1.5, transparent: | ||
+ | init_object(obj8); | ||
+ | scene.add(obj8); | ||
+ | |||
+ | var obj9 = new THREE.Object3D(); | ||
+ | obj9.name = " | ||
+ | obj9.userData.explodable = 1; | ||
+ | obj9.userData.points = []; | ||
+ | obj9.userData.points.push(new PMPoint(-1, -1, -1)); | ||
+ | obj9.userData.points.push(new PMPoint(-3, -3, 5)); | ||
+ | |||
+ | obj9.userData.edgeindices = [1, 0]; | ||
+ | < | ||
+ | obj9.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0xFF0000, linewidth: 1.5, transparent: | ||
+ | init_object(obj9); | ||
+ | scene.add(obj9); | ||
+ | |||
+ | var obj10 = new THREE.Object3D(); | ||
+ | obj10.name = " | ||
+ | obj10.userData.explodable = 1; | ||
+ | obj10.userData.points = []; | ||
+ | obj10.userData.points.push(new PMPoint(5, 1, 0)); | ||
+ | obj10.userData.points.push(new PMPoint(3, 0, 0)); | ||
+ | |||
+ | obj10.userData.edgeindices = [1, 0]; | ||
+ | < | ||
+ | obj10.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0xFF0000, linewidth: 1.5, transparent: | ||
+ | init_object(obj10); | ||
+ | scene.add(obj10); | ||
+ | |||
+ | var obj11 = new THREE.Object3D(); | ||
+ | obj11.name = " | ||
+ | obj11.userData.explodable = 1; | ||
+ | obj11.userData.points = []; | ||
+ | obj11.userData.points.push(new PMPoint(5, 0, 1)); | ||
+ | obj11.userData.points.push(new PMPoint(3, 0, 0)); | ||
+ | |||
+ | obj11.userData.edgeindices = [1, 0]; | ||
+ | < | ||
+ | obj11.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0xFF0000, linewidth: 1.5, transparent: | ||
+ | init_object(obj11); | ||
+ | scene.add(obj11); | ||
+ | |||
+ | // 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 | ||
+ | |||
+ | });}); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | === Creation functions for commonly used tropical cycles === | ||
+ | |||
+ | == Uniform linear spaces == | ||
+ | |||
+ | As a special case of tropical linear spaces, one can create the space associated to the uniform matroid (with trivial valuation) as '' | ||
+ | |||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | == True linear spaces == | ||
+ | |||
+ | There are creation function for cycles that are supported on an affine linear space. In the special case, that a cycle is the whole projective torus, this can be created via '' | ||
+ | |||
+ | If the cycle is given by a basis of the lineality space and a translation vector, one can use '' | ||
+ | |||
+ | Note that both the generators of the lineality space in the matrix and the translation vector should be given in tropical homogeneous coordinates, | ||
+ | |||
+ | == Halfspace subdivision == | ||
+ | |||
+ | '' | ||
+ | |||
+ | == Matroid fans == | ||
+ | |||
+ | A-tint uses the algorithms developped by Felipe Rincón to compute matroidal fans. The original algorithm was developed for matrix matroids but has been adapted here to also work on general matroids. You compute a matroidal fan via '' | ||
+ | |||
+ | === Operations on tropical varieties === | ||
+ | |||
+ | == Computing the cartesian product == | ||
+ | |||
+ | The function '' | ||
+ | |||
+ | <code perl> | ||
+ | > $p = cartesian_product(uniform_linear_space< | ||
+ | </ | ||
+ | == Computing the skeleton == | ||
+ | |||
+ | This is actually an operation on polyhedral complexes, since taking the skeleton forgets the weights. The function '' | ||
+ | |||
+ | == Comparing complexes == | ||
+ | |||
+ | You can check if two polyhedral complexes are exactly the same, i.e. have the same rays, cones and weights up to reordering and equivalence of tropical coordinates, | ||
+ | |||
+ | == Refining == | ||
+ | |||
+ | You can refine a weighted complex along any other complex containing it (as a set), using the function '' | ||
+ | |||
+ | === Local computations === | ||
+ | |||
+ | a-tint has a mechanism to allow computations locally around a given set of cones: Each Cycle has a property LOCAL_RESTRICTION. This is an IncidenceMatrix (or list of sets of ray indices). Each of these sets of ray indices is supposed to describe a cone of the complex - though not necessarily a maximal one. | ||
+ | |||
+ | If you define a complex with this property, then all computations will only be done " | ||
+ | |||
+ | **Note:** It is important, that all maximal cones of a restricted complex contain one of the LOCAL_RESTRICTION cones. | ||
+ | |||
+ | This way a bounded complex can also be made " | ||
+ | |||
+ | <code perl> | ||
+ | > $w = new Cycle< | ||
+ | > print $w-> | ||
+ | true | ||
+ | </ | ||
+ | The above example describes the bounded line segment $[-1,1] \in \mathbb R$, subdivided at 0. Since we restrict ourselves locally to the vertex 0, the outer codimension one faces are not detected by a-tint and the complex is balanced. | ||
+ | |||
+ | This can improve computation speed, e.g. when one is only interested in the weight of a divisor at a certain cone. | ||
+ | |||
+ | There are some convenience functions to create a local variety from a global one: | ||
+ | |||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | Some examples: | ||
+ | |||
+ | <code perl> | ||
+ | > $x = uniform_linear_space< | ||
+ | > $x1 = local_restrict($x, | ||
+ | > #The tropical hyperplane, locally around the 0-th ray and the maximal cone spanned by rays 2 and 3. | ||
+ | > #As a set this can be interpreted as the union of an open neighborhood of ray 0 and the interior of the maximal | ||
+ | > #cone <2,3> | ||
+ | > $x2 = local_vertex($x, | ||
+ | > $x3 = local_codim_one($x, | ||
+ | > $x4 = local_point($x, | ||
+ | > #Refines the surface such that it contains the point (0,1,1,0), then takes an open neighborhood of that | ||
+ | </ | ||
+ | For details see the internal documentation of these functions. | ||
+ | |||
+ | === Delocalizing === | ||
+ | |||
+ | If you have a locally restricted complex and you would like to obtain the same complex without the LOCAL_RESTRICTION, | ||
+ | |||
+ | <code perl> | ||
+ | > $y = $x-> | ||
+ | </ | ||