1{
2 "cells": [
3  {
4   "cell_type": "markdown",
5   "metadata": {},
6   "source": [
7    "## ILP and Hilbert bases\n",
8    "\n",
9    "### A first example\n",
10    "\n",
11    "First we will construct a new rational polytope:\n",
12    "\n",
13    "    \n"
14   ]
15  },
16  {
17   "cell_type": "code",
18   "execution_count": 1,
19   "metadata": {},
20   "outputs": [],
21   "source": [
22    "$p=new Polytope<Rational>;"
23   ]
24  },
25  {
26   "cell_type": "markdown",
27   "metadata": {},
28   "source": [
29    "    \n"
30   ]
31  },
32  {
33   "cell_type": "code",
34   "execution_count": 2,
35   "metadata": {},
36   "outputs": [],
37   "source": [
38    "$p->POINTS=<<\".\";\n",
39    "1 0 0 0\n",
40    "1 1 0 0\n",
41    "1 0 1 0\n",
42    "1 1 1 0\n",
43    "1 0 0 1\n",
44    "1 1 0 1\n",
45    "1 0 1 1\n",
46    "1 1 1 1\n",
47    "."
48   ]
49  },
50  {
51   "cell_type": "markdown",
52   "metadata": {},
53   "source": [
54    "\n",
55    "Note that points in `polymake` are always given in homogenous coordinates. I.e., the point (a,b,c) in R<sup>3</sup> is represented as `1 a b c` in `polymake`.\n",
56    "\n",
57    "Now we can examine some properties of `$p`. For instance we can determine the number of facets or whether `$p` is simple:\n",
58    "\n",
59    "    \n"
60   ]
61  },
62  {
63   "cell_type": "code",
64   "execution_count": 3,
65   "metadata": {},
66   "outputs": [
67    {
68     "data": {
69      "text/plain": [
70       "6"
71      ]
72     },
73     "execution_count": 3,
74     "metadata": {},
75     "output_type": "execute_result"
76    },
77    {
78     "data": {
79      "text/html": [
80       "<details><summary><pre style=\"display:inline\"><small>Click here for additional output</small></pre></summary>\n",
81       "<pre>\n",
82       "polymake: used package cdd\n",
83       "  cddlib\n",
84       "  Implementation of the double description method of Motzkin et al.\n",
85       "  Copyright by Komei Fukuda.\n",
86       "  http://www-oldurls.inf.ethz.ch/personal/fukudak/cdd_home/\n",
87       "\n",
88       "polymake: used package lrs\n",
89       "  Implementation of the reverse search algorithm of Avis and Fukuda.\n",
90       "  Copyright by David Avis.\n",
91       "  http://cgm.cs.mcgill.ca/~avis/C/lrs.html\n",
92       "\n",
93       "</pre>\n",
94       "</details>\n"
95      ]
96     },
97     "metadata": {},
98     "output_type": "display_data"
99    }
100   ],
101   "source": [
102    "print $p->N_FACETS;"
103   ]
104  },
105  {
106   "cell_type": "code",
107   "execution_count": 4,
108   "metadata": {},
109   "outputs": [
110    {
111     "data": {
112      "text/plain": [
113       "true"
114      ]
115     },
116     "execution_count": 4,
117     "metadata": {},
118     "output_type": "execute_result"
119    }
120   ],
121   "source": [
122    "print $p->SIMPLE;"
123   ]
124  },
125  {
126   "cell_type": "markdown",
127   "metadata": {},
128   "source": [
129    "\n",
130    "As you might already have noticed, our polytope is just a 3-dimensional cube. So there would have been an easier way to create it using the client `cube`:\n",
131    "\n",
132    "    \n"
133   ]
134  },
135  {
136   "cell_type": "code",
137   "execution_count": 5,
138   "metadata": {},
139   "outputs": [],
140   "source": [
141    "$c = cube(3,0);"
142   ]
143  },
144  {
145   "cell_type": "markdown",
146   "metadata": {},
147   "source": [
148    "(You can check out the details of any function in the [documentation](https://polymake.org/doku.php/documentation/latest/polytope).)\n",
149    "\n",
150    "And we can also verify that the two polytopes are actually equal:"
151   ]
152  },
153  {
154   "cell_type": "code",
155   "execution_count": 6,
156   "metadata": {},
157   "outputs": [
158    {
159     "data": {
160      "text/plain": [
161       "true"
162      ]
163     },
164     "execution_count": 6,
165     "metadata": {},
166     "output_type": "execute_result"
167    }
168   ],
169   "source": [
170    "print equal_polyhedra($p,$c);"
171   ]
172  },
173  {
174   "cell_type": "markdown",
175   "metadata": {},
176   "source": [
177    "### Another example\n",
178    "\n",
179    "Now let us proceed with a somewhat more interesting example: The convex hull of 20 randomly chosen points on the 2-dimensional sphere."
180   ]
181  },
182  {
183   "cell_type": "code",
184   "execution_count": 7,
185   "metadata": {},
186   "outputs": [],
187   "source": [
188    "$rs = rand_sphere(3,20);"
189   ]
190  },
191  {
192   "cell_type": "markdown",
193   "metadata": {},
194   "source": [
195    "\n",
196    "\n",
197    "`polymake` can of course visualise this polytope:\n",
198    "\n",
199    "    \n"
200   ]
201  },
202  {
203   "cell_type": "code",
204   "execution_count": 8,
205   "metadata": {},
206   "outputs": [
207    {
208     "data": {
209      "text/html": [
210       "<!--\n",
211       "polymake for knusper\n",
212       "Thu Aug 27 11:38:20 2020\n",
213       "rs\n",
214       "-->\n",
215       "\n",
216       "\n",
217       "<html>\n",
218       "   <head>\n",
219       "      <meta charset=utf-8>\n",
220       "      <title>rs</title>\n",
221       "      <style>\n",
222       "/*\n",
223       "// COMMON_CODE_BLOCK_BEGIN\n",
224       "*/\n",
225       "         html {overflow: scroll;}\n",
226       "         strong{font-size: 18px;}\n",
227       "         canvas { z-index: 8; }\n",
228       "         input[type='radio'] {margin-left:0;}\n",
229       "         input[type='checkbox'] {margin-right:7px; margin-left: 0px; padding-left:0px;}\n",
230       "         .group{padding-bottom: 15px;}\n",
231       "         .settings * {z-index: 11; }\n",
232       "         .settings{z-index: 10; font-family: Arial, Helvetica, sans-serif; margin-left: 30px; visibility: hidden; width: 14em; height: 96%; border: solid 1px silver; padding: 2px; overflow-y: scroll; box-sizing: border-box; background-color: white; position: absolute;}\n",
233       "         .indented{margin-left: 20px; margin-top: 10px; padding-bottom: 0px;} \n",
234       "         .shownObjectsList{overflow: auto; max-width: 150px; max-height: 150px;}\n",
235       "         .showSettingsButton{visibility: visible; z-index: 12; position: absolute }\n",
236       "         .hideSettingsButton{visibility: hidden; z-index: 12; position: absolute; opacity: 0.5}\n",
237       "         button{margin-left: 0; margin-top: 10px}\n",
238       "         img{cursor: pointer;}\n",
239       "         .suboption{padding-top: 15px;}\n",
240       "         #model333753212 { width: 100%; height: 100%; }\n",
241       "         .threejs_container { width: 100%; height: 75vh;}\n",
242       "         .settings{max-height: 74vh} \n",
243       "         input[type=range] {\n",
244       "           -webkit-appearance: none;\n",
245       "           padding:0; \n",
246       "           width:90%; \n",
247       "           margin-left: auto;\n",
248       "           margin-right: auto;\n",
249       "           margin-top: 15px;\n",
250       "           margin-bottom: 15px;\n",
251       "           display: block;\t\n",
252       "         }\n",
253       "         input[type=range]:focus {\n",
254       "           outline: none;\n",
255       "         }\n",
256       "         input[type=range]::-webkit-slider-runnable-track {\n",
257       "           height: 4px;\n",
258       "           cursor: pointer;\n",
259       "           animate: 0.2s;\n",
260       "           box-shadow: 0px 0px 0px #000000;\n",
261       "           background: #E3E3E3;\n",
262       "           border-radius: 0px;\n",
263       "           border: 0px solid #000000;\n",
264       "         }\n",
265       "         input[type=range]::-webkit-slider-thumb {\n",
266       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
267       "           border: 1px solid #ABABAB;\n",
268       "           height: 13px;\n",
269       "           width: 25px;\n",
270       "           border-radius: 20px;\n",
271       "           background: #E0E0E0;\n",
272       "           cursor: pointer;\n",
273       "           -webkit-appearance: none;\n",
274       "           margin-top: -5px;\n",
275       "         }\n",
276       "         input[type=range]:focus::-webkit-slider-runnable-track {\n",
277       "           background: #E3E3E3;\n",
278       "         }\n",
279       "         input[type=range]::-moz-range-track {\n",
280       "           height: 4px;\n",
281       "           cursor: pointer;\n",
282       "           animate: 0.2s;\n",
283       "           box-shadow: 0px 0px 0px #000000;\n",
284       "           background: #E3E3E3;\n",
285       "           border-radius: 0px;\n",
286       "           border: 0px solid #000000;\n",
287       "         }\n",
288       "         input[type=range]::-moz-range-thumb {\n",
289       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
290       "           border: 1px solid #ABABAB;\n",
291       "           height: 13px;\n",
292       "           width: 25px;\n",
293       "           border-radius: 20px;\n",
294       "           background: #E0E0E0;\n",
295       "           cursor: pointer;\n",
296       "         }\n",
297       "         input[type=range]::-ms-track {\n",
298       "           height: 4px;\n",
299       "           cursor: pointer;\n",
300       "           animate: 0.2s;\n",
301       "           background: transparent;\n",
302       "           border-color: transparent;\n",
303       "           color: transparent;\n",
304       "         }\n",
305       "         input[type=range]::-ms-fill-lower {\n",
306       "           background: #E3E3E3;\n",
307       "           border: 0px solid #000000;\n",
308       "           border-radius: 0px;\n",
309       "           box-shadow: 0px 0px 0px #000000;\n",
310       "         }\n",
311       "         input[type=range]::-ms-fill-upper {\n",
312       "           background: #E3E3E3;\n",
313       "           border: 0px solid #000000;\n",
314       "           border-radius: 0px;\n",
315       "           box-shadow: 0px 0px 0px #000000;\n",
316       "         }\n",
317       "         input[type=range]::-ms-thumb {\n",
318       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
319       "           border: 1px solid #ABABAB;\n",
320       "           height: 13px;\n",
321       "           width: 25px;\n",
322       "           border-radius: 20px;\n",
323       "           background: #E0E0E0;\n",
324       "           cursor: pointer;\n",
325       "         }\n",
326       "         input[type=range]:focus::-ms-fill-lower {\n",
327       "           background: #E3E3E3;\n",
328       "         }\n",
329       "         input[type=range]:focus::-ms-fill-upper {\n",
330       "           background: #E3E3E3;\n",
331       "         }\n",
332       "/*\n",
333       "// COMMON_CODE_BLOCK_END\n",
334       "*/\n",
335       "\t\t</style>\n",
336       "   </head>\n",
337       "<body>\n",
338       "   <div class='threejs_container'>\n",
339       "\t\t<div id='settings_0' class='settings'>\n",
340       "\t\t\t<div class=group id='transparency_0' class='transparency'>\n",
341       "\t\t\t\t<strong>Transparency</strong>\n",
342       "\t\t\t\t<input id='transparencyRange_0' type='range' min=0 max=1 step=0.01 value=0>\n",
343       "\t\t\t</div>\n",
344       "\t\t\t\n",
345       "\t\t\t<div class=group id='rotation_0'>\n",
346       "\t\t\t\t<strong>Rotation</strong>\n",
347       "\t\t\t\t<div class=indented>\n",
348       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationX_0'> x-axis</div>\n",
349       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationY_0'> y-axis</div>\n",
350       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationZ_0'> z-axis</div>\n",
351       "\t\t\t\t\t<button id='resetButton_0'>Reset</button>\n",
352       "\t\t\t\t</div>\n",
353       "\n",
354       "\t\t\t\t<div class=suboption>Rotation speed</div>\n",
355       "\t\t\t\t<input id='rotationSpeedRange_0' type='range' min=0 max=5 step=0.01 value=2>\n",
356       "\t\t\t</div>\n",
357       "\n",
358       "\n",
359       "\t\t\t<div class=group id='display_0'>\n",
360       "\t\t\t\t<strong>Display</strong>\n",
361       "\t\t\t\t<div class=indented>\n",
362       "\t\t\t\t\t<div id='shownObjectTypesList_0' class='shownObjectsList'></div>\n",
363       "\t\t\t\t</div>\n",
364       "\t\t\t\t<div class=suboption>Objects</div>\n",
365       "\t\t\t\t<div class=indented>\n",
366       "\t\t\t\t   <div id='shownObjectsList_0' class='shownObjectsList'></div>\n",
367       "\t\t\t\t</div>\n",
368       "\t\t\t</div>\n",
369       "         \n",
370       "         <div class=group id='camera_0'>\n",
371       "            <strong>Camera</strong>\n",
372       "            <div class=indented>\n",
373       "               <form>\n",
374       "                  <select id=\"cameraType_0\">\n",
375       "                     <option value='perspective' selected> Perspective<br></option>\n",
376       "                     <option value='orthographic' > Orthographic<br></option>\n",
377       "                  </select>\n",
378       "               </form>\n",
379       "            </div>\n",
380       "         </div>\n",
381       "\n",
382       "\t\t\t<div class=group id='svg_0'>\n",
383       "\t\t\t\t<strong>SVG</strong>\n",
384       "\t\t\t\t<div class=indented>\n",
385       "\t\t\t\t\t<form>\n",
386       "\t\t\t\t\t\t<input type=\"radio\" name='screenshotMode' value='download' id='download_0' checked> Download<br>\n",
387       "\t\t\t\t\t\t<input type=\"radio\" name='screenshotMode' value='tab' id='tab_0' > New tab<br>\n",
388       "\t\t\t\t\t</form>\n",
389       "\t\t\t\t\t<button id='takeScreenshot_0'>Screenshot</button>\n",
390       "\t\t\t\t</div>\n",
391       "\t\t\t</div>\n",
392       "\n",
393       "\t\t</div>\t<!-- end of settings -->\n",
394       "\t\t<img id='hideSettingsButton_0' class='hideSettingsButton' src='/kernelspecs/polymake/close.svg' width=20px\">\n",
395       "\t\t<img id='showSettingsButton_0' class='showSettingsButton' src='/kernelspecs/polymake/menu.svg' width=20px\">\n",
396       "<div id=\"model333753212\"></div>\n",
397       "</div>\n",
398       "   <script>\n",
399       "    requirejs.config({\n",
400       "      paths: {\n",
401       "        three: '/kernelspecs/polymake/three',\n",
402       "        TrackballControls: '/kernelspecs/polymake/TrackballControls',\n",
403       "        OrbitControls: '/kernelspecs/polymake/OrbitControls',\n",
404       "        Projector: '/kernelspecs/polymake/Projector',\n",
405       "        SVGRenderer: '/kernelspecs/polymake/SVGRenderer',\n",
406       "        WEBGL: '/kernelspecs/polymake/WebGL',\n",
407       "      },\n",
408       "      shim: {\n",
409       "        'three': { exports: 'THREE'},\n",
410       "        'SVGRenderer': { deps: [ 'three' ], exports: 'THREE.SVGRenderer' },\n",
411       "        'WEBGL': { deps: [ 'three' ], exports: 'THREE.WEBGL' },\n",
412       "        'Projector': { deps: [ 'three' ], exports: 'THREE.Projector' },\n",
413       "        'TrackballControls': { deps: [ 'three' ], exports: 'THREE.TrackballControls' },\n",
414       "        'OrbitControls': { deps: [ 'three' ], exports: 'THREE.OrbitControls' },\n",
415       "      }\n",
416       "    });\n",
417       "    \n",
418       "    require(['three'],function(THREE){\n",
419       "        window.THREE = THREE;\n",
420       "      require(['TrackballControls', 'OrbitControls', 'Projector', 'SVGRenderer', 'WEBGL'],\n",
421       "               function(TrackballControls, OrbitControls, Projector, SVGRenderer, WEBGL) {\n",
422       "    THREE.TrackballControls = TrackballControls;\n",
423       "    THREE.OrbitControls = OrbitControls;\n",
424       "    THREE.Projector = Projector;\n",
425       "    THREE.SVGRenderer = SVGRenderer;\n",
426       "    THREE.WEBGL = WEBGL;\n",
427       "\n",
428       "// COMMON_CODE_BLOCK_BEGIN\n",
429       "\n",
430       "const intervalLength = 25; // for automatic animations\n",
431       "const explodableModel = false; \n",
432       "const modelContains = { points: false, pointlabels: false, lines: false, edgelabels: false, faces: false, arrowheads: false };\n",
433       "const foldables = [];\n",
434       "\n",
435       "var three = document.getElementById(\"model333753212\");\n",
436       "var scene = new THREE.Scene();\n",
437       "var renderer = new THREE.WebGLRenderer( { antialias: true } );\n",
438       "var svgRenderer = new THREE.SVGRenderer( { antialias: true } );\n",
439       "renderer.setPixelRatio( window.devicePixelRatio );\n",
440       "renderer.setClearColor(0xFFFFFF, 1);\n",
441       "svgRenderer.setClearColor(0xFFFFFF, 1);\n",
442       "three.appendChild(renderer.domElement);\n",
443       "\n",
444       "var frustumSize = 4;\n",
445       "var cameras = [new THREE.PerspectiveCamera(75, 1, 0.1, 1000), new THREE.OrthographicCamera()];\n",
446       "cameras.forEach(function(cam) {\n",
447       "    cam.position.set(0, 0, 5);\n",
448       "    cam.lookAt(0, 0, 0);  \n",
449       "    cam.up.set(0, 1, 0);         \n",
450       "});\n",
451       "var controls = [new THREE.TrackballControls(cameras[0], three), new THREE.OrbitControls(cameras[1], three)];\n",
452       "var camera, control;\n",
453       "\n",
454       "controls[0].zoomSpeed = 0.2;\n",
455       "controls[0].rotateSpeed = 4;\n",
456       "\n",
457       "\n",
458       "// class to allow move points together with labels and spheres\n",
459       "var PMPoint = function (x,y,z) {\n",
460       "   this.vector = new THREE.Vector3(x,y,z);\n",
461       "   this.sprite = null;\n",
462       "   this.sphere = null;\n",
463       "}\n",
464       "PMPoint.prototype.addLabel = function(labelsprite) {\n",
465       "   this.sprite = labelsprite;\n",
466       "   this.sprite.position.copy(this.vector);\n",
467       "}\n",
468       "PMPoint.prototype.addSphere = function(spheremesh) {\n",
469       "   this.sphere = spheremesh;\n",
470       "   this.sphere.position.copy(this.vector);\n",
471       "}\n",
472       "PMPoint.prototype.set = function(x,y,z) {\n",
473       "   this.vector.set(x,y,z);\n",
474       "   if (this.sprite) {\n",
475       "      this.sprite.position.copy(this.vector);\n",
476       "   }\n",
477       "   if (this.sphere) {\n",
478       "      this.sphere.position.copy(this.vector);\n",
479       "   }\n",
480       "}\n",
481       "PMPoint.prototype.radius = function() {\n",
482       "   if (this.sphere) {\n",
483       "      return this.sphere.geometry.parameters.radius;\n",
484       "   } else {\n",
485       "      return 0;\n",
486       "   }\n",
487       "};\n",
488       "// select the target node\n",
489       "var target = document.querySelector('#model333753212');\n",
490       "\n",
491       "// create an observer instance\n",
492       "var observer = new MutationObserver(function(mutations) {\n",
493       "   mutations.forEach(function(mutation) {\n",
494       "      if (mutation.removedNodes && mutation.removedNodes.length > 0) {\n",
495       "         cancelAnimationFrame(renderId);\n",
496       "         observer.disconnect();\n",
497       "         console.log(\"cancelled frame \"+renderId);\n",
498       "      }\n",
499       "   });\n",
500       "});\n",
501       "\n",
502       "// configuration of the observer:\n",
503       "var config = { childList: true, characterData: true }\n",
504       "\n",
505       "// pass in the target node, as well as the observer options\n",
506       "while (target) {\n",
507       "   if (target.className==\"output\") {\n",
508       "      observer.observe(target, config);\n",
509       "      break;\n",
510       "   }\n",
511       "   target = target.parentNode;\n",
512       "}\n",
513       "\n",
514       "// COMMON_CODE_BLOCK_END\n",
515       "\n",
516       "var obj0 = new THREE.Object3D();\n",
517       "obj0.name = \"rs\";\n",
518       "obj0.userData.explodable = 1;\n",
519       "obj0.userData.points = [];\n",
520       "obj0.userData.points.push(new PMPoint(-0.504544, -0.245877, 0.827635));\n",
521       "obj0.userData.points.push(new PMPoint(-0.171247, -0.983096, 0.0647788));\n",
522       "obj0.userData.points.push(new PMPoint(0.397165, -0.503251, 0.767462));\n",
523       "obj0.userData.points.push(new PMPoint(-0.818591, -0.555017, -0.14787));\n",
524       "obj0.userData.points.push(new PMPoint(-0.63444, -0.162518, -0.755695));\n",
525       "obj0.userData.points.push(new PMPoint(-0.255875, 0.908972, -0.329087));\n",
526       "obj0.userData.points.push(new PMPoint(-0.272367, 0.0328207, -0.961633));\n",
527       "obj0.userData.points.push(new PMPoint(0.877439, 0.3782, 0.295069));\n",
528       "obj0.userData.points.push(new PMPoint(0.431367, 0.406399, -0.805458));\n",
529       "obj0.userData.points.push(new PMPoint(-0.977942, 0.158118, 0.136482));\n",
530       "obj0.userData.points.push(new PMPoint(0.266113, 0.0658087, 0.961693));\n",
531       "obj0.userData.points.push(new PMPoint(-0.554078, -0.390684, -0.735094));\n",
532       "obj0.userData.points.push(new PMPoint(0.795907, 0.0333783, -0.604498));\n",
533       "obj0.userData.points.push(new PMPoint(0.0805864, 0.981181, 0.17547));\n",
534       "obj0.userData.points.push(new PMPoint(-0.940302, -0.334343, 0.0636122));\n",
535       "obj0.userData.points.push(new PMPoint(-0.204604, 0.111891, 0.972429));\n",
536       "obj0.userData.points.push(new PMPoint(-0.446011, -0.474317, -0.759011));\n",
537       "obj0.userData.points.push(new PMPoint(-0.949291, 0.215985, -0.228466));\n",
538       "obj0.userData.points.push(new PMPoint(-0.583256, -0.0822278, -0.808115));\n",
539       "obj0.userData.points.push(new PMPoint(0.166539, 0.0625275, 0.98405));\n",
540       "\n",
541       "obj0.userData.pointradii = 0.02;\n",
542       "   <!-- Vertex style -->\n",
543       "obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
544       "obj0.userData.pointlabels = [\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\"];\n",
545       "obj0.userData.edgeindices = [0, 1, 0, 2, 1, 2, 1, 3, 3, 4, 5, 6, 2, 7, 5, 8, 6, 8, 7, 8, 0, 9, 5, 9, 2, 10, 7, 10, 3, 11, 4, 11, 1, 12, 2, 12, 6, 12, 7, 12, 8, 12, 5, 13, 7, 13, 8, 13, 9, 13, 10, 13, 0, 14, 1, 14, 3, 14, 9, 14, 0, 15, 9, 15, 13, 15, 1, 16, 3, 16, 6, 16, 11, 16, 12, 16, 3, 17, 4, 17, 5, 17, 9, 17, 14, 17, 4, 18, 5, 18, 6, 18, 11, 18, 16, 18, 17, 18, 0, 19, 2, 19, 10, 19, 13, 19, 15, 19];\n",
546       "   <!-- Edge style -->\n",
547       "obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
548       "obj0.userData.facets = [[12, 6, 8], [16, 6, 12], [12, 1, 16], [12, 2, 1], [2, 10, 19], [2, 19, 0], [1, 2, 0], [13, 15, 19], [15, 0, 19], [16, 1, 3], [1, 0, 14], [1, 14, 3], [5, 6, 18], [5, 18, 17], [5, 17, 9], [11, 16, 3], [18, 16, 11], [18, 11, 4], [11, 3, 4], [17, 4, 3], [17, 3, 14], [9, 17, 14], [17, 18, 4], [9, 14, 0], [18, 6, 16], [15, 9, 0], [13, 5, 9], [13, 9, 15], [10, 13, 19], [8, 6, 5], [8, 5, 13], [7, 8, 13], [7, 13, 10], [2, 7, 10], [12, 7, 2], [12, 8, 7]];\n",
549       "   <!-- Facet style -->\n",
550       "obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
551       "init_object(obj0);\n",
552       "scene.add(obj0);\n",
553       "\n",
554       "// COMMON_CODE_BLOCK_BEGIN\n",
555       "function textSpriteMaterial(message, parameters) {\n",
556       "    if ( parameters === undefined ) parameters = {};\n",
557       "    var fontface = \"Helvetica\";\n",
558       "    var fontsize = parameters.hasOwnProperty(\"fontsize\") ? parameters[\"fontsize\"] : 15;\n",
559       "    fontsize = fontsize*10;\n",
560       "    var lines = message.split('\\\\n');\n",
561       "    var size = 512;\n",
562       "    for(var i = 0; i<lines.length; i++){\n",
563       "        var tmp = lines[i].length;\n",
564       "        while(tmp*fontsize > size){\n",
565       "           fontsize--;\n",
566       "        }\n",
567       "    }\n",
568       "    \n",
569       "    var canvas = document.createElement('canvas');\n",
570       "    canvas.width = size;\n",
571       "    canvas.height = size;\n",
572       "    var context = canvas.getContext('2d');\n",
573       "    context.fillStyle = \"rgba(255, 255, 255, 0)\";\n",
574       "    context.fill();\n",
575       "    context.font = fontsize + \"px \" + fontface;\n",
576       "    \n",
577       "    // text color\n",
578       "    context.fillStyle = \"rgba(0, 0, 0, 1.0)\";\n",
579       "     for(var i = 0; i<lines.length; i++){\n",
580       "        context.fillText(lines[i], size/2, size/2+i*fontsize);\n",
581       "     }\n",
582       "    \n",
583       "    // canvas contents will be used for a texture\n",
584       "    var texture = new THREE.Texture(canvas);\n",
585       "    texture.needsUpdate = true;\n",
586       "    \n",
587       "    var spriteMaterial = new THREE.SpriteMaterial({map: texture, depthTest: true, depthWrite: false, polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: 1 });\n",
588       "    return spriteMaterial;\n",
589       "}\n",
590       "\n",
591       "\n",
592       "// ---------------------- INITIALIZING OBJECTS--------------------------------------\n",
593       "// ---------------------------------------------------------------------------------\n",
594       "\n",
595       "function init_object(obj) {\n",
596       "    if (obj.userData.hasOwnProperty(\"pointmaterial\")) {\n",
597       "        init_points(obj);\n",
598       "        modelContains.points = true;\n",
599       "    }\n",
600       "    if (obj.userData.hasOwnProperty(\"pointlabels\")) {\n",
601       "        init_pointlabels(obj);\n",
602       "        modelContains.pointlabels = true;\n",
603       "    }\n",
604       "    if (obj.userData.hasOwnProperty(\"edgematerial\")) {\n",
605       "        init_lines(obj);\n",
606       "        modelContains.lines = true;\n",
607       "    }\n",
608       "    if (obj.userData.hasOwnProperty(\"edgelabels\")) {\n",
609       "        init_edgelabels(obj);\n",
610       "        modelContains.edgelabels = true;\n",
611       "    }\n",
612       "    if (obj.userData.hasOwnProperty(\"arrowstyle\")) {\n",
613       "        init_arrowheads(obj);\n",
614       "        modelContains.arrowheads = true;\n",
615       "    }\n",
616       "    if (obj.userData.hasOwnProperty(\"facetmaterial\")) {\n",
617       "        init_faces(obj);\n",
618       "        modelContains.faces = true;\n",
619       "    }\n",
620       "}\n",
621       "\n",
622       "function init_points(obj) {\n",
623       "    var pointgroup = new THREE.Group();\n",
624       "    pointgroup.name = \"points\";\n",
625       "    var points = obj.userData.points;\n",
626       "    var radii = obj.userData.pointradii;\n",
627       "    var materials = obj.userData.pointmaterial;\n",
628       "    var geometry,material;\n",
629       "    if (!Array.isArray(radii)) {\n",
630       "        geometry = new THREE.SphereBufferGeometry(radii);  \n",
631       "    }\n",
632       "    if (!Array.isArray(materials)) {\n",
633       "        material = materials;\n",
634       "    }\n",
635       "    for (var i=0; i<points.length; i++) {\n",
636       "        var point = points[i];\n",
637       "        if (Array.isArray(radii)) {\n",
638       "            if (radii[i] == 0) {\n",
639       "                continue;\n",
640       "            }\n",
641       "            geometry = new THREE.SphereBufferGeometry(radii[i]);  \n",
642       "        } \n",
643       "        if (Array.isArray(materials)) {\n",
644       "            material = materials[i];     \n",
645       "        } \n",
646       "        var sphere = new THREE.Mesh(geometry, material);\n",
647       "        point.addSphere(sphere);\n",
648       "        pointgroup.add(sphere);\n",
649       "    }\n",
650       "    obj.add(pointgroup);\n",
651       "}\n",
652       "\n",
653       "function init_pointlabels(obj) {\n",
654       "    var points = obj.userData.points;\n",
655       "    var labels = obj.userData.pointlabels;\n",
656       "    var pointlabels = new THREE.Group();\n",
657       "    pointlabels.name = \"pointlabels\";\n",
658       "    if (Array.isArray(labels)) {\n",
659       "        for (var i=0; i<points.length; i++) {\n",
660       "            var point = points[i];\n",
661       "            var spriteMaterial = textSpriteMaterial( labels[i] );\n",
662       "\t        var sprite = new THREE.Sprite(spriteMaterial);\n",
663       "            point.addLabel(sprite);\n",
664       "            pointlabels.add(sprite);\n",
665       "        }\n",
666       "    } else {\n",
667       "        var spriteMaterial = textSpriteMaterial( labels );\n",
668       "        for (var i=0; i<points.length; i++) {\n",
669       "            var point = points[i];\n",
670       "\t        var sprite = new THREE.Sprite(spriteMaterial);\n",
671       "            point.addLabel(sprite);\n",
672       "            pointlabels.add(sprite);\n",
673       "        }\n",
674       "    }\n",
675       "    obj.add(pointlabels);\n",
676       "}\n",
677       "\n",
678       "function init_lines(obj) {\n",
679       "    var edgeindices = obj.userData.edgeindices;\n",
680       "    var points = obj.userData.points;\n",
681       "    var materials = obj.userData.edgematerial;\n",
682       "    var geometry = new THREE.BufferGeometry();\n",
683       "    var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 );\n",
684       "    var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 );\n",
685       "    var geometry = new THREE.BufferGeometry();\n",
686       "    geometry.setAttribute('position', bufattr);\n",
687       "    if (Array.isArray(materials)) {     \n",
688       "        for (var i=0; i<materials.length; i++) {\n",
689       "            geometry.addGroup(2*i,2,i);\n",
690       "        }\n",
691       "    }\n",
692       "    var lines = new THREE.LineSegments(geometry, materials);\n",
693       "    lines.name = \"lines\";\n",
694       "    obj.add(lines);\n",
695       "    updateEdgesPosition(obj);\n",
696       "}\n",
697       "\n",
698       "function init_edgelabels(obj) {\n",
699       "    var points = obj.userData.points;\n",
700       "    var edgeindices = obj.userData.edgeindices;\n",
701       "    var labels = obj.userData.edgelabels;\n",
702       "    var edgelabels = new THREE.Group();\n",
703       "    edgelabels.name = \"edgelabels\";\n",
704       "    if (Array.isArray(labels)) {\n",
705       "        for (var i=0; i<edgeindices.length; i=i+2) {\n",
706       "            var point = points[i];\n",
707       "            var spriteMaterial = textSpriteMaterial( labels[i] );\n",
708       "            var sprite = new THREE.Sprite(spriteMaterial);\n",
709       "            sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5));\n",
710       "            edgelabels.add(sprite);\n",
711       "        }\n",
712       "    } else {\n",
713       "        var spriteMaterial = textSpriteMaterial( labels );\n",
714       "        for (var i=0; i<points.length; i++) {\n",
715       "            var point = points[i];\n",
716       "            var sprite = new THREE.Sprite(spriteMaterial);\n",
717       "            sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5));\n",
718       "            pointlabels.add(sprite);\n",
719       "        }\n",
720       "    }\n",
721       "    obj.add(edgelabels);\n",
722       "}\n",
723       "\n",
724       "function init_arrowheads(obj) {\n",
725       "    var arrowheads = new THREE.Group();\n",
726       "    arrowheads.name = \"arrowheads\";\n",
727       "    var arrowstyle = obj.userData.arrowstyle;\n",
728       "    var edgeindices = obj.userData.edgeindices;\n",
729       "    var edgematerials = obj.userData.edgematerial;\n",
730       "    var points = obj.userData.points;\n",
731       "    var material;\n",
732       "    if (!Array.isArray(edgematerials)) {\n",
733       "        material = new THREE.MeshBasicMaterial( {color: edgematerials.color} );\n",
734       "    }\n",
735       "\n",
736       "    for (var i=0; i<edgeindices.length; i=i+2) {\n",
737       "        var start = points[edgeindices[i]];\n",
738       "        var end = points[edgeindices[i+1]];\n",
739       "        var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius();\n",
740       "        if (dist <= 0) {\n",
741       "            continue;\n",
742       "        }\n",
743       "        var dir = new THREE.Vector3().subVectors(end.vector,start.vector);\n",
744       "        dir.normalize();\n",
745       "        var axis = new THREE.Vector3().set(dir.z,0,-dir.x);\n",
746       "        axis.normalize();\n",
747       "        var radians = Math.acos( dir.y );\n",
748       "        var radius = dist/25;\n",
749       "        var height = dist/5;\n",
750       "        var geometry = new THREE.ConeBufferGeometry(radius,height);\n",
751       "        var position = new THREE.Vector3().addVectors(start.vector,dir.clone().multiplyScalar(start.radius()+dist-height/2));\n",
752       "        if (Array.isArray(edgematerials)) {\n",
753       "            material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} );\n",
754       "        }\n",
755       "        var cone = new THREE.Mesh( geometry, material );\n",
756       "        cone.quaternion.setFromAxisAngle(axis,radians);;\n",
757       "        cone.position.copy(position);;\n",
758       "        arrowheads.add(cone);\n",
759       "    }\n",
760       "    obj.add(arrowheads);\n",
761       "}\n",
762       "\n",
763       "function init_faces(obj) {\n",
764       "    var points = obj.userData.points;\n",
765       "    var facets = obj.userData.facets;\n",
766       "    obj.userData.triangleindices = [];\n",
767       "    for (var i=0; i<facets.length; i++) {\n",
768       "        facet = facets[i];\n",
769       "        for (var t=0; t<facet.length-2; t++) {\n",
770       "            obj.userData.triangleindices.push(facet[0],facet[t+1],facet[t+2]);  \n",
771       "        }\n",
772       "    }\n",
773       "    var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 );\n",
774       "    var bufattr = new THREE.Float32BufferAttribute(bufarr,3);\n",
775       "    \n",
776       "    var materials = obj.userData.facetmaterial;\n",
777       "    var geometry = new THREE.BufferGeometry();\n",
778       "    geometry.setAttribute('position',bufattr);\n",
779       "    if (Array.isArray(materials)) {\n",
780       "        var tricount = 0;\n",
781       "        var facet;\n",
782       "        for (var i=0; i<facets.length; i++) {\n",
783       "            facet = facets[i];\n",
784       "            geometry.addGroup(tricount,(facet.length-2)*3,i);\n",
785       "            tricount += (facet.length-2)*3;\n",
786       "        }\n",
787       "    }\n",
788       "    var mesh = new THREE.Mesh(geometry, materials);\n",
789       "    mesh.name = \"faces\";\n",
790       "    obj.add(mesh); \n",
791       "    updateFacesPosition(obj);\n",
792       "}\n",
793       "// //INITIALIZING\n",
794       "\n",
795       "\n",
796       "function updateFacesPosition(obj) {\n",
797       "    var points = obj.userData.points;\n",
798       "    var indices = obj.userData.triangleindices;\n",
799       "    var faces = obj.getObjectByName(\"faces\");\n",
800       "    var ba = faces.geometry.getAttribute(\"position\");\n",
801       "    for (var i=0; i<indices.length; i++) {\n",
802       "        ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z); \n",
803       "    }\n",
804       "    faces.geometry.attributes.position.needsUpdate = true;\n",
805       "    \n",
806       "}\n",
807       "\n",
808       "function updateEdgesPosition(obj) {\n",
809       "    var points = obj.userData.points;\n",
810       "    var indices = obj.userData.edgeindices;\n",
811       "    var lines = obj.getObjectByName(\"lines\");\n",
812       "    var ba = lines.geometry.getAttribute(\"position\"); \n",
813       "    for (var i=0; i<indices.length; i++) {\n",
814       "        ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z); \n",
815       "    }\n",
816       "    lines.geometry.attributes.position.needsUpdate = true;\n",
817       "}\n",
818       "\n",
819       "function onWindowResize() {\n",
820       "    renderer.setSize( three.clientWidth, three.clientHeight );\n",
821       "    svgRenderer.setSize( three.clientWidth, three.clientHeight );\n",
822       "    updateCamera();\n",
823       "}\n",
824       "\n",
825       "function updateCamera() {\n",
826       "    var width = three.clientWidth;\n",
827       "    var height = three.clientHeight;\n",
828       "    var aspect = width / height;\n",
829       "    if (camera.type == \"OrthographicCamera\") {\n",
830       "        camera.left = frustumSize * aspect / - 2;\n",
831       "        camera.right = frustumSize * aspect / 2;\n",
832       "        camera.top = frustumSize / 2;\n",
833       "        camera.bottom = - frustumSize / 2;\n",
834       "    } else if (camera.type == \"PerspectiveCamera\") {\n",
835       "        camera.aspect = aspect;\n",
836       "    }\n",
837       "    camera.updateProjectionMatrix();\n",
838       "}\n",
839       "\n",
840       "function changeCamera(event) {\n",
841       "    var selindex = event.currentTarget.selectedIndex;\n",
842       "    camera = cameras[selindex];\n",
843       "    control = controls[selindex];\n",
844       "    control.enabled = true; \n",
845       "    for (var i=0; i<controls.length; i++) {\n",
846       "        if (i!=selindex) {\n",
847       "            controls[i].enabled = false;\n",
848       "        }\n",
849       "    }\n",
850       "    updateCamera();\n",
851       "}\n",
852       "\n",
853       "var camtypenode = document.getElementById('cameraType_0');\n",
854       "camtypenode.onchange = changeCamera;\n",
855       "camtypenode.dispatchEvent(new Event('change'));\n",
856       "\n",
857       "onWindowResize();\n",
858       "window.addEventListener('resize', onWindowResize);\t\n",
859       "\n",
860       "\n",
861       "var xRotationEnabled = false;\n",
862       "var yRotationEnabled = false;\n",
863       "var zRotationEnabled = false;\n",
864       "var rotationSpeedFactor = 1;\n",
865       "var settingsShown = false;\n",
866       "var labelsShown = true;\n",
867       "var intervals = [];\n",
868       "var timeouts = [];\n",
869       "var explodingSpeed = 0.05;\n",
870       "var explodeScale = 0;\n",
871       "var XMLS = new XMLSerializer();\n",
872       "var svgElement;\n",
873       "var renderId;\n",
874       "\n",
875       "var render = function () {\n",
876       "\n",
877       "\trenderId = requestAnimationFrame(render);\n",
878       "\n",
879       "//\tcomment in for automatic explosion\n",
880       "//\texplode(updateFactor());\n",
881       "\n",
882       "    var phi = 0.02 * rotationSpeedFactor;\n",
883       "\n",
884       "    if (xRotationEnabled) {\n",
885       "        scene.rotation.x += phi;\n",
886       "    }\n",
887       "    if (yRotationEnabled) {\n",
888       "        scene.rotation.y += phi;\n",
889       "    }\n",
890       "    if (zRotationEnabled) {\n",
891       "        scene.rotation.z += phi;\n",
892       "    }\n",
893       "\n",
894       "    control.update();\n",
895       "    renderer.render(scene, camera);\n",
896       "};\n",
897       "\n",
898       "if ( THREE.WEBGL.isWebGLAvailable() ) {\n",
899       "\trender();\n",
900       "} else {\n",
901       "\tvar warning = WEBGL.getWebGLErrorMessage();\n",
902       "\tthree.appendChild( warning );\n",
903       "}\n",
904       "    \n",
905       "function changeTransparency() {\n",
906       "    var opacity = 1-Number(event.currentTarget.value);\n",
907       "    for (var i=0; i<scene.children.length; i++) {\n",
908       "        child = scene.children[i];\n",
909       "        if ( child.userData.hasOwnProperty(\"facetmaterial\") ) {\n",
910       "            if (Array.isArray(child.userData.facetmaterial)) {\n",
911       "                for (var j=0; j<child.userData.facetmaterial.length; j++) {\n",
912       "                    child.userData.facetmaterial[j].opacity = opacity;\n",
913       "                }\n",
914       "            } else {\n",
915       "                child.userData.facetmaterial.opacity = opacity;\n",
916       "            }    \n",
917       "        }\n",
918       "    }\n",
919       "}\n",
920       "\n",
921       "function changeRotationX(event){\n",
922       "    xRotationEnabled = event.currentTarget.checked;\n",
923       "}\t\n",
924       "\n",
925       "function changeRotationY(event){\n",
926       "    yRotationEnabled = event.currentTarget.checked;\n",
927       "}\t\n",
928       "\n",
929       "function changeRotationZ(event){\n",
930       "    zRotationEnabled = event.currentTarget.checked;\n",
931       "}\t\n",
932       "\n",
933       "\n",
934       "function changeRotationSpeedFactor(event){\n",
935       "    rotationSpeedFactor = Number(event.currentTarget.value);\n",
936       "}\n",
937       "\n",
938       "function resetScene(){\n",
939       "    scene.rotation.set(0,0,0);\n",
940       "    camera.position.set(0,0,5);\n",
941       "    camera.up.set(0,1,0);\n",
942       "}\n",
943       "\n",
944       "function showSettings(event){\n",
945       "    document.getElementById('settings_0').style.visibility = 'visible';\n",
946       "    document.getElementById('showSettingsButton_0').style.visibility = 'hidden';\n",
947       "    document.getElementById('hideSettingsButton_0').style.visibility = 'visible';\n",
948       "    settingsShown = true;\n",
949       "}\n",
950       "\n",
951       "function hideSettings(event){\n",
952       "    document.getElementById('settings_0').style.visibility = 'hidden';\n",
953       "    document.getElementById('showSettingsButton_0').style.visibility = 'visible';\n",
954       "    document.getElementById('hideSettingsButton_0').style.visibility = 'hidden';\n",
955       "    settingsShown = false;\n",
956       "}\n",
957       "\n",
958       "\n",
959       "\n",
960       "var pos = 150* Math.PI;\n",
961       "\n",
962       "function updateFactor() {\n",
963       "    pos++;\n",
964       "    return Math.sin(.01*pos)+1;\n",
965       "}\n",
966       "\n",
967       "// ------------------------ FOLDING ------------------------------------------------\n",
968       "// ---------------------------------------------------------------------------------\n",
969       "// rotate point p around axis defined by points p1 and p2 by given angle\n",
970       "function rotate(p, p1, p2, angle ){   \n",
971       "    angle = -angle;\n",
972       "    var x = p.x, y = p.y, z = p.z, \n",
973       "    a = p1.x, b = p1.y, c = p1.z, \n",
974       "    u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z;\n",
975       "    var result = [];\n",
976       "    var L = u*u + v*v + w*w;\n",
977       "    var sqrt = Math.sqrt;\n",
978       "    var cos = Math.cos;\n",
979       "    var sin = Math.sin;\n",
980       "\n",
981       "    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))/L;\n",
982       "    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))/L;\n",
983       "    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))/L;\n",
984       "\n",
985       "    return result;\n",
986       "}\n",
987       "\n",
988       "var fold = function(event){\n",
989       "    var obj = foldables[Number(event.currentTarget.name)];\n",
990       "    var foldvalue = Number(event.currentTarget.value);\n",
991       "    var scale = foldvalue - obj.userData.oldscale;\n",
992       "\n",
993       "    for (var j=0; j<obj.userData.axes.length; j++) {\n",
994       "        rotateVertices(obj, j, scale);\n",
995       "    }\n",
996       "    update(obj);\n",
997       "    obj.userData.oldscale += scale;\n",
998       "    lookAtBarycenter(obj);\n",
999       "}\n",
1000       "\n",
1001       "function lookAtBarycenter(obj){\n",
1002       "    control.target = barycenter(obj);\n",
1003       "}\n",
1004       "\n",
1005       "function barycenter(obj) {\n",
1006       "    var center = new THREE.Vector3(0,0,0);\n",
1007       "    var points = obj.userData.points;\n",
1008       "    for (var i=0; i<points.length; i++){\n",
1009       "        center.add(points[i].vector);\n",
1010       "    }\n",
1011       "    center.divideScalar(points.length);\n",
1012       "    return center;\n",
1013       "}\n",
1014       "\n",
1015       "function rotateVertices(obj, edge, scale) {\n",
1016       "    var axes = obj.userData.axes;\n",
1017       "    var subtrees = obj.userData.subtrees;\n",
1018       "    var points = obj.userData.points;\n",
1019       "    var angles = obj.userData.angles;\n",
1020       "    if (edge < axes.length){\n",
1021       "        for (var j=0; j<subtrees[edge].length; j++){\n",
1022       "            var rotP = rotate(points[subtrees[edge][j]].vector, points[axes[edge][0]].vector,points[axes[edge][1]].vector, scale * (Math.PI - angles[edge]));\n",
1023       "            points[subtrees[edge][j]].set(rotP[0],rotP[1],rotP[2]);\n",
1024       "        }\n",
1025       "    }\n",
1026       "}\n",
1027       "\n",
1028       "function update(obj) {\n",
1029       "   updateFacesPosition(obj);\n",
1030       "   updateEdgesPosition(obj);\n",
1031       "}\n",
1032       "\n",
1033       "if (foldables.length) {\n",
1034       "    var settings = document.getElementById('settings_0');\n",
1035       "    var foldDiv = document.createElement('div');\n",
1036       "    foldDiv.id = 'fold_0';\n",
1037       "    var title = document.createElement('strong');\n",
1038       "    title.innerHTML = 'Fold';\n",
1039       "    foldDiv.appendChild(title);\n",
1040       "    foldDiv.className = 'group';\n",
1041       "    for (var i=0; i<foldables.length; i++) {\n",
1042       "        var range = document.createElement('input');\n",
1043       "        range.type = 'range';\n",
1044       "        range.min = 0;\n",
1045       "        range.max = 1;\n",
1046       "        range.value = 0;\n",
1047       "        range.step = 0.001;\n",
1048       "        range.name = String(i);\n",
1049       "        range.oninput = fold;\n",
1050       "        foldDiv.appendChild(range);\n",
1051       "    }\n",
1052       "    lookAtBarycenter(foldables[0]);\n",
1053       "    settings.insertBefore(foldDiv,settings.childNodes[0]);\n",
1054       "}\n",
1055       "\n",
1056       "    \n",
1057       "// ---------------------- EXPLOSION ------------------------------------------------\n",
1058       "// ---------------------------------------------------------------------------------\n",
1059       "\n",
1060       "if (explodableModel) {\n",
1061       "    for (var i=0; i<scene.children.length; i++) {\n",
1062       "        obj = scene.children[i];\n",
1063       "        if ( obj.userData.explodable ) {\n",
1064       "            computeCentroid(obj);\n",
1065       "        }\n",
1066       "    }\n",
1067       "    document.getElementById('explodeRange_0').oninput = triggerExplode;\n",
1068       "    document.getElementById('explodeCheckbox_0').onchange = triggerAutomaticExplode;\n",
1069       "    document.getElementById('explodingSpeedRange_0').oninput = setExplodingSpeed;\n",
1070       "}\n",
1071       "\n",
1072       "function computeCentroid(obj) {\n",
1073       "    centroid = new THREE.Vector3();\n",
1074       "    obj.userData.points.forEach(function(pmpoint) {\n",
1075       "        centroid.add(pmpoint.vector);\t\t\t\n",
1076       "    });\n",
1077       "    centroid.divideScalar(obj.userData.points.length);\n",
1078       "    obj.userData.centroid = centroid;\n",
1079       "}\n",
1080       "\n",
1081       "function explode(factor) {\n",
1082       "    for (var i=0; i<scene.children.length; i++) {\n",
1083       "        var obj = scene.children[i];\n",
1084       "        if (obj.userData.hasOwnProperty(\"centroid\")) { \n",
1085       "            var c = obj.userData.centroid;\n",
1086       "            obj.position.set(c.x*factor, c.y*factor, c.z*factor);\n",
1087       "        }\n",
1088       "    }\t\n",
1089       "}\n",
1090       "\n",
1091       "function triggerExplode(event){\n",
1092       "    explodeScale = Number(event.currentTarget.value);\n",
1093       "    explode(explodeScale);\n",
1094       "}\n",
1095       "\n",
1096       "function setExplodingSpeed(event){\n",
1097       "    explodingSpeed = Number(event.currentTarget.value);\n",
1098       "}\n",
1099       "\n",
1100       "function triggerAutomaticExplode(event){\n",
1101       "    if (event.currentTarget.checked){\n",
1102       "        startExploding();\n",
1103       "    } else {\n",
1104       "        clearIntervals();\n",
1105       "    }\t\n",
1106       "}\n",
1107       "\n",
1108       "function startExploding(){\n",
1109       "    intervals.push(setInterval(explodingInterval, 25));\n",
1110       "}\n",
1111       "\n",
1112       "\n",
1113       "function explodingInterval(){\n",
1114       "    explodeScale += explodingSpeed;\n",
1115       "    if (explodeScale <= 6){ \n",
1116       "        explode(explodeScale);\n",
1117       "    }\n",
1118       "    else{\n",
1119       "        explode(6);\n",
1120       "        explodeScale = 6;\n",
1121       "        clearIntervals();\n",
1122       "        timeouts.push(setTimeout(startUnexploding, 3000));\n",
1123       "    }\n",
1124       "    document.getElementById('explodeRange_0').value = explodeScale;\n",
1125       "}\n",
1126       "\n",
1127       "\n",
1128       "function startUnexploding(){\n",
1129       "    intervals.push(setInterval(unexplodingInterval, 25));\n",
1130       "}\n",
1131       "\n",
1132       "function unexplodingInterval(){\n",
1133       "    explodeScale -= explodingSpeed;\n",
1134       "    if (explodeScale >= 0){\t\n",
1135       "        explode(explodeScale);\n",
1136       "    }\n",
1137       "    else {\n",
1138       "        explode(0);\n",
1139       "        explodeScale = 0;\n",
1140       "        clearIntervals();\n",
1141       "        timeouts.push(setTimeout(startExploding, 3000));\n",
1142       "    }\n",
1143       "    document.getElementById('explodeRange_0').value = explodeScale;\n",
1144       "}\n",
1145       "\n",
1146       "function clearIntervals(){\n",
1147       "    intervals.forEach(function(interval){\n",
1148       "        clearInterval(interval);\n",
1149       "    });\n",
1150       "    intervals = [];\n",
1151       "    timeouts.forEach(function(timeout){\n",
1152       "        clearTimeout(timeout);\n",
1153       "    });\n",
1154       "    timeouts = [];\n",
1155       "}\n",
1156       "\n",
1157       "// ---------------------- DISPLAY --------------------------------------------------\n",
1158       "// ---------------------------------------------------------------------------------\n",
1159       "\n",
1160       "const objectTypeInnerHTMLs = { points: \"Points\", pointlabels: \"Point labels\", lines: \"Edges\", edgelabels: \"Edge labels\", faces: \"Faces\", arrowheads: \"Arrow heads\" };\n",
1161       "const objectTypeVisible = {};\n",
1162       "Object.assign(objectTypeVisible,modelContains);\n",
1163       "const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort();\n",
1164       "const shownObjectTypesList = document.getElementById('shownObjectTypesList_0');\n",
1165       "\n",
1166       "function setVisibility(bool,objname) {\n",
1167       "    for (var i=0; i<scene.children.length; i++){\n",
1168       "        var obj = scene.children[i].getObjectByName(objname);\n",
1169       "        if (obj) {\n",
1170       "            obj.visible = bool;\n",
1171       "        }\n",
1172       "    }\n",
1173       "}\n",
1174       "\n",
1175       "function toggleObjectTypeVisibility(event){\n",
1176       "    var name = event.currentTarget.name;\n",
1177       "    var checked = event.currentTarget.checked;\n",
1178       "    objectTypeVisible[name] = checked;\n",
1179       "    setVisibility(checked,name);\n",
1180       "}\n",
1181       "\n",
1182       "for (var i=0; i<sortedObjectTypeKeys.length; i++){\n",
1183       "    var key = sortedObjectTypeKeys[i];\n",
1184       "    if (modelContains[key]) {\n",
1185       "        var objTypeNode = document.createElement('span');\n",
1186       "        objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '<br>';\n",
1187       "        var checkbox = document.createElement('input');\n",
1188       "        checkbox.type = 'checkbox';\n",
1189       "        checkbox.checked = true;\n",
1190       "        checkbox.name = key;\n",
1191       "        checkbox.onchange = toggleObjectTypeVisibility;\n",
1192       "        shownObjectTypesList.appendChild(checkbox);\n",
1193       "        shownObjectTypesList.appendChild(objTypeNode);\n",
1194       "    }\n",
1195       "}\n",
1196       "\n",
1197       "// ------------------------------------------------------\n",
1198       "\n",
1199       "function toggleObjectVisibility(event){\n",
1200       "    var nr = Number(event.currentTarget.name);\n",
1201       "    scene.children[nr].visible = event.currentTarget.checked;\n",
1202       "}\n",
1203       "\n",
1204       "// append checkboxes for displaying or hiding objects\n",
1205       "var shownObjectsList = document.getElementById('shownObjectsList_0');\n",
1206       "for (var i=0; i<scene.children.length; i++){\n",
1207       "    obj = scene.children[i];\n",
1208       "    var objNode = document.createElement('span');\n",
1209       "    objNode.innerHTML = obj.name + '<br>';\n",
1210       "    var checkbox = document.createElement('input');\n",
1211       "    checkbox.type = 'checkbox';\n",
1212       "    checkbox.checked = true;\n",
1213       "    checkbox.name = String(i);\n",
1214       "    checkbox.onchange = toggleObjectVisibility;\n",
1215       "    shownObjectsList.appendChild(checkbox);\n",
1216       "    shownObjectsList.appendChild(objNode);\n",
1217       "}\n",
1218       "\n",
1219       "// ---------------------- SVG ------------------------------------------------------\n",
1220       "// ---------------------------------------------------------------------------------\n",
1221       "\n",
1222       "function takeSvgScreenshot() {\n",
1223       "    if (objectTypeVisible[\"pointlabels\"]) {\n",
1224       "        setVisibility(false,\"pointlabels\");\n",
1225       "    }\n",
1226       "    if (objectTypeVisible[\"edgelabels\"]) {\n",
1227       "        setVisibility(false,\"edgelabels\");\n",
1228       "    }\n",
1229       "    svgRenderer.render(scene,camera);\n",
1230       "    svgElement = XMLS.serializeToString(svgRenderer.domElement);\n",
1231       "    \n",
1232       "    if (objectTypeVisible[\"pointlabels\"]) {\n",
1233       "        setVisibility(true,\"pointlabels\");\n",
1234       "    }\n",
1235       "    if (objectTypeVisible[\"edgelabels\"]) {\n",
1236       "        setVisibility(true,\"edgelabels\");\n",
1237       "    }\n",
1238       "\n",
1239       "    if (document.getElementById('tab_0').checked){\n",
1240       "        //show in new tab\n",
1241       "        var myWindow = window.open(\"\",\"\");\n",
1242       "        myWindow.document.body.innerHTML = svgElement;\n",
1243       "    } else{\n",
1244       "        // download svg file \n",
1245       "        download(\"screenshot.svg\", svgElement);\n",
1246       "    }\n",
1247       "}\n",
1248       "\n",
1249       "function download(filename, text) {\n",
1250       "    var element = document.createElement('a');\n",
1251       "    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));\n",
1252       "    element.setAttribute('download', filename);\n",
1253       "\n",
1254       "    element.style.display = 'none';\n",
1255       "    document.body.appendChild(element);\n",
1256       "\n",
1257       "    element.click();\n",
1258       "\n",
1259       "    document.body.removeChild(element);\n",
1260       "}\n",
1261       "\n",
1262       "\n",
1263       "document.getElementById('transparencyRange_0').oninput = changeTransparency;\n",
1264       "document.getElementById('changeRotationX_0').onchange = changeRotationX;\n",
1265       "document.getElementById('changeRotationY_0').onchange = changeRotationY;\n",
1266       "document.getElementById('changeRotationZ_0').onchange = changeRotationZ;\n",
1267       "document.getElementById('resetButton_0').onclick = resetScene;\n",
1268       "document.getElementById('rotationSpeedRange_0').oninput = changeRotationSpeedFactor;\n",
1269       "document.getElementById('takeScreenshot_0').onclick = takeSvgScreenshot;\n",
1270       "document.getElementById('showSettingsButton_0').onclick = showSettings;\n",
1271       "document.getElementById('hideSettingsButton_0').onclick = hideSettings;\n",
1272       "\n",
1273       "\n",
1274       "// ------------------ SHORTCUTS --------------------------------------------\n",
1275       "// -------------------------------------------------------------------------\n",
1276       "\n",
1277       "/**\n",
1278       " * http://www.openjs.com/scripts/events/keyboard_shortcuts/\n",
1279       " * Version : 2.01.B\n",
1280       " * By Binny V A\n",
1281       " * License : BSD\n",
1282       " */\n",
1283       "shortcut = {\n",
1284       "\t'all_shortcuts':{},//All the shortcuts are stored in this array\n",
1285       "\t'add': function(shortcut_combination,callback,opt) {\n",
1286       "\t\t//Provide a set of default options\n",
1287       "\t\tvar default_options = {\n",
1288       "\t\t\t'type':'keydown',\n",
1289       "\t\t\t'propagate':false,\n",
1290       "\t\t\t'disable_in_input':false,\n",
1291       "\t\t\t'target':document,\n",
1292       "\t\t\t'keycode':false\n",
1293       "\t\t}\n",
1294       "\t\tif(!opt) opt = default_options;\n",
1295       "\t\telse {\n",
1296       "\t\t\tfor(var dfo in default_options) {\n",
1297       "\t\t\t\tif(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];\n",
1298       "\t\t\t}\n",
1299       "\t\t}\n",
1300       "\n",
1301       "\t\tvar ele = opt.target;\n",
1302       "\t\tif(typeof opt.target == 'string') ele = document.getElementById(opt.target);\n",
1303       "\t\tvar ths = this;\n",
1304       "\t\tshortcut_combination = shortcut_combination.toLowerCase();\n",
1305       "\n",
1306       "\t\t//The function to be called at keypress\n",
1307       "\t\tvar func = function(e) {\n",
1308       "\t\t\te = e || window.event;\n",
1309       "\t\t\t\n",
1310       "\t\t\tif(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields\n",
1311       "\t\t\t\tvar element;\n",
1312       "\t\t\t\tif(e.target) element=e.target;\n",
1313       "\t\t\t\telse if(e.srcElement) element=e.srcElement;\n",
1314       "\t\t\t\tif(element.nodeType==3) element=element.parentNode;\n",
1315       "\n",
1316       "\t\t\t\tif(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;\n",
1317       "\t\t\t}\n",
1318       "\t\n",
1319       "\t\t\t//Find Which key is pressed\n",
1320       "\t\t\tif (e.keyCode) code = e.keyCode;\n",
1321       "\t\t\telse if (e.which) code = e.which;\n",
1322       "\t\t\tvar character = String.fromCharCode(code).toLowerCase();\n",
1323       "\t\t\t\n",
1324       "\t\t\tif(code == 188) character=\",\"; //If the user presses , when the type is onkeydown\n",
1325       "\t\t\tif(code == 190) character=\".\"; //If the user presses , when the type is onkeydown\n",
1326       "\n",
1327       "\t\t\tvar keys = shortcut_combination.split(\"+\");\n",
1328       "\t\t\t//Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked\n",
1329       "\t\t\tvar kp = 0;\n",
1330       "\t\t\t\n",
1331       "\t\t\t//Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken\n",
1332       "\t\t\tvar shift_nums = {\n",
1333       "\t\t\t\t\"`\":\"~\",\n",
1334       "\t\t\t\t\"1\":\"!\",\n",
1335       "\t\t\t\t\"2\":\"@\",\n",
1336       "\t\t\t\t\"3\":\"#\",\n",
1337       "\t\t\t\t\"4\":\"$\",\n",
1338       "\t\t\t\t\"5\":\"%\",\n",
1339       "\t\t\t\t\"6\":\"^\",\n",
1340       "\t\t\t\t\"7\":\"&\",\n",
1341       "\t\t\t\t\"8\":\"*\",\n",
1342       "\t\t\t\t\"9\":\"(\",\n",
1343       "\t\t\t\t\"0\":\")\",\n",
1344       "\t\t\t\t\"-\":\"_\",\n",
1345       "\t\t\t\t\"=\":\"+\",\n",
1346       "\t\t\t\t\";\":\":\",\n",
1347       "\t\t\t\t\"'\":\"\\\"\",\n",
1348       "\t\t\t\t\",\":\"<\",\n",
1349       "\t\t\t\t\".\":\">\",\n",
1350       "\t\t\t\t\"/\":\"?\",\n",
1351       "\t\t\t\t\"\\\\\":\"|\"\n",
1352       "\t\t\t}\n",
1353       "\t\t\t//Special Keys - and their codes\n",
1354       "\t\t\tvar special_keys = {\n",
1355       "\t\t\t\t'esc':27,\n",
1356       "\t\t\t\t'escape':27,\n",
1357       "\t\t\t\t'tab':9,\n",
1358       "\t\t\t\t'space':32,\n",
1359       "\t\t\t\t'return':13,\n",
1360       "\t\t\t\t'enter':13,\n",
1361       "\t\t\t\t'backspace':8,\n",
1362       "\t\n",
1363       "\t\t\t\t'scrolllock':145,\n",
1364       "\t\t\t\t'scroll_lock':145,\n",
1365       "\t\t\t\t'scroll':145,\n",
1366       "\t\t\t\t'capslock':20,\n",
1367       "\t\t\t\t'caps_lock':20,\n",
1368       "\t\t\t\t'caps':20,\n",
1369       "\t\t\t\t'numlock':144,\n",
1370       "\t\t\t\t'num_lock':144,\n",
1371       "\t\t\t\t'num':144,\n",
1372       "\t\t\t\t\n",
1373       "\t\t\t\t'pause':19,\n",
1374       "\t\t\t\t'break':19,\n",
1375       "\t\t\t\t\n",
1376       "\t\t\t\t'insert':45,\n",
1377       "\t\t\t\t'home':36,\n",
1378       "\t\t\t\t'delete':46,\n",
1379       "\t\t\t\t'end':35,\n",
1380       "\t\t\t\t\n",
1381       "\t\t\t\t'pageup':33,\n",
1382       "\t\t\t\t'page_up':33,\n",
1383       "\t\t\t\t'pu':33,\n",
1384       "\t\n",
1385       "\t\t\t\t'pagedown':34,\n",
1386       "\t\t\t\t'page_down':34,\n",
1387       "\t\t\t\t'pd':34,\n",
1388       "\t\n",
1389       "\t\t\t\t'left':37,\n",
1390       "\t\t\t\t'up':38,\n",
1391       "\t\t\t\t'right':39,\n",
1392       "\t\t\t\t'down':40,\n",
1393       "\t\n",
1394       "\t\t\t\t'f1':112,\n",
1395       "\t\t\t\t'f2':113,\n",
1396       "\t\t\t\t'f3':114,\n",
1397       "\t\t\t\t'f4':115,\n",
1398       "\t\t\t\t'f5':116,\n",
1399       "\t\t\t\t'f6':117,\n",
1400       "\t\t\t\t'f7':118,\n",
1401       "\t\t\t\t'f8':119,\n",
1402       "\t\t\t\t'f9':120,\n",
1403       "\t\t\t\t'f10':121,\n",
1404       "\t\t\t\t'f11':122,\n",
1405       "\t\t\t\t'f12':123\n",
1406       "\t\t\t}\n",
1407       "\t\n",
1408       "\t\t\tvar modifiers = { \n",
1409       "\t\t\t\tshift: { wanted:false, pressed:false},\n",
1410       "\t\t\t\tctrl : { wanted:false, pressed:false},\n",
1411       "\t\t\t\talt  : { wanted:false, pressed:false},\n",
1412       "\t\t\t\tmeta : { wanted:false, pressed:false}\t//Meta is Mac specific\n",
1413       "\t\t\t};\n",
1414       "                        \n",
1415       "\t\t\tif(e.ctrlKey)\tmodifiers.ctrl.pressed = true;\n",
1416       "\t\t\tif(e.shiftKey)\tmodifiers.shift.pressed = true;\n",
1417       "\t\t\tif(e.altKey)\tmodifiers.alt.pressed = true;\n",
1418       "\t\t\tif(e.metaKey)   modifiers.meta.pressed = true;\n",
1419       "                        \n",
1420       "\t\t\tfor(var i=0; k=keys[i],i<keys.length; i++) {\n",
1421       "\t\t\t\t//Modifiers\n",
1422       "\t\t\t\tif(k == 'ctrl' || k == 'control') {\n",
1423       "\t\t\t\t\tkp++;\n",
1424       "\t\t\t\t\tmodifiers.ctrl.wanted = true;\n",
1425       "\n",
1426       "\t\t\t\t} else if(k == 'shift') {\n",
1427       "\t\t\t\t\tkp++;\n",
1428       "\t\t\t\t\tmodifiers.shift.wanted = true;\n",
1429       "\n",
1430       "\t\t\t\t} else if(k == 'alt') {\n",
1431       "\t\t\t\t\tkp++;\n",
1432       "\t\t\t\t\tmodifiers.alt.wanted = true;\n",
1433       "\t\t\t\t} else if(k == 'meta') {\n",
1434       "\t\t\t\t\tkp++;\n",
1435       "\t\t\t\t\tmodifiers.meta.wanted = true;\n",
1436       "\t\t\t\t} else if(k.length > 1) { //If it is a special key\n",
1437       "\t\t\t\t\tif(special_keys[k] == code) kp++;\n",
1438       "\t\t\t\t\t\n",
1439       "\t\t\t\t} else if(opt['keycode']) {\n",
1440       "\t\t\t\t\tif(opt['keycode'] == code) kp++;\n",
1441       "\n",
1442       "\t\t\t\t} else { //The special keys did not match\n",
1443       "\t\t\t\t\tif(character == k) kp++;\n",
1444       "\t\t\t\t\telse {\n",
1445       "\t\t\t\t\t\tif(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase\n",
1446       "\t\t\t\t\t\t\tcharacter = shift_nums[character]; \n",
1447       "\t\t\t\t\t\t\tif(character == k) kp++;\n",
1448       "\t\t\t\t\t\t}\n",
1449       "\t\t\t\t\t}\n",
1450       "\t\t\t\t}\n",
1451       "\t\t\t}\n",
1452       "\t\t\t\n",
1453       "\t\t\tif(kp == keys.length && \n",
1454       "\t\t\t\t\t\tmodifiers.ctrl.pressed == modifiers.ctrl.wanted &&\n",
1455       "\t\t\t\t\t\tmodifiers.shift.pressed == modifiers.shift.wanted &&\n",
1456       "\t\t\t\t\t\tmodifiers.alt.pressed == modifiers.alt.wanted &&\n",
1457       "\t\t\t\t\t\tmodifiers.meta.pressed == modifiers.meta.wanted) {\n",
1458       "\t\t\t\tcallback(e);\n",
1459       "\t\n",
1460       "\t\t\t\tif(!opt['propagate']) { //Stop the event\n",
1461       "\t\t\t\t\t//e.cancelBubble is supported by IE - this will kill the bubbling process.\n",
1462       "\t\t\t\t\te.cancelBubble = true;\n",
1463       "\t\t\t\t\te.returnValue = false;\n",
1464       "\t\n",
1465       "\t\t\t\t\t//e.stopPropagation works in Firefox.\n",
1466       "\t\t\t\t\tif (e.stopPropagation) {\n",
1467       "\t\t\t\t\t\te.stopPropagation();\n",
1468       "\t\t\t\t\t\te.preventDefault();\n",
1469       "\t\t\t\t\t}\n",
1470       "\t\t\t\t\treturn false;\n",
1471       "\t\t\t\t}\n",
1472       "\t\t\t}\n",
1473       "\t\t}\n",
1474       "\t\tthis.all_shortcuts[shortcut_combination] = {\n",
1475       "\t\t\t'callback':func, \n",
1476       "\t\t\t'target':ele, \n",
1477       "\t\t\t'event': opt['type']\n",
1478       "\t\t};\n",
1479       "\t\t//Attach the function with the event\n",
1480       "\t\tif(ele.addEventListener) ele.addEventListener(opt['type'], func, false);\n",
1481       "\t\telse if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);\n",
1482       "\t\telse ele['on'+opt['type']] = func;\n",
1483       "\t},\n",
1484       "\n",
1485       "\t//Remove the shortcut - just specify the shortcut and I will remove the binding\n",
1486       "\t'remove':function(shortcut_combination) {\n",
1487       "\t\tshortcut_combination = shortcut_combination.toLowerCase();\n",
1488       "\t\tvar binding = this.all_shortcuts[shortcut_combination];\n",
1489       "\t\tdelete(this.all_shortcuts[shortcut_combination])\n",
1490       "\t\tif(!binding) return;\n",
1491       "\t\tvar type = binding['event'];\n",
1492       "\t\tvar ele = binding['target'];\n",
1493       "\t\tvar callback = binding['callback'];\n",
1494       "\n",
1495       "\t\tif(ele.detachEvent) ele.detachEvent('on'+type, callback);\n",
1496       "\t\telse if(ele.removeEventListener) ele.removeEventListener(type, callback, false);\n",
1497       "\t\telse ele['on'+type] = false;\n",
1498       "\t}\n",
1499       "}\n",
1500       "\n",
1501       "shortcut.add(\"Alt+Left\",function() {\n",
1502       "\tvar event = new Event('click');\n",
1503       "\tif (settingsShown){\n",
1504       "\t\tdocument.getElementById('hideSettingsButton_0').dispatchEvent(event);\n",
1505       "\t} else {\n",
1506       "\t\tdocument.getElementById('showSettingsButton_0').dispatchEvent(event);\n",
1507       "\t}\n",
1508       "});\n",
1509       "\n",
1510       "\n",
1511       "// COMMON_CODE_BLOCK_END\n",
1512       "\n",
1513       "});});\n",
1514       "      </script>\n",
1515       "   </body>\n",
1516       "</html>"
1517      ]
1518     },
1519     "metadata": {},
1520     "output_type": "display_data"
1521    },
1522    {
1523     "data": {
1524      "text/html": [
1525       "<details><summary><pre style=\"display:inline\"><small>Click here for additional output</small></pre></summary>\n",
1526       "<pre>\n",
1527       "polymake: used package threejs\n",
1528       "   Three.js is a lightweight cross-browser JavaScript library/API used to create and display animated 3D computer graphics on a Web browser.\n",
1529       "   See http://github.com/mrdoob for the source code.\n",
1530       "\n",
1531       "</pre>\n",
1532       "</details>\n"
1533      ]
1534     },
1535     "metadata": {},
1536     "output_type": "display_data"
1537    }
1538   ],
1539   "source": [
1540    "$rs->VISUAL;"
1541   ]
1542  },
1543  {
1544   "cell_type": "markdown",
1545   "metadata": {},
1546   "source": [
1547    "Now we will create yet another new polytope by scaling our random sphere by a factor lambda. (Otherwise there are rather few integral points contained in it.)\n",
1548    "\n",
1549    "To this end, we have to multiply every coordinate (except for the homogenising 1 in the beginning) of every vertex by lamda. Then we can create a new polytope by specifying its vertices.\n"
1550   ]
1551  },
1552  {
1553   "cell_type": "code",
1554   "execution_count": 9,
1555   "metadata": {},
1556   "outputs": [],
1557   "source": [
1558    "$lambda=2;"
1559   ]
1560  },
1561  {
1562   "cell_type": "markdown",
1563   "metadata": {},
1564   "source": [
1565    "    \n"
1566   ]
1567  },
1568  {
1569   "cell_type": "code",
1570   "execution_count": 10,
1571   "metadata": {},
1572   "outputs": [],
1573   "source": [
1574    "$s=new Matrix<Rational>([[1,0,0,0],[0,$lambda,0,0],[0,0,$lambda,0],[0,0,0,$lambda]]);"
1575   ]
1576  },
1577  {
1578   "cell_type": "markdown",
1579   "metadata": {},
1580   "source": [
1581    "    \n"
1582   ]
1583  },
1584  {
1585   "cell_type": "code",
1586   "execution_count": 11,
1587   "metadata": {},
1588   "outputs": [
1589    {
1590     "data": {
1591      "text/plain": [
1592       "1 0 0 0\n",
1593       "0 2 0 0\n",
1594       "0 0 2 0\n",
1595       "0 0 0 2\n"
1596      ]
1597     },
1598     "execution_count": 11,
1599     "metadata": {},
1600     "output_type": "execute_result"
1601    }
1602   ],
1603   "source": [
1604    "print $s;"
1605   ]
1606  },
1607  {
1608   "cell_type": "code",
1609   "execution_count": 12,
1610   "metadata": {},
1611   "outputs": [],
1612   "source": [
1613    "$scaled_rs=new Polytope<Rational>(VERTICES=>($rs->VERTICES * $s), LINEALITY_SPACE=>[]);"
1614   ]
1615  },
1616  {
1617   "cell_type": "markdown",
1618   "metadata": {},
1619   "source": [
1620    "\n",
1621    "\n",
1622    "`polymake` can visualise the polytope together with its lattice points:\n",
1623    "\n",
1624    "    \n"
1625   ]
1626  },
1627  {
1628   "cell_type": "code",
1629   "execution_count": 13,
1630   "metadata": {},
1631   "outputs": [
1632    {
1633     "data": {
1634      "text/html": [
1635       "<!--\n",
1636       "polymake for knusper\n",
1637       "Thu Aug 27 11:38:20 2020\n",
1638       "scaled_rs\n",
1639       "-->\n",
1640       "\n",
1641       "\n",
1642       "<html>\n",
1643       "   <head>\n",
1644       "      <meta charset=utf-8>\n",
1645       "      <title>scaled_rs</title>\n",
1646       "      <style>\n",
1647       "/*\n",
1648       "// COMMON_CODE_BLOCK_BEGIN\n",
1649       "*/\n",
1650       "         html {overflow: scroll;}\n",
1651       "         strong{font-size: 18px;}\n",
1652       "         canvas { z-index: 8; }\n",
1653       "         input[type='radio'] {margin-left:0;}\n",
1654       "         input[type='checkbox'] {margin-right:7px; margin-left: 0px; padding-left:0px;}\n",
1655       "         .group{padding-bottom: 15px;}\n",
1656       "         .settings * {z-index: 11; }\n",
1657       "         .settings{z-index: 10; font-family: Arial, Helvetica, sans-serif; margin-left: 30px; visibility: hidden; width: 14em; height: 96%; border: solid 1px silver; padding: 2px; overflow-y: scroll; box-sizing: border-box; background-color: white; position: absolute;}\n",
1658       "         .indented{margin-left: 20px; margin-top: 10px; padding-bottom: 0px;} \n",
1659       "         .shownObjectsList{overflow: auto; max-width: 150px; max-height: 150px;}\n",
1660       "         .showSettingsButton{visibility: visible; z-index: 12; position: absolute }\n",
1661       "         .hideSettingsButton{visibility: hidden; z-index: 12; position: absolute; opacity: 0.5}\n",
1662       "         button{margin-left: 0; margin-top: 10px}\n",
1663       "         img{cursor: pointer;}\n",
1664       "         .suboption{padding-top: 15px;}\n",
1665       "         #model79422509120 { width: 100%; height: 100%; }\n",
1666       "         .threejs_container { width: 100%; height: 75vh;}\n",
1667       "         .settings{max-height: 74vh} \n",
1668       "         input[type=range] {\n",
1669       "           -webkit-appearance: none;\n",
1670       "           padding:0; \n",
1671       "           width:90%; \n",
1672       "           margin-left: auto;\n",
1673       "           margin-right: auto;\n",
1674       "           margin-top: 15px;\n",
1675       "           margin-bottom: 15px;\n",
1676       "           display: block;\t\n",
1677       "         }\n",
1678       "         input[type=range]:focus {\n",
1679       "           outline: none;\n",
1680       "         }\n",
1681       "         input[type=range]::-webkit-slider-runnable-track {\n",
1682       "           height: 4px;\n",
1683       "           cursor: pointer;\n",
1684       "           animate: 0.2s;\n",
1685       "           box-shadow: 0px 0px 0px #000000;\n",
1686       "           background: #E3E3E3;\n",
1687       "           border-radius: 0px;\n",
1688       "           border: 0px solid #000000;\n",
1689       "         }\n",
1690       "         input[type=range]::-webkit-slider-thumb {\n",
1691       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
1692       "           border: 1px solid #ABABAB;\n",
1693       "           height: 13px;\n",
1694       "           width: 25px;\n",
1695       "           border-radius: 20px;\n",
1696       "           background: #E0E0E0;\n",
1697       "           cursor: pointer;\n",
1698       "           -webkit-appearance: none;\n",
1699       "           margin-top: -5px;\n",
1700       "         }\n",
1701       "         input[type=range]:focus::-webkit-slider-runnable-track {\n",
1702       "           background: #E3E3E3;\n",
1703       "         }\n",
1704       "         input[type=range]::-moz-range-track {\n",
1705       "           height: 4px;\n",
1706       "           cursor: pointer;\n",
1707       "           animate: 0.2s;\n",
1708       "           box-shadow: 0px 0px 0px #000000;\n",
1709       "           background: #E3E3E3;\n",
1710       "           border-radius: 0px;\n",
1711       "           border: 0px solid #000000;\n",
1712       "         }\n",
1713       "         input[type=range]::-moz-range-thumb {\n",
1714       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
1715       "           border: 1px solid #ABABAB;\n",
1716       "           height: 13px;\n",
1717       "           width: 25px;\n",
1718       "           border-radius: 20px;\n",
1719       "           background: #E0E0E0;\n",
1720       "           cursor: pointer;\n",
1721       "         }\n",
1722       "         input[type=range]::-ms-track {\n",
1723       "           height: 4px;\n",
1724       "           cursor: pointer;\n",
1725       "           animate: 0.2s;\n",
1726       "           background: transparent;\n",
1727       "           border-color: transparent;\n",
1728       "           color: transparent;\n",
1729       "         }\n",
1730       "         input[type=range]::-ms-fill-lower {\n",
1731       "           background: #E3E3E3;\n",
1732       "           border: 0px solid #000000;\n",
1733       "           border-radius: 0px;\n",
1734       "           box-shadow: 0px 0px 0px #000000;\n",
1735       "         }\n",
1736       "         input[type=range]::-ms-fill-upper {\n",
1737       "           background: #E3E3E3;\n",
1738       "           border: 0px solid #000000;\n",
1739       "           border-radius: 0px;\n",
1740       "           box-shadow: 0px 0px 0px #000000;\n",
1741       "         }\n",
1742       "         input[type=range]::-ms-thumb {\n",
1743       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
1744       "           border: 1px solid #ABABAB;\n",
1745       "           height: 13px;\n",
1746       "           width: 25px;\n",
1747       "           border-radius: 20px;\n",
1748       "           background: #E0E0E0;\n",
1749       "           cursor: pointer;\n",
1750       "         }\n",
1751       "         input[type=range]:focus::-ms-fill-lower {\n",
1752       "           background: #E3E3E3;\n",
1753       "         }\n",
1754       "         input[type=range]:focus::-ms-fill-upper {\n",
1755       "           background: #E3E3E3;\n",
1756       "         }\n",
1757       "/*\n",
1758       "// COMMON_CODE_BLOCK_END\n",
1759       "*/\n",
1760       "\t\t</style>\n",
1761       "   </head>\n",
1762       "<body>\n",
1763       "   <div class='threejs_container'>\n",
1764       "\t\t<div id='settings_1' class='settings'>\n",
1765       "\t\t\t<div class=group id='explode_1'>\n",
1766       "\t\t\t\t<strong>Explode</strong>\n",
1767       "\t\t\t\t<input id='explodeRange_1' type='range' min=0 max=6 step=0.01 value=0>\n",
1768       "\t\t\t\t<div class=indented><input id='explodeCheckbox_1' type='checkbox'>Automatic explosion</div>\n",
1769       "\t\t\t\t<div class=suboption>Exploding speed</div>\n",
1770       "\t\t\t\t<input id='explodingSpeedRange_1' type='range' min=0 max=0.5 step=0.001 value=0.05>\n",
1771       "\t\t\t</div>\n",
1772       "\t\n",
1773       "\t\t\t<div class=group id='transparency_1' class='transparency'>\n",
1774       "\t\t\t\t<strong>Transparency</strong>\n",
1775       "\t\t\t\t<input id='transparencyRange_1' type='range' min=0 max=1 step=0.01 value=0>\n",
1776       "\t\t\t</div>\n",
1777       "\t\t\t\n",
1778       "\t\t\t<div class=group id='rotation_1'>\n",
1779       "\t\t\t\t<strong>Rotation</strong>\n",
1780       "\t\t\t\t<div class=indented>\n",
1781       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationX_1'> x-axis</div>\n",
1782       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationY_1'> y-axis</div>\n",
1783       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationZ_1'> z-axis</div>\n",
1784       "\t\t\t\t\t<button id='resetButton_1'>Reset</button>\n",
1785       "\t\t\t\t</div>\n",
1786       "\n",
1787       "\t\t\t\t<div class=suboption>Rotation speed</div>\n",
1788       "\t\t\t\t<input id='rotationSpeedRange_1' type='range' min=0 max=5 step=0.01 value=2>\n",
1789       "\t\t\t</div>\n",
1790       "\n",
1791       "\n",
1792       "\t\t\t<div class=group id='display_1'>\n",
1793       "\t\t\t\t<strong>Display</strong>\n",
1794       "\t\t\t\t<div class=indented>\n",
1795       "\t\t\t\t\t<div id='shownObjectTypesList_1' class='shownObjectsList'></div>\n",
1796       "\t\t\t\t</div>\n",
1797       "\t\t\t\t<div class=suboption>Objects</div>\n",
1798       "\t\t\t\t<div class=indented>\n",
1799       "\t\t\t\t   <div id='shownObjectsList_1' class='shownObjectsList'></div>\n",
1800       "\t\t\t\t</div>\n",
1801       "\t\t\t</div>\n",
1802       "         \n",
1803       "         <div class=group id='camera_1'>\n",
1804       "            <strong>Camera</strong>\n",
1805       "            <div class=indented>\n",
1806       "               <form>\n",
1807       "                  <select id=\"cameraType_1\">\n",
1808       "                     <option value='perspective' selected> Perspective<br></option>\n",
1809       "                     <option value='orthographic' > Orthographic<br></option>\n",
1810       "                  </select>\n",
1811       "               </form>\n",
1812       "            </div>\n",
1813       "         </div>\n",
1814       "\n",
1815       "\t\t\t<div class=group id='svg_1'>\n",
1816       "\t\t\t\t<strong>SVG</strong>\n",
1817       "\t\t\t\t<div class=indented>\n",
1818       "\t\t\t\t\t<form>\n",
1819       "\t\t\t\t\t\t<input type=\"radio\" name='screenshotMode' value='download' id='download_1' checked> Download<br>\n",
1820       "\t\t\t\t\t\t<input type=\"radio\" name='screenshotMode' value='tab' id='tab_1' > New tab<br>\n",
1821       "\t\t\t\t\t</form>\n",
1822       "\t\t\t\t\t<button id='takeScreenshot_1'>Screenshot</button>\n",
1823       "\t\t\t\t</div>\n",
1824       "\t\t\t</div>\n",
1825       "\n",
1826       "\t\t</div>\t<!-- end of settings -->\n",
1827       "\t\t<img id='hideSettingsButton_1' class='hideSettingsButton' src='/kernelspecs/polymake/close.svg' width=20px\">\n",
1828       "\t\t<img id='showSettingsButton_1' class='showSettingsButton' src='/kernelspecs/polymake/menu.svg' width=20px\">\n",
1829       "<div id=\"model79422509120\"></div>\n",
1830       "</div>\n",
1831       "   <script>\n",
1832       "    requirejs.config({\n",
1833       "      paths: {\n",
1834       "        three: '/kernelspecs/polymake/three',\n",
1835       "        TrackballControls: '/kernelspecs/polymake/TrackballControls',\n",
1836       "        OrbitControls: '/kernelspecs/polymake/OrbitControls',\n",
1837       "        Projector: '/kernelspecs/polymake/Projector',\n",
1838       "        SVGRenderer: '/kernelspecs/polymake/SVGRenderer',\n",
1839       "        WEBGL: '/kernelspecs/polymake/WebGL',\n",
1840       "      },\n",
1841       "      shim: {\n",
1842       "        'three': { exports: 'THREE'},\n",
1843       "        'SVGRenderer': { deps: [ 'three' ], exports: 'THREE.SVGRenderer' },\n",
1844       "        'WEBGL': { deps: [ 'three' ], exports: 'THREE.WEBGL' },\n",
1845       "        'Projector': { deps: [ 'three' ], exports: 'THREE.Projector' },\n",
1846       "        'TrackballControls': { deps: [ 'three' ], exports: 'THREE.TrackballControls' },\n",
1847       "        'OrbitControls': { deps: [ 'three' ], exports: 'THREE.OrbitControls' },\n",
1848       "      }\n",
1849       "    });\n",
1850       "    \n",
1851       "    require(['three'],function(THREE){\n",
1852       "        window.THREE = THREE;\n",
1853       "      require(['TrackballControls', 'OrbitControls', 'Projector', 'SVGRenderer', 'WEBGL'],\n",
1854       "               function(TrackballControls, OrbitControls, Projector, SVGRenderer, WEBGL) {\n",
1855       "    THREE.TrackballControls = TrackballControls;\n",
1856       "    THREE.OrbitControls = OrbitControls;\n",
1857       "    THREE.Projector = Projector;\n",
1858       "    THREE.SVGRenderer = SVGRenderer;\n",
1859       "    THREE.WEBGL = WEBGL;\n",
1860       "\n",
1861       "// COMMON_CODE_BLOCK_BEGIN\n",
1862       "\n",
1863       "const intervalLength = 25; // for automatic animations\n",
1864       "const explodableModel = true; \n",
1865       "const modelContains = { points: false, pointlabels: false, lines: false, edgelabels: false, faces: false, arrowheads: false };\n",
1866       "const foldables = [];\n",
1867       "\n",
1868       "var three = document.getElementById(\"model79422509120\");\n",
1869       "var scene = new THREE.Scene();\n",
1870       "var renderer = new THREE.WebGLRenderer( { antialias: true } );\n",
1871       "var svgRenderer = new THREE.SVGRenderer( { antialias: true } );\n",
1872       "renderer.setPixelRatio( window.devicePixelRatio );\n",
1873       "renderer.setClearColor(0xFFFFFF, 1);\n",
1874       "svgRenderer.setClearColor(0xFFFFFF, 1);\n",
1875       "three.appendChild(renderer.domElement);\n",
1876       "\n",
1877       "var frustumSize = 4;\n",
1878       "var cameras = [new THREE.PerspectiveCamera(75, 1, 0.1, 1000), new THREE.OrthographicCamera()];\n",
1879       "cameras.forEach(function(cam) {\n",
1880       "    cam.position.set(0, 0, 5);\n",
1881       "    cam.lookAt(0, 0, 0);  \n",
1882       "    cam.up.set(0, 1, 0);         \n",
1883       "});\n",
1884       "var controls = [new THREE.TrackballControls(cameras[0], three), new THREE.OrbitControls(cameras[1], three)];\n",
1885       "var camera, control;\n",
1886       "\n",
1887       "controls[0].zoomSpeed = 0.2;\n",
1888       "controls[0].rotateSpeed = 4;\n",
1889       "\n",
1890       "\n",
1891       "// class to allow move points together with labels and spheres\n",
1892       "var PMPoint = function (x,y,z) {\n",
1893       "   this.vector = new THREE.Vector3(x,y,z);\n",
1894       "   this.sprite = null;\n",
1895       "   this.sphere = null;\n",
1896       "}\n",
1897       "PMPoint.prototype.addLabel = function(labelsprite) {\n",
1898       "   this.sprite = labelsprite;\n",
1899       "   this.sprite.position.copy(this.vector);\n",
1900       "}\n",
1901       "PMPoint.prototype.addSphere = function(spheremesh) {\n",
1902       "   this.sphere = spheremesh;\n",
1903       "   this.sphere.position.copy(this.vector);\n",
1904       "}\n",
1905       "PMPoint.prototype.set = function(x,y,z) {\n",
1906       "   this.vector.set(x,y,z);\n",
1907       "   if (this.sprite) {\n",
1908       "      this.sprite.position.copy(this.vector);\n",
1909       "   }\n",
1910       "   if (this.sphere) {\n",
1911       "      this.sphere.position.copy(this.vector);\n",
1912       "   }\n",
1913       "}\n",
1914       "PMPoint.prototype.radius = function() {\n",
1915       "   if (this.sphere) {\n",
1916       "      return this.sphere.geometry.parameters.radius;\n",
1917       "   } else {\n",
1918       "      return 0;\n",
1919       "   }\n",
1920       "};\n",
1921       "// select the target node\n",
1922       "var target = document.querySelector('#model79422509120');\n",
1923       "\n",
1924       "// create an observer instance\n",
1925       "var observer = new MutationObserver(function(mutations) {\n",
1926       "   mutations.forEach(function(mutation) {\n",
1927       "      if (mutation.removedNodes && mutation.removedNodes.length > 0) {\n",
1928       "         cancelAnimationFrame(renderId);\n",
1929       "         observer.disconnect();\n",
1930       "         console.log(\"cancelled frame \"+renderId);\n",
1931       "      }\n",
1932       "   });\n",
1933       "});\n",
1934       "\n",
1935       "// configuration of the observer:\n",
1936       "var config = { childList: true, characterData: true }\n",
1937       "\n",
1938       "// pass in the target node, as well as the observer options\n",
1939       "while (target) {\n",
1940       "   if (target.className==\"output\") {\n",
1941       "      observer.observe(target, config);\n",
1942       "      break;\n",
1943       "   }\n",
1944       "   target = target.parentNode;\n",
1945       "}\n",
1946       "\n",
1947       "// COMMON_CODE_BLOCK_END\n",
1948       "\n",
1949       "var obj0 = new THREE.Object3D();\n",
1950       "obj0.name = \"scaled_rs\";\n",
1951       "obj0.userData.explodable = 1;\n",
1952       "obj0.userData.points = [];\n",
1953       "obj0.userData.points.push(new PMPoint(-1.00909, -0.491753, 1.65527));\n",
1954       "obj0.userData.points.push(new PMPoint(-0.342494, -1.96619, 0.129558));\n",
1955       "obj0.userData.points.push(new PMPoint(0.79433, -1.0065, 1.53492));\n",
1956       "obj0.userData.points.push(new PMPoint(-1.63718, -1.11003, -0.29574));\n",
1957       "obj0.userData.points.push(new PMPoint(-1.26888, -0.325036, -1.51139));\n",
1958       "obj0.userData.points.push(new PMPoint(-0.511749, 1.81794, -0.658173));\n",
1959       "obj0.userData.points.push(new PMPoint(-0.544735, 0.0656413, -1.92327));\n",
1960       "obj0.userData.points.push(new PMPoint(1.75488, 0.756399, 0.590139));\n",
1961       "obj0.userData.points.push(new PMPoint(0.862733, 0.812798, -1.61092));\n",
1962       "obj0.userData.points.push(new PMPoint(-1.95588, 0.316236, 0.272963));\n",
1963       "obj0.userData.points.push(new PMPoint(0.532226, 0.131617, 1.92339));\n",
1964       "obj0.userData.points.push(new PMPoint(-1.10816, -0.781368, -1.47019));\n",
1965       "obj0.userData.points.push(new PMPoint(1.59181, 0.0667565, -1.209));\n",
1966       "obj0.userData.points.push(new PMPoint(0.161173, 1.96236, 0.350941));\n",
1967       "obj0.userData.points.push(new PMPoint(-1.8806, -0.668687, 0.127224));\n",
1968       "obj0.userData.points.push(new PMPoint(-0.409209, 0.223782, 1.94486));\n",
1969       "obj0.userData.points.push(new PMPoint(-0.892021, -0.948635, -1.51802));\n",
1970       "obj0.userData.points.push(new PMPoint(-1.89858, 0.431969, -0.456932));\n",
1971       "obj0.userData.points.push(new PMPoint(-1.16651, -0.164456, -1.61623));\n",
1972       "obj0.userData.points.push(new PMPoint(0.333079, 0.125055, 1.9681));\n",
1973       "\n",
1974       "obj0.userData.edgeindices = [0, 1, 0, 2, 1, 2, 1, 3, 3, 4, 5, 6, 2, 7, 5, 8, 6, 8, 7, 8, 0, 9, 5, 9, 2, 10, 7, 10, 3, 11, 4, 11, 1, 12, 2, 12, 6, 12, 7, 12, 8, 12, 5, 13, 7, 13, 8, 13, 9, 13, 10, 13, 0, 14, 1, 14, 3, 14, 9, 14, 0, 15, 9, 15, 13, 15, 1, 16, 3, 16, 6, 16, 11, 16, 12, 16, 3, 17, 4, 17, 5, 17, 9, 17, 14, 17, 4, 18, 5, 18, 6, 18, 11, 18, 16, 18, 17, 18, 0, 19, 2, 19, 10, 19, 13, 19, 15, 19];\n",
1975       "   <!-- Edge style -->\n",
1976       "obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
1977       "obj0.userData.facets = [[12, 6, 8], [16, 6, 12], [12, 1, 16], [12, 2, 1], [2, 10, 19], [2, 19, 0], [1, 2, 0], [13, 15, 19], [15, 0, 19], [16, 1, 3], [1, 0, 14], [1, 14, 3], [5, 6, 18], [5, 18, 17], [5, 17, 9], [11, 16, 3], [18, 16, 11], [18, 11, 4], [11, 3, 4], [17, 4, 3], [17, 3, 14], [9, 17, 14], [17, 18, 4], [9, 14, 0], [18, 6, 16], [15, 9, 0], [13, 5, 9], [13, 9, 15], [10, 13, 19], [8, 6, 5], [8, 5, 13], [7, 8, 13], [7, 13, 10], [2, 7, 10], [12, 7, 2], [12, 8, 7]];\n",
1978       "init_object(obj0);\n",
1979       "scene.add(obj0);\n",
1980       "\n",
1981       "var obj1 = new THREE.Object3D();\n",
1982       "obj1.name = \"Lattice points and vertices of scaled_rs\";\n",
1983       "obj1.userData.explodable = 1;\n",
1984       "obj1.userData.points = [];\n",
1985       "obj1.userData.points.push(new PMPoint(-1, -1, -1));\n",
1986       "obj1.userData.points.push(new PMPoint(-1, -1, 0));\n",
1987       "obj1.userData.points.push(new PMPoint(-1, 0, -1));\n",
1988       "obj1.userData.points.push(new PMPoint(-1, 0, 0));\n",
1989       "obj1.userData.points.push(new PMPoint(-1, 0, 1));\n",
1990       "obj1.userData.points.push(new PMPoint(-1, 1, 0));\n",
1991       "obj1.userData.points.push(new PMPoint(0, -1, 0));\n",
1992       "obj1.userData.points.push(new PMPoint(0, -1, 1));\n",
1993       "obj1.userData.points.push(new PMPoint(0, 0, -1));\n",
1994       "obj1.userData.points.push(new PMPoint(0, 0, 0));\n",
1995       "obj1.userData.points.push(new PMPoint(0, 0, 1));\n",
1996       "obj1.userData.points.push(new PMPoint(0, 1, -1));\n",
1997       "obj1.userData.points.push(new PMPoint(0, 1, 0));\n",
1998       "obj1.userData.points.push(new PMPoint(0, 1, 1));\n",
1999       "obj1.userData.points.push(new PMPoint(1, 0, -1));\n",
2000       "obj1.userData.points.push(new PMPoint(1, 0, 0));\n",
2001       "obj1.userData.points.push(new PMPoint(1, 0, 1));\n",
2002       "obj1.userData.points.push(new PMPoint(1, 1, 0));\n",
2003       "obj1.userData.points.push(new PMPoint(-1.00909, -0.491753, 1.65527));\n",
2004       "obj1.userData.points.push(new PMPoint(-0.342494, -1.96619, 0.129558));\n",
2005       "obj1.userData.points.push(new PMPoint(0.79433, -1.0065, 1.53492));\n",
2006       "obj1.userData.points.push(new PMPoint(-1.63718, -1.11003, -0.29574));\n",
2007       "obj1.userData.points.push(new PMPoint(-1.26888, -0.325036, -1.51139));\n",
2008       "obj1.userData.points.push(new PMPoint(-0.511749, 1.81794, -0.658173));\n",
2009       "obj1.userData.points.push(new PMPoint(-0.544735, 0.0656413, -1.92327));\n",
2010       "obj1.userData.points.push(new PMPoint(1.75488, 0.756399, 0.590139));\n",
2011       "obj1.userData.points.push(new PMPoint(0.862733, 0.812798, -1.61092));\n",
2012       "obj1.userData.points.push(new PMPoint(-1.95588, 0.316236, 0.272963));\n",
2013       "obj1.userData.points.push(new PMPoint(0.532226, 0.131617, 1.92339));\n",
2014       "obj1.userData.points.push(new PMPoint(-1.10816, -0.781368, -1.47019));\n",
2015       "obj1.userData.points.push(new PMPoint(1.59181, 0.0667565, -1.209));\n",
2016       "obj1.userData.points.push(new PMPoint(0.161173, 1.96236, 0.350941));\n",
2017       "obj1.userData.points.push(new PMPoint(-1.8806, -0.668687, 0.127224));\n",
2018       "obj1.userData.points.push(new PMPoint(-0.409209, 0.223782, 1.94486));\n",
2019       "obj1.userData.points.push(new PMPoint(-0.892021, -0.948635, -1.51802));\n",
2020       "obj1.userData.points.push(new PMPoint(-1.89858, 0.431969, -0.456932));\n",
2021       "obj1.userData.points.push(new PMPoint(-1.16651, -0.164456, -1.61623));\n",
2022       "obj1.userData.points.push(new PMPoint(0.333079, 0.125055, 1.9681));\n",
2023       "\n",
2024       "obj1.userData.pointradii = 0.02;\n",
2025       "   <!-- Vertex style -->\n",
2026       "obj1.userData.pointmaterial = [new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2027       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2028       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2029       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2030       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2031       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2032       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2033       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2034       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2035       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2036       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2037       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2038       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2039       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2040       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2041       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2042       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2043       "new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
2044       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2045       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2046       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2047       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2048       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2049       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2050       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2051       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2052       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2053       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2054       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2055       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2056       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2057       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2058       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2059       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2060       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2061       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2062       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
2063       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } )];\n",
2064       "init_object(obj1);\n",
2065       "scene.add(obj1);\n",
2066       "\n",
2067       "// COMMON_CODE_BLOCK_BEGIN\n",
2068       "function textSpriteMaterial(message, parameters) {\n",
2069       "    if ( parameters === undefined ) parameters = {};\n",
2070       "    var fontface = \"Helvetica\";\n",
2071       "    var fontsize = parameters.hasOwnProperty(\"fontsize\") ? parameters[\"fontsize\"] : 15;\n",
2072       "    fontsize = fontsize*10;\n",
2073       "    var lines = message.split('\\\\n');\n",
2074       "    var size = 512;\n",
2075       "    for(var i = 0; i<lines.length; i++){\n",
2076       "        var tmp = lines[i].length;\n",
2077       "        while(tmp*fontsize > size){\n",
2078       "           fontsize--;\n",
2079       "        }\n",
2080       "    }\n",
2081       "    \n",
2082       "    var canvas = document.createElement('canvas');\n",
2083       "    canvas.width = size;\n",
2084       "    canvas.height = size;\n",
2085       "    var context = canvas.getContext('2d');\n",
2086       "    context.fillStyle = \"rgba(255, 255, 255, 0)\";\n",
2087       "    context.fill();\n",
2088       "    context.font = fontsize + \"px \" + fontface;\n",
2089       "    \n",
2090       "    // text color\n",
2091       "    context.fillStyle = \"rgba(0, 0, 0, 1.0)\";\n",
2092       "     for(var i = 0; i<lines.length; i++){\n",
2093       "        context.fillText(lines[i], size/2, size/2+i*fontsize);\n",
2094       "     }\n",
2095       "    \n",
2096       "    // canvas contents will be used for a texture\n",
2097       "    var texture = new THREE.Texture(canvas);\n",
2098       "    texture.needsUpdate = true;\n",
2099       "    \n",
2100       "    var spriteMaterial = new THREE.SpriteMaterial({map: texture, depthTest: true, depthWrite: false, polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: 1 });\n",
2101       "    return spriteMaterial;\n",
2102       "}\n",
2103       "\n",
2104       "\n",
2105       "// ---------------------- INITIALIZING OBJECTS--------------------------------------\n",
2106       "// ---------------------------------------------------------------------------------\n",
2107       "\n",
2108       "function init_object(obj) {\n",
2109       "    if (obj.userData.hasOwnProperty(\"pointmaterial\")) {\n",
2110       "        init_points(obj);\n",
2111       "        modelContains.points = true;\n",
2112       "    }\n",
2113       "    if (obj.userData.hasOwnProperty(\"pointlabels\")) {\n",
2114       "        init_pointlabels(obj);\n",
2115       "        modelContains.pointlabels = true;\n",
2116       "    }\n",
2117       "    if (obj.userData.hasOwnProperty(\"edgematerial\")) {\n",
2118       "        init_lines(obj);\n",
2119       "        modelContains.lines = true;\n",
2120       "    }\n",
2121       "    if (obj.userData.hasOwnProperty(\"edgelabels\")) {\n",
2122       "        init_edgelabels(obj);\n",
2123       "        modelContains.edgelabels = true;\n",
2124       "    }\n",
2125       "    if (obj.userData.hasOwnProperty(\"arrowstyle\")) {\n",
2126       "        init_arrowheads(obj);\n",
2127       "        modelContains.arrowheads = true;\n",
2128       "    }\n",
2129       "    if (obj.userData.hasOwnProperty(\"facetmaterial\")) {\n",
2130       "        init_faces(obj);\n",
2131       "        modelContains.faces = true;\n",
2132       "    }\n",
2133       "}\n",
2134       "\n",
2135       "function init_points(obj) {\n",
2136       "    var pointgroup = new THREE.Group();\n",
2137       "    pointgroup.name = \"points\";\n",
2138       "    var points = obj.userData.points;\n",
2139       "    var radii = obj.userData.pointradii;\n",
2140       "    var materials = obj.userData.pointmaterial;\n",
2141       "    var geometry,material;\n",
2142       "    if (!Array.isArray(radii)) {\n",
2143       "        geometry = new THREE.SphereBufferGeometry(radii);  \n",
2144       "    }\n",
2145       "    if (!Array.isArray(materials)) {\n",
2146       "        material = materials;\n",
2147       "    }\n",
2148       "    for (var i=0; i<points.length; i++) {\n",
2149       "        var point = points[i];\n",
2150       "        if (Array.isArray(radii)) {\n",
2151       "            if (radii[i] == 0) {\n",
2152       "                continue;\n",
2153       "            }\n",
2154       "            geometry = new THREE.SphereBufferGeometry(radii[i]);  \n",
2155       "        } \n",
2156       "        if (Array.isArray(materials)) {\n",
2157       "            material = materials[i];     \n",
2158       "        } \n",
2159       "        var sphere = new THREE.Mesh(geometry, material);\n",
2160       "        point.addSphere(sphere);\n",
2161       "        pointgroup.add(sphere);\n",
2162       "    }\n",
2163       "    obj.add(pointgroup);\n",
2164       "}\n",
2165       "\n",
2166       "function init_pointlabels(obj) {\n",
2167       "    var points = obj.userData.points;\n",
2168       "    var labels = obj.userData.pointlabels;\n",
2169       "    var pointlabels = new THREE.Group();\n",
2170       "    pointlabels.name = \"pointlabels\";\n",
2171       "    if (Array.isArray(labels)) {\n",
2172       "        for (var i=0; i<points.length; i++) {\n",
2173       "            var point = points[i];\n",
2174       "            var spriteMaterial = textSpriteMaterial( labels[i] );\n",
2175       "\t        var sprite = new THREE.Sprite(spriteMaterial);\n",
2176       "            point.addLabel(sprite);\n",
2177       "            pointlabels.add(sprite);\n",
2178       "        }\n",
2179       "    } else {\n",
2180       "        var spriteMaterial = textSpriteMaterial( labels );\n",
2181       "        for (var i=0; i<points.length; i++) {\n",
2182       "            var point = points[i];\n",
2183       "\t        var sprite = new THREE.Sprite(spriteMaterial);\n",
2184       "            point.addLabel(sprite);\n",
2185       "            pointlabels.add(sprite);\n",
2186       "        }\n",
2187       "    }\n",
2188       "    obj.add(pointlabels);\n",
2189       "}\n",
2190       "\n",
2191       "function init_lines(obj) {\n",
2192       "    var edgeindices = obj.userData.edgeindices;\n",
2193       "    var points = obj.userData.points;\n",
2194       "    var materials = obj.userData.edgematerial;\n",
2195       "    var geometry = new THREE.BufferGeometry();\n",
2196       "    var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 );\n",
2197       "    var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 );\n",
2198       "    var geometry = new THREE.BufferGeometry();\n",
2199       "    geometry.setAttribute('position', bufattr);\n",
2200       "    if (Array.isArray(materials)) {     \n",
2201       "        for (var i=0; i<materials.length; i++) {\n",
2202       "            geometry.addGroup(2*i,2,i);\n",
2203       "        }\n",
2204       "    }\n",
2205       "    var lines = new THREE.LineSegments(geometry, materials);\n",
2206       "    lines.name = \"lines\";\n",
2207       "    obj.add(lines);\n",
2208       "    updateEdgesPosition(obj);\n",
2209       "}\n",
2210       "\n",
2211       "function init_edgelabels(obj) {\n",
2212       "    var points = obj.userData.points;\n",
2213       "    var edgeindices = obj.userData.edgeindices;\n",
2214       "    var labels = obj.userData.edgelabels;\n",
2215       "    var edgelabels = new THREE.Group();\n",
2216       "    edgelabels.name = \"edgelabels\";\n",
2217       "    if (Array.isArray(labels)) {\n",
2218       "        for (var i=0; i<edgeindices.length; i=i+2) {\n",
2219       "            var point = points[i];\n",
2220       "            var spriteMaterial = textSpriteMaterial( labels[i] );\n",
2221       "            var sprite = new THREE.Sprite(spriteMaterial);\n",
2222       "            sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5));\n",
2223       "            edgelabels.add(sprite);\n",
2224       "        }\n",
2225       "    } else {\n",
2226       "        var spriteMaterial = textSpriteMaterial( labels );\n",
2227       "        for (var i=0; i<points.length; i++) {\n",
2228       "            var point = points[i];\n",
2229       "            var sprite = new THREE.Sprite(spriteMaterial);\n",
2230       "            sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5));\n",
2231       "            pointlabels.add(sprite);\n",
2232       "        }\n",
2233       "    }\n",
2234       "    obj.add(edgelabels);\n",
2235       "}\n",
2236       "\n",
2237       "function init_arrowheads(obj) {\n",
2238       "    var arrowheads = new THREE.Group();\n",
2239       "    arrowheads.name = \"arrowheads\";\n",
2240       "    var arrowstyle = obj.userData.arrowstyle;\n",
2241       "    var edgeindices = obj.userData.edgeindices;\n",
2242       "    var edgematerials = obj.userData.edgematerial;\n",
2243       "    var points = obj.userData.points;\n",
2244       "    var material;\n",
2245       "    if (!Array.isArray(edgematerials)) {\n",
2246       "        material = new THREE.MeshBasicMaterial( {color: edgematerials.color} );\n",
2247       "    }\n",
2248       "\n",
2249       "    for (var i=0; i<edgeindices.length; i=i+2) {\n",
2250       "        var start = points[edgeindices[i]];\n",
2251       "        var end = points[edgeindices[i+1]];\n",
2252       "        var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius();\n",
2253       "        if (dist <= 0) {\n",
2254       "            continue;\n",
2255       "        }\n",
2256       "        var dir = new THREE.Vector3().subVectors(end.vector,start.vector);\n",
2257       "        dir.normalize();\n",
2258       "        var axis = new THREE.Vector3().set(dir.z,0,-dir.x);\n",
2259       "        axis.normalize();\n",
2260       "        var radians = Math.acos( dir.y );\n",
2261       "        var radius = dist/25;\n",
2262       "        var height = dist/5;\n",
2263       "        var geometry = new THREE.ConeBufferGeometry(radius,height);\n",
2264       "        var position = new THREE.Vector3().addVectors(start.vector,dir.clone().multiplyScalar(start.radius()+dist-height/2));\n",
2265       "        if (Array.isArray(edgematerials)) {\n",
2266       "            material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} );\n",
2267       "        }\n",
2268       "        var cone = new THREE.Mesh( geometry, material );\n",
2269       "        cone.quaternion.setFromAxisAngle(axis,radians);;\n",
2270       "        cone.position.copy(position);;\n",
2271       "        arrowheads.add(cone);\n",
2272       "    }\n",
2273       "    obj.add(arrowheads);\n",
2274       "}\n",
2275       "\n",
2276       "function init_faces(obj) {\n",
2277       "    var points = obj.userData.points;\n",
2278       "    var facets = obj.userData.facets;\n",
2279       "    obj.userData.triangleindices = [];\n",
2280       "    for (var i=0; i<facets.length; i++) {\n",
2281       "        facet = facets[i];\n",
2282       "        for (var t=0; t<facet.length-2; t++) {\n",
2283       "            obj.userData.triangleindices.push(facet[0],facet[t+1],facet[t+2]);  \n",
2284       "        }\n",
2285       "    }\n",
2286       "    var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 );\n",
2287       "    var bufattr = new THREE.Float32BufferAttribute(bufarr,3);\n",
2288       "    \n",
2289       "    var materials = obj.userData.facetmaterial;\n",
2290       "    var geometry = new THREE.BufferGeometry();\n",
2291       "    geometry.setAttribute('position',bufattr);\n",
2292       "    if (Array.isArray(materials)) {\n",
2293       "        var tricount = 0;\n",
2294       "        var facet;\n",
2295       "        for (var i=0; i<facets.length; i++) {\n",
2296       "            facet = facets[i];\n",
2297       "            geometry.addGroup(tricount,(facet.length-2)*3,i);\n",
2298       "            tricount += (facet.length-2)*3;\n",
2299       "        }\n",
2300       "    }\n",
2301       "    var mesh = new THREE.Mesh(geometry, materials);\n",
2302       "    mesh.name = \"faces\";\n",
2303       "    obj.add(mesh); \n",
2304       "    updateFacesPosition(obj);\n",
2305       "}\n",
2306       "// //INITIALIZING\n",
2307       "\n",
2308       "\n",
2309       "function updateFacesPosition(obj) {\n",
2310       "    var points = obj.userData.points;\n",
2311       "    var indices = obj.userData.triangleindices;\n",
2312       "    var faces = obj.getObjectByName(\"faces\");\n",
2313       "    var ba = faces.geometry.getAttribute(\"position\");\n",
2314       "    for (var i=0; i<indices.length; i++) {\n",
2315       "        ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z); \n",
2316       "    }\n",
2317       "    faces.geometry.attributes.position.needsUpdate = true;\n",
2318       "    \n",
2319       "}\n",
2320       "\n",
2321       "function updateEdgesPosition(obj) {\n",
2322       "    var points = obj.userData.points;\n",
2323       "    var indices = obj.userData.edgeindices;\n",
2324       "    var lines = obj.getObjectByName(\"lines\");\n",
2325       "    var ba = lines.geometry.getAttribute(\"position\"); \n",
2326       "    for (var i=0; i<indices.length; i++) {\n",
2327       "        ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z); \n",
2328       "    }\n",
2329       "    lines.geometry.attributes.position.needsUpdate = true;\n",
2330       "}\n",
2331       "\n",
2332       "function onWindowResize() {\n",
2333       "    renderer.setSize( three.clientWidth, three.clientHeight );\n",
2334       "    svgRenderer.setSize( three.clientWidth, three.clientHeight );\n",
2335       "    updateCamera();\n",
2336       "}\n",
2337       "\n",
2338       "function updateCamera() {\n",
2339       "    var width = three.clientWidth;\n",
2340       "    var height = three.clientHeight;\n",
2341       "    var aspect = width / height;\n",
2342       "    if (camera.type == \"OrthographicCamera\") {\n",
2343       "        camera.left = frustumSize * aspect / - 2;\n",
2344       "        camera.right = frustumSize * aspect / 2;\n",
2345       "        camera.top = frustumSize / 2;\n",
2346       "        camera.bottom = - frustumSize / 2;\n",
2347       "    } else if (camera.type == \"PerspectiveCamera\") {\n",
2348       "        camera.aspect = aspect;\n",
2349       "    }\n",
2350       "    camera.updateProjectionMatrix();\n",
2351       "}\n",
2352       "\n",
2353       "function changeCamera(event) {\n",
2354       "    var selindex = event.currentTarget.selectedIndex;\n",
2355       "    camera = cameras[selindex];\n",
2356       "    control = controls[selindex];\n",
2357       "    control.enabled = true; \n",
2358       "    for (var i=0; i<controls.length; i++) {\n",
2359       "        if (i!=selindex) {\n",
2360       "            controls[i].enabled = false;\n",
2361       "        }\n",
2362       "    }\n",
2363       "    updateCamera();\n",
2364       "}\n",
2365       "\n",
2366       "var camtypenode = document.getElementById('cameraType_1');\n",
2367       "camtypenode.onchange = changeCamera;\n",
2368       "camtypenode.dispatchEvent(new Event('change'));\n",
2369       "\n",
2370       "onWindowResize();\n",
2371       "window.addEventListener('resize', onWindowResize);\t\n",
2372       "\n",
2373       "\n",
2374       "var xRotationEnabled = false;\n",
2375       "var yRotationEnabled = false;\n",
2376       "var zRotationEnabled = false;\n",
2377       "var rotationSpeedFactor = 1;\n",
2378       "var settingsShown = false;\n",
2379       "var labelsShown = true;\n",
2380       "var intervals = [];\n",
2381       "var timeouts = [];\n",
2382       "var explodingSpeed = 0.05;\n",
2383       "var explodeScale = 0;\n",
2384       "var XMLS = new XMLSerializer();\n",
2385       "var svgElement;\n",
2386       "var renderId;\n",
2387       "\n",
2388       "var render = function () {\n",
2389       "\n",
2390       "\trenderId = requestAnimationFrame(render);\n",
2391       "\n",
2392       "//\tcomment in for automatic explosion\n",
2393       "//\texplode(updateFactor());\n",
2394       "\n",
2395       "    var phi = 0.02 * rotationSpeedFactor;\n",
2396       "\n",
2397       "    if (xRotationEnabled) {\n",
2398       "        scene.rotation.x += phi;\n",
2399       "    }\n",
2400       "    if (yRotationEnabled) {\n",
2401       "        scene.rotation.y += phi;\n",
2402       "    }\n",
2403       "    if (zRotationEnabled) {\n",
2404       "        scene.rotation.z += phi;\n",
2405       "    }\n",
2406       "\n",
2407       "    control.update();\n",
2408       "    renderer.render(scene, camera);\n",
2409       "};\n",
2410       "\n",
2411       "if ( THREE.WEBGL.isWebGLAvailable() ) {\n",
2412       "\trender();\n",
2413       "} else {\n",
2414       "\tvar warning = WEBGL.getWebGLErrorMessage();\n",
2415       "\tthree.appendChild( warning );\n",
2416       "}\n",
2417       "    \n",
2418       "function changeTransparency() {\n",
2419       "    var opacity = 1-Number(event.currentTarget.value);\n",
2420       "    for (var i=0; i<scene.children.length; i++) {\n",
2421       "        child = scene.children[i];\n",
2422       "        if ( child.userData.hasOwnProperty(\"facetmaterial\") ) {\n",
2423       "            if (Array.isArray(child.userData.facetmaterial)) {\n",
2424       "                for (var j=0; j<child.userData.facetmaterial.length; j++) {\n",
2425       "                    child.userData.facetmaterial[j].opacity = opacity;\n",
2426       "                }\n",
2427       "            } else {\n",
2428       "                child.userData.facetmaterial.opacity = opacity;\n",
2429       "            }    \n",
2430       "        }\n",
2431       "    }\n",
2432       "}\n",
2433       "\n",
2434       "function changeRotationX(event){\n",
2435       "    xRotationEnabled = event.currentTarget.checked;\n",
2436       "}\t\n",
2437       "\n",
2438       "function changeRotationY(event){\n",
2439       "    yRotationEnabled = event.currentTarget.checked;\n",
2440       "}\t\n",
2441       "\n",
2442       "function changeRotationZ(event){\n",
2443       "    zRotationEnabled = event.currentTarget.checked;\n",
2444       "}\t\n",
2445       "\n",
2446       "\n",
2447       "function changeRotationSpeedFactor(event){\n",
2448       "    rotationSpeedFactor = Number(event.currentTarget.value);\n",
2449       "}\n",
2450       "\n",
2451       "function resetScene(){\n",
2452       "    scene.rotation.set(0,0,0);\n",
2453       "    camera.position.set(0,0,5);\n",
2454       "    camera.up.set(0,1,0);\n",
2455       "}\n",
2456       "\n",
2457       "function showSettings(event){\n",
2458       "    document.getElementById('settings_1').style.visibility = 'visible';\n",
2459       "    document.getElementById('showSettingsButton_1').style.visibility = 'hidden';\n",
2460       "    document.getElementById('hideSettingsButton_1').style.visibility = 'visible';\n",
2461       "    settingsShown = true;\n",
2462       "}\n",
2463       "\n",
2464       "function hideSettings(event){\n",
2465       "    document.getElementById('settings_1').style.visibility = 'hidden';\n",
2466       "    document.getElementById('showSettingsButton_1').style.visibility = 'visible';\n",
2467       "    document.getElementById('hideSettingsButton_1').style.visibility = 'hidden';\n",
2468       "    settingsShown = false;\n",
2469       "}\n",
2470       "\n",
2471       "\n",
2472       "\n",
2473       "var pos = 150* Math.PI;\n",
2474       "\n",
2475       "function updateFactor() {\n",
2476       "    pos++;\n",
2477       "    return Math.sin(.01*pos)+1;\n",
2478       "}\n",
2479       "\n",
2480       "// ------------------------ FOLDING ------------------------------------------------\n",
2481       "// ---------------------------------------------------------------------------------\n",
2482       "// rotate point p around axis defined by points p1 and p2 by given angle\n",
2483       "function rotate(p, p1, p2, angle ){   \n",
2484       "    angle = -angle;\n",
2485       "    var x = p.x, y = p.y, z = p.z, \n",
2486       "    a = p1.x, b = p1.y, c = p1.z, \n",
2487       "    u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z;\n",
2488       "    var result = [];\n",
2489       "    var L = u*u + v*v + w*w;\n",
2490       "    var sqrt = Math.sqrt;\n",
2491       "    var cos = Math.cos;\n",
2492       "    var sin = Math.sin;\n",
2493       "\n",
2494       "    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))/L;\n",
2495       "    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))/L;\n",
2496       "    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))/L;\n",
2497       "\n",
2498       "    return result;\n",
2499       "}\n",
2500       "\n",
2501       "var fold = function(event){\n",
2502       "    var obj = foldables[Number(event.currentTarget.name)];\n",
2503       "    var foldvalue = Number(event.currentTarget.value);\n",
2504       "    var scale = foldvalue - obj.userData.oldscale;\n",
2505       "\n",
2506       "    for (var j=0; j<obj.userData.axes.length; j++) {\n",
2507       "        rotateVertices(obj, j, scale);\n",
2508       "    }\n",
2509       "    update(obj);\n",
2510       "    obj.userData.oldscale += scale;\n",
2511       "    lookAtBarycenter(obj);\n",
2512       "}\n",
2513       "\n",
2514       "function lookAtBarycenter(obj){\n",
2515       "    control.target = barycenter(obj);\n",
2516       "}\n",
2517       "\n",
2518       "function barycenter(obj) {\n",
2519       "    var center = new THREE.Vector3(0,0,0);\n",
2520       "    var points = obj.userData.points;\n",
2521       "    for (var i=0; i<points.length; i++){\n",
2522       "        center.add(points[i].vector);\n",
2523       "    }\n",
2524       "    center.divideScalar(points.length);\n",
2525       "    return center;\n",
2526       "}\n",
2527       "\n",
2528       "function rotateVertices(obj, edge, scale) {\n",
2529       "    var axes = obj.userData.axes;\n",
2530       "    var subtrees = obj.userData.subtrees;\n",
2531       "    var points = obj.userData.points;\n",
2532       "    var angles = obj.userData.angles;\n",
2533       "    if (edge < axes.length){\n",
2534       "        for (var j=0; j<subtrees[edge].length; j++){\n",
2535       "            var rotP = rotate(points[subtrees[edge][j]].vector, points[axes[edge][0]].vector,points[axes[edge][1]].vector, scale * (Math.PI - angles[edge]));\n",
2536       "            points[subtrees[edge][j]].set(rotP[0],rotP[1],rotP[2]);\n",
2537       "        }\n",
2538       "    }\n",
2539       "}\n",
2540       "\n",
2541       "function update(obj) {\n",
2542       "   updateFacesPosition(obj);\n",
2543       "   updateEdgesPosition(obj);\n",
2544       "}\n",
2545       "\n",
2546       "if (foldables.length) {\n",
2547       "    var settings = document.getElementById('settings_1');\n",
2548       "    var foldDiv = document.createElement('div');\n",
2549       "    foldDiv.id = 'fold_1';\n",
2550       "    var title = document.createElement('strong');\n",
2551       "    title.innerHTML = 'Fold';\n",
2552       "    foldDiv.appendChild(title);\n",
2553       "    foldDiv.className = 'group';\n",
2554       "    for (var i=0; i<foldables.length; i++) {\n",
2555       "        var range = document.createElement('input');\n",
2556       "        range.type = 'range';\n",
2557       "        range.min = 0;\n",
2558       "        range.max = 1;\n",
2559       "        range.value = 0;\n",
2560       "        range.step = 0.001;\n",
2561       "        range.name = String(i);\n",
2562       "        range.oninput = fold;\n",
2563       "        foldDiv.appendChild(range);\n",
2564       "    }\n",
2565       "    lookAtBarycenter(foldables[0]);\n",
2566       "    settings.insertBefore(foldDiv,settings.childNodes[0]);\n",
2567       "}\n",
2568       "\n",
2569       "    \n",
2570       "// ---------------------- EXPLOSION ------------------------------------------------\n",
2571       "// ---------------------------------------------------------------------------------\n",
2572       "\n",
2573       "if (explodableModel) {\n",
2574       "    for (var i=0; i<scene.children.length; i++) {\n",
2575       "        obj = scene.children[i];\n",
2576       "        if ( obj.userData.explodable ) {\n",
2577       "            computeCentroid(obj);\n",
2578       "        }\n",
2579       "    }\n",
2580       "    document.getElementById('explodeRange_1').oninput = triggerExplode;\n",
2581       "    document.getElementById('explodeCheckbox_1').onchange = triggerAutomaticExplode;\n",
2582       "    document.getElementById('explodingSpeedRange_1').oninput = setExplodingSpeed;\n",
2583       "}\n",
2584       "\n",
2585       "function computeCentroid(obj) {\n",
2586       "    centroid = new THREE.Vector3();\n",
2587       "    obj.userData.points.forEach(function(pmpoint) {\n",
2588       "        centroid.add(pmpoint.vector);\t\t\t\n",
2589       "    });\n",
2590       "    centroid.divideScalar(obj.userData.points.length);\n",
2591       "    obj.userData.centroid = centroid;\n",
2592       "}\n",
2593       "\n",
2594       "function explode(factor) {\n",
2595       "    for (var i=0; i<scene.children.length; i++) {\n",
2596       "        var obj = scene.children[i];\n",
2597       "        if (obj.userData.hasOwnProperty(\"centroid\")) { \n",
2598       "            var c = obj.userData.centroid;\n",
2599       "            obj.position.set(c.x*factor, c.y*factor, c.z*factor);\n",
2600       "        }\n",
2601       "    }\t\n",
2602       "}\n",
2603       "\n",
2604       "function triggerExplode(event){\n",
2605       "    explodeScale = Number(event.currentTarget.value);\n",
2606       "    explode(explodeScale);\n",
2607       "}\n",
2608       "\n",
2609       "function setExplodingSpeed(event){\n",
2610       "    explodingSpeed = Number(event.currentTarget.value);\n",
2611       "}\n",
2612       "\n",
2613       "function triggerAutomaticExplode(event){\n",
2614       "    if (event.currentTarget.checked){\n",
2615       "        startExploding();\n",
2616       "    } else {\n",
2617       "        clearIntervals();\n",
2618       "    }\t\n",
2619       "}\n",
2620       "\n",
2621       "function startExploding(){\n",
2622       "    intervals.push(setInterval(explodingInterval, 25));\n",
2623       "}\n",
2624       "\n",
2625       "\n",
2626       "function explodingInterval(){\n",
2627       "    explodeScale += explodingSpeed;\n",
2628       "    if (explodeScale <= 6){ \n",
2629       "        explode(explodeScale);\n",
2630       "    }\n",
2631       "    else{\n",
2632       "        explode(6);\n",
2633       "        explodeScale = 6;\n",
2634       "        clearIntervals();\n",
2635       "        timeouts.push(setTimeout(startUnexploding, 3000));\n",
2636       "    }\n",
2637       "    document.getElementById('explodeRange_1').value = explodeScale;\n",
2638       "}\n",
2639       "\n",
2640       "\n",
2641       "function startUnexploding(){\n",
2642       "    intervals.push(setInterval(unexplodingInterval, 25));\n",
2643       "}\n",
2644       "\n",
2645       "function unexplodingInterval(){\n",
2646       "    explodeScale -= explodingSpeed;\n",
2647       "    if (explodeScale >= 0){\t\n",
2648       "        explode(explodeScale);\n",
2649       "    }\n",
2650       "    else {\n",
2651       "        explode(0);\n",
2652       "        explodeScale = 0;\n",
2653       "        clearIntervals();\n",
2654       "        timeouts.push(setTimeout(startExploding, 3000));\n",
2655       "    }\n",
2656       "    document.getElementById('explodeRange_1').value = explodeScale;\n",
2657       "}\n",
2658       "\n",
2659       "function clearIntervals(){\n",
2660       "    intervals.forEach(function(interval){\n",
2661       "        clearInterval(interval);\n",
2662       "    });\n",
2663       "    intervals = [];\n",
2664       "    timeouts.forEach(function(timeout){\n",
2665       "        clearTimeout(timeout);\n",
2666       "    });\n",
2667       "    timeouts = [];\n",
2668       "}\n",
2669       "\n",
2670       "// ---------------------- DISPLAY --------------------------------------------------\n",
2671       "// ---------------------------------------------------------------------------------\n",
2672       "\n",
2673       "const objectTypeInnerHTMLs = { points: \"Points\", pointlabels: \"Point labels\", lines: \"Edges\", edgelabels: \"Edge labels\", faces: \"Faces\", arrowheads: \"Arrow heads\" };\n",
2674       "const objectTypeVisible = {};\n",
2675       "Object.assign(objectTypeVisible,modelContains);\n",
2676       "const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort();\n",
2677       "const shownObjectTypesList = document.getElementById('shownObjectTypesList_1');\n",
2678       "\n",
2679       "function setVisibility(bool,objname) {\n",
2680       "    for (var i=0; i<scene.children.length; i++){\n",
2681       "        var obj = scene.children[i].getObjectByName(objname);\n",
2682       "        if (obj) {\n",
2683       "            obj.visible = bool;\n",
2684       "        }\n",
2685       "    }\n",
2686       "}\n",
2687       "\n",
2688       "function toggleObjectTypeVisibility(event){\n",
2689       "    var name = event.currentTarget.name;\n",
2690       "    var checked = event.currentTarget.checked;\n",
2691       "    objectTypeVisible[name] = checked;\n",
2692       "    setVisibility(checked,name);\n",
2693       "}\n",
2694       "\n",
2695       "for (var i=0; i<sortedObjectTypeKeys.length; i++){\n",
2696       "    var key = sortedObjectTypeKeys[i];\n",
2697       "    if (modelContains[key]) {\n",
2698       "        var objTypeNode = document.createElement('span');\n",
2699       "        objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '<br>';\n",
2700       "        var checkbox = document.createElement('input');\n",
2701       "        checkbox.type = 'checkbox';\n",
2702       "        checkbox.checked = true;\n",
2703       "        checkbox.name = key;\n",
2704       "        checkbox.onchange = toggleObjectTypeVisibility;\n",
2705       "        shownObjectTypesList.appendChild(checkbox);\n",
2706       "        shownObjectTypesList.appendChild(objTypeNode);\n",
2707       "    }\n",
2708       "}\n",
2709       "\n",
2710       "// ------------------------------------------------------\n",
2711       "\n",
2712       "function toggleObjectVisibility(event){\n",
2713       "    var nr = Number(event.currentTarget.name);\n",
2714       "    scene.children[nr].visible = event.currentTarget.checked;\n",
2715       "}\n",
2716       "\n",
2717       "// append checkboxes for displaying or hiding objects\n",
2718       "var shownObjectsList = document.getElementById('shownObjectsList_1');\n",
2719       "for (var i=0; i<scene.children.length; i++){\n",
2720       "    obj = scene.children[i];\n",
2721       "    var objNode = document.createElement('span');\n",
2722       "    objNode.innerHTML = obj.name + '<br>';\n",
2723       "    var checkbox = document.createElement('input');\n",
2724       "    checkbox.type = 'checkbox';\n",
2725       "    checkbox.checked = true;\n",
2726       "    checkbox.name = String(i);\n",
2727       "    checkbox.onchange = toggleObjectVisibility;\n",
2728       "    shownObjectsList.appendChild(checkbox);\n",
2729       "    shownObjectsList.appendChild(objNode);\n",
2730       "}\n",
2731       "\n",
2732       "// ---------------------- SVG ------------------------------------------------------\n",
2733       "// ---------------------------------------------------------------------------------\n",
2734       "\n",
2735       "function takeSvgScreenshot() {\n",
2736       "    if (objectTypeVisible[\"pointlabels\"]) {\n",
2737       "        setVisibility(false,\"pointlabels\");\n",
2738       "    }\n",
2739       "    if (objectTypeVisible[\"edgelabels\"]) {\n",
2740       "        setVisibility(false,\"edgelabels\");\n",
2741       "    }\n",
2742       "    svgRenderer.render(scene,camera);\n",
2743       "    svgElement = XMLS.serializeToString(svgRenderer.domElement);\n",
2744       "    \n",
2745       "    if (objectTypeVisible[\"pointlabels\"]) {\n",
2746       "        setVisibility(true,\"pointlabels\");\n",
2747       "    }\n",
2748       "    if (objectTypeVisible[\"edgelabels\"]) {\n",
2749       "        setVisibility(true,\"edgelabels\");\n",
2750       "    }\n",
2751       "\n",
2752       "    if (document.getElementById('tab_1').checked){\n",
2753       "        //show in new tab\n",
2754       "        var myWindow = window.open(\"\",\"\");\n",
2755       "        myWindow.document.body.innerHTML = svgElement;\n",
2756       "    } else{\n",
2757       "        // download svg file \n",
2758       "        download(\"screenshot.svg\", svgElement);\n",
2759       "    }\n",
2760       "}\n",
2761       "\n",
2762       "function download(filename, text) {\n",
2763       "    var element = document.createElement('a');\n",
2764       "    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));\n",
2765       "    element.setAttribute('download', filename);\n",
2766       "\n",
2767       "    element.style.display = 'none';\n",
2768       "    document.body.appendChild(element);\n",
2769       "\n",
2770       "    element.click();\n",
2771       "\n",
2772       "    document.body.removeChild(element);\n",
2773       "}\n",
2774       "\n",
2775       "\n",
2776       "document.getElementById('transparencyRange_1').oninput = changeTransparency;\n",
2777       "document.getElementById('changeRotationX_1').onchange = changeRotationX;\n",
2778       "document.getElementById('changeRotationY_1').onchange = changeRotationY;\n",
2779       "document.getElementById('changeRotationZ_1').onchange = changeRotationZ;\n",
2780       "document.getElementById('resetButton_1').onclick = resetScene;\n",
2781       "document.getElementById('rotationSpeedRange_1').oninput = changeRotationSpeedFactor;\n",
2782       "document.getElementById('takeScreenshot_1').onclick = takeSvgScreenshot;\n",
2783       "document.getElementById('showSettingsButton_1').onclick = showSettings;\n",
2784       "document.getElementById('hideSettingsButton_1').onclick = hideSettings;\n",
2785       "\n",
2786       "\n",
2787       "// ------------------ SHORTCUTS --------------------------------------------\n",
2788       "// -------------------------------------------------------------------------\n",
2789       "\n",
2790       "/**\n",
2791       " * http://www.openjs.com/scripts/events/keyboard_shortcuts/\n",
2792       " * Version : 2.01.B\n",
2793       " * By Binny V A\n",
2794       " * License : BSD\n",
2795       " */\n",
2796       "shortcut = {\n",
2797       "\t'all_shortcuts':{},//All the shortcuts are stored in this array\n",
2798       "\t'add': function(shortcut_combination,callback,opt) {\n",
2799       "\t\t//Provide a set of default options\n",
2800       "\t\tvar default_options = {\n",
2801       "\t\t\t'type':'keydown',\n",
2802       "\t\t\t'propagate':false,\n",
2803       "\t\t\t'disable_in_input':false,\n",
2804       "\t\t\t'target':document,\n",
2805       "\t\t\t'keycode':false\n",
2806       "\t\t}\n",
2807       "\t\tif(!opt) opt = default_options;\n",
2808       "\t\telse {\n",
2809       "\t\t\tfor(var dfo in default_options) {\n",
2810       "\t\t\t\tif(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];\n",
2811       "\t\t\t}\n",
2812       "\t\t}\n",
2813       "\n",
2814       "\t\tvar ele = opt.target;\n",
2815       "\t\tif(typeof opt.target == 'string') ele = document.getElementById(opt.target);\n",
2816       "\t\tvar ths = this;\n",
2817       "\t\tshortcut_combination = shortcut_combination.toLowerCase();\n",
2818       "\n",
2819       "\t\t//The function to be called at keypress\n",
2820       "\t\tvar func = function(e) {\n",
2821       "\t\t\te = e || window.event;\n",
2822       "\t\t\t\n",
2823       "\t\t\tif(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields\n",
2824       "\t\t\t\tvar element;\n",
2825       "\t\t\t\tif(e.target) element=e.target;\n",
2826       "\t\t\t\telse if(e.srcElement) element=e.srcElement;\n",
2827       "\t\t\t\tif(element.nodeType==3) element=element.parentNode;\n",
2828       "\n",
2829       "\t\t\t\tif(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;\n",
2830       "\t\t\t}\n",
2831       "\t\n",
2832       "\t\t\t//Find Which key is pressed\n",
2833       "\t\t\tif (e.keyCode) code = e.keyCode;\n",
2834       "\t\t\telse if (e.which) code = e.which;\n",
2835       "\t\t\tvar character = String.fromCharCode(code).toLowerCase();\n",
2836       "\t\t\t\n",
2837       "\t\t\tif(code == 188) character=\",\"; //If the user presses , when the type is onkeydown\n",
2838       "\t\t\tif(code == 190) character=\".\"; //If the user presses , when the type is onkeydown\n",
2839       "\n",
2840       "\t\t\tvar keys = shortcut_combination.split(\"+\");\n",
2841       "\t\t\t//Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked\n",
2842       "\t\t\tvar kp = 0;\n",
2843       "\t\t\t\n",
2844       "\t\t\t//Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken\n",
2845       "\t\t\tvar shift_nums = {\n",
2846       "\t\t\t\t\"`\":\"~\",\n",
2847       "\t\t\t\t\"1\":\"!\",\n",
2848       "\t\t\t\t\"2\":\"@\",\n",
2849       "\t\t\t\t\"3\":\"#\",\n",
2850       "\t\t\t\t\"4\":\"$\",\n",
2851       "\t\t\t\t\"5\":\"%\",\n",
2852       "\t\t\t\t\"6\":\"^\",\n",
2853       "\t\t\t\t\"7\":\"&\",\n",
2854       "\t\t\t\t\"8\":\"*\",\n",
2855       "\t\t\t\t\"9\":\"(\",\n",
2856       "\t\t\t\t\"0\":\")\",\n",
2857       "\t\t\t\t\"-\":\"_\",\n",
2858       "\t\t\t\t\"=\":\"+\",\n",
2859       "\t\t\t\t\";\":\":\",\n",
2860       "\t\t\t\t\"'\":\"\\\"\",\n",
2861       "\t\t\t\t\",\":\"<\",\n",
2862       "\t\t\t\t\".\":\">\",\n",
2863       "\t\t\t\t\"/\":\"?\",\n",
2864       "\t\t\t\t\"\\\\\":\"|\"\n",
2865       "\t\t\t}\n",
2866       "\t\t\t//Special Keys - and their codes\n",
2867       "\t\t\tvar special_keys = {\n",
2868       "\t\t\t\t'esc':27,\n",
2869       "\t\t\t\t'escape':27,\n",
2870       "\t\t\t\t'tab':9,\n",
2871       "\t\t\t\t'space':32,\n",
2872       "\t\t\t\t'return':13,\n",
2873       "\t\t\t\t'enter':13,\n",
2874       "\t\t\t\t'backspace':8,\n",
2875       "\t\n",
2876       "\t\t\t\t'scrolllock':145,\n",
2877       "\t\t\t\t'scroll_lock':145,\n",
2878       "\t\t\t\t'scroll':145,\n",
2879       "\t\t\t\t'capslock':20,\n",
2880       "\t\t\t\t'caps_lock':20,\n",
2881       "\t\t\t\t'caps':20,\n",
2882       "\t\t\t\t'numlock':144,\n",
2883       "\t\t\t\t'num_lock':144,\n",
2884       "\t\t\t\t'num':144,\n",
2885       "\t\t\t\t\n",
2886       "\t\t\t\t'pause':19,\n",
2887       "\t\t\t\t'break':19,\n",
2888       "\t\t\t\t\n",
2889       "\t\t\t\t'insert':45,\n",
2890       "\t\t\t\t'home':36,\n",
2891       "\t\t\t\t'delete':46,\n",
2892       "\t\t\t\t'end':35,\n",
2893       "\t\t\t\t\n",
2894       "\t\t\t\t'pageup':33,\n",
2895       "\t\t\t\t'page_up':33,\n",
2896       "\t\t\t\t'pu':33,\n",
2897       "\t\n",
2898       "\t\t\t\t'pagedown':34,\n",
2899       "\t\t\t\t'page_down':34,\n",
2900       "\t\t\t\t'pd':34,\n",
2901       "\t\n",
2902       "\t\t\t\t'left':37,\n",
2903       "\t\t\t\t'up':38,\n",
2904       "\t\t\t\t'right':39,\n",
2905       "\t\t\t\t'down':40,\n",
2906       "\t\n",
2907       "\t\t\t\t'f1':112,\n",
2908       "\t\t\t\t'f2':113,\n",
2909       "\t\t\t\t'f3':114,\n",
2910       "\t\t\t\t'f4':115,\n",
2911       "\t\t\t\t'f5':116,\n",
2912       "\t\t\t\t'f6':117,\n",
2913       "\t\t\t\t'f7':118,\n",
2914       "\t\t\t\t'f8':119,\n",
2915       "\t\t\t\t'f9':120,\n",
2916       "\t\t\t\t'f10':121,\n",
2917       "\t\t\t\t'f11':122,\n",
2918       "\t\t\t\t'f12':123\n",
2919       "\t\t\t}\n",
2920       "\t\n",
2921       "\t\t\tvar modifiers = { \n",
2922       "\t\t\t\tshift: { wanted:false, pressed:false},\n",
2923       "\t\t\t\tctrl : { wanted:false, pressed:false},\n",
2924       "\t\t\t\talt  : { wanted:false, pressed:false},\n",
2925       "\t\t\t\tmeta : { wanted:false, pressed:false}\t//Meta is Mac specific\n",
2926       "\t\t\t};\n",
2927       "                        \n",
2928       "\t\t\tif(e.ctrlKey)\tmodifiers.ctrl.pressed = true;\n",
2929       "\t\t\tif(e.shiftKey)\tmodifiers.shift.pressed = true;\n",
2930       "\t\t\tif(e.altKey)\tmodifiers.alt.pressed = true;\n",
2931       "\t\t\tif(e.metaKey)   modifiers.meta.pressed = true;\n",
2932       "                        \n",
2933       "\t\t\tfor(var i=0; k=keys[i],i<keys.length; i++) {\n",
2934       "\t\t\t\t//Modifiers\n",
2935       "\t\t\t\tif(k == 'ctrl' || k == 'control') {\n",
2936       "\t\t\t\t\tkp++;\n",
2937       "\t\t\t\t\tmodifiers.ctrl.wanted = true;\n",
2938       "\n",
2939       "\t\t\t\t} else if(k == 'shift') {\n",
2940       "\t\t\t\t\tkp++;\n",
2941       "\t\t\t\t\tmodifiers.shift.wanted = true;\n",
2942       "\n",
2943       "\t\t\t\t} else if(k == 'alt') {\n",
2944       "\t\t\t\t\tkp++;\n",
2945       "\t\t\t\t\tmodifiers.alt.wanted = true;\n",
2946       "\t\t\t\t} else if(k == 'meta') {\n",
2947       "\t\t\t\t\tkp++;\n",
2948       "\t\t\t\t\tmodifiers.meta.wanted = true;\n",
2949       "\t\t\t\t} else if(k.length > 1) { //If it is a special key\n",
2950       "\t\t\t\t\tif(special_keys[k] == code) kp++;\n",
2951       "\t\t\t\t\t\n",
2952       "\t\t\t\t} else if(opt['keycode']) {\n",
2953       "\t\t\t\t\tif(opt['keycode'] == code) kp++;\n",
2954       "\n",
2955       "\t\t\t\t} else { //The special keys did not match\n",
2956       "\t\t\t\t\tif(character == k) kp++;\n",
2957       "\t\t\t\t\telse {\n",
2958       "\t\t\t\t\t\tif(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase\n",
2959       "\t\t\t\t\t\t\tcharacter = shift_nums[character]; \n",
2960       "\t\t\t\t\t\t\tif(character == k) kp++;\n",
2961       "\t\t\t\t\t\t}\n",
2962       "\t\t\t\t\t}\n",
2963       "\t\t\t\t}\n",
2964       "\t\t\t}\n",
2965       "\t\t\t\n",
2966       "\t\t\tif(kp == keys.length && \n",
2967       "\t\t\t\t\t\tmodifiers.ctrl.pressed == modifiers.ctrl.wanted &&\n",
2968       "\t\t\t\t\t\tmodifiers.shift.pressed == modifiers.shift.wanted &&\n",
2969       "\t\t\t\t\t\tmodifiers.alt.pressed == modifiers.alt.wanted &&\n",
2970       "\t\t\t\t\t\tmodifiers.meta.pressed == modifiers.meta.wanted) {\n",
2971       "\t\t\t\tcallback(e);\n",
2972       "\t\n",
2973       "\t\t\t\tif(!opt['propagate']) { //Stop the event\n",
2974       "\t\t\t\t\t//e.cancelBubble is supported by IE - this will kill the bubbling process.\n",
2975       "\t\t\t\t\te.cancelBubble = true;\n",
2976       "\t\t\t\t\te.returnValue = false;\n",
2977       "\t\n",
2978       "\t\t\t\t\t//e.stopPropagation works in Firefox.\n",
2979       "\t\t\t\t\tif (e.stopPropagation) {\n",
2980       "\t\t\t\t\t\te.stopPropagation();\n",
2981       "\t\t\t\t\t\te.preventDefault();\n",
2982       "\t\t\t\t\t}\n",
2983       "\t\t\t\t\treturn false;\n",
2984       "\t\t\t\t}\n",
2985       "\t\t\t}\n",
2986       "\t\t}\n",
2987       "\t\tthis.all_shortcuts[shortcut_combination] = {\n",
2988       "\t\t\t'callback':func, \n",
2989       "\t\t\t'target':ele, \n",
2990       "\t\t\t'event': opt['type']\n",
2991       "\t\t};\n",
2992       "\t\t//Attach the function with the event\n",
2993       "\t\tif(ele.addEventListener) ele.addEventListener(opt['type'], func, false);\n",
2994       "\t\telse if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);\n",
2995       "\t\telse ele['on'+opt['type']] = func;\n",
2996       "\t},\n",
2997       "\n",
2998       "\t//Remove the shortcut - just specify the shortcut and I will remove the binding\n",
2999       "\t'remove':function(shortcut_combination) {\n",
3000       "\t\tshortcut_combination = shortcut_combination.toLowerCase();\n",
3001       "\t\tvar binding = this.all_shortcuts[shortcut_combination];\n",
3002       "\t\tdelete(this.all_shortcuts[shortcut_combination])\n",
3003       "\t\tif(!binding) return;\n",
3004       "\t\tvar type = binding['event'];\n",
3005       "\t\tvar ele = binding['target'];\n",
3006       "\t\tvar callback = binding['callback'];\n",
3007       "\n",
3008       "\t\tif(ele.detachEvent) ele.detachEvent('on'+type, callback);\n",
3009       "\t\telse if(ele.removeEventListener) ele.removeEventListener(type, callback, false);\n",
3010       "\t\telse ele['on'+type] = false;\n",
3011       "\t}\n",
3012       "}\n",
3013       "\n",
3014       "shortcut.add(\"Alt+Left\",function() {\n",
3015       "\tvar event = new Event('click');\n",
3016       "\tif (settingsShown){\n",
3017       "\t\tdocument.getElementById('hideSettingsButton_1').dispatchEvent(event);\n",
3018       "\t} else {\n",
3019       "\t\tdocument.getElementById('showSettingsButton_1').dispatchEvent(event);\n",
3020       "\t}\n",
3021       "});\n",
3022       "\n",
3023       "\n",
3024       "// COMMON_CODE_BLOCK_END\n",
3025       "\n",
3026       "});});\n",
3027       "      </script>\n",
3028       "   </body>\n",
3029       "</html>"
3030      ]
3031     },
3032     "metadata": {},
3033     "output_type": "display_data"
3034    }
3035   ],
3036   "source": [
3037    "$scaled_rs->VISUAL->LATTICE_COLORED;"
3038   ]
3039  },
3040  {
3041   "cell_type": "markdown",
3042   "metadata": {},
3043   "source": [
3044    "Now will construct the integer hull of `$scaled_rs` and visualise it:"
3045   ]
3046  },
3047  {
3048   "cell_type": "code",
3049   "execution_count": 14,
3050   "metadata": {},
3051   "outputs": [
3052    {
3053     "data": {
3054      "text/html": [
3055       "<!--\n",
3056       "polymake for knusper\n",
3057       "Thu Aug 27 11:38:20 2020\n",
3058       "integer_hull\n",
3059       "-->\n",
3060       "\n",
3061       "\n",
3062       "<html>\n",
3063       "   <head>\n",
3064       "      <meta charset=utf-8>\n",
3065       "      <title>integer_hull</title>\n",
3066       "      <style>\n",
3067       "/*\n",
3068       "// COMMON_CODE_BLOCK_BEGIN\n",
3069       "*/\n",
3070       "         html {overflow: scroll;}\n",
3071       "         strong{font-size: 18px;}\n",
3072       "         canvas { z-index: 8; }\n",
3073       "         input[type='radio'] {margin-left:0;}\n",
3074       "         input[type='checkbox'] {margin-right:7px; margin-left: 0px; padding-left:0px;}\n",
3075       "         .group{padding-bottom: 15px;}\n",
3076       "         .settings * {z-index: 11; }\n",
3077       "         .settings{z-index: 10; font-family: Arial, Helvetica, sans-serif; margin-left: 30px; visibility: hidden; width: 14em; height: 96%; border: solid 1px silver; padding: 2px; overflow-y: scroll; box-sizing: border-box; background-color: white; position: absolute;}\n",
3078       "         .indented{margin-left: 20px; margin-top: 10px; padding-bottom: 0px;} \n",
3079       "         .shownObjectsList{overflow: auto; max-width: 150px; max-height: 150px;}\n",
3080       "         .showSettingsButton{visibility: visible; z-index: 12; position: absolute }\n",
3081       "         .hideSettingsButton{visibility: hidden; z-index: 12; position: absolute; opacity: 0.5}\n",
3082       "         button{margin-left: 0; margin-top: 10px}\n",
3083       "         img{cursor: pointer;}\n",
3084       "         .suboption{padding-top: 15px;}\n",
3085       "         #model20732307065 { width: 100%; height: 100%; }\n",
3086       "         .threejs_container { width: 100%; height: 75vh;}\n",
3087       "         .settings{max-height: 74vh} \n",
3088       "         input[type=range] {\n",
3089       "           -webkit-appearance: none;\n",
3090       "           padding:0; \n",
3091       "           width:90%; \n",
3092       "           margin-left: auto;\n",
3093       "           margin-right: auto;\n",
3094       "           margin-top: 15px;\n",
3095       "           margin-bottom: 15px;\n",
3096       "           display: block;\t\n",
3097       "         }\n",
3098       "         input[type=range]:focus {\n",
3099       "           outline: none;\n",
3100       "         }\n",
3101       "         input[type=range]::-webkit-slider-runnable-track {\n",
3102       "           height: 4px;\n",
3103       "           cursor: pointer;\n",
3104       "           animate: 0.2s;\n",
3105       "           box-shadow: 0px 0px 0px #000000;\n",
3106       "           background: #E3E3E3;\n",
3107       "           border-radius: 0px;\n",
3108       "           border: 0px solid #000000;\n",
3109       "         }\n",
3110       "         input[type=range]::-webkit-slider-thumb {\n",
3111       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
3112       "           border: 1px solid #ABABAB;\n",
3113       "           height: 13px;\n",
3114       "           width: 25px;\n",
3115       "           border-radius: 20px;\n",
3116       "           background: #E0E0E0;\n",
3117       "           cursor: pointer;\n",
3118       "           -webkit-appearance: none;\n",
3119       "           margin-top: -5px;\n",
3120       "         }\n",
3121       "         input[type=range]:focus::-webkit-slider-runnable-track {\n",
3122       "           background: #E3E3E3;\n",
3123       "         }\n",
3124       "         input[type=range]::-moz-range-track {\n",
3125       "           height: 4px;\n",
3126       "           cursor: pointer;\n",
3127       "           animate: 0.2s;\n",
3128       "           box-shadow: 0px 0px 0px #000000;\n",
3129       "           background: #E3E3E3;\n",
3130       "           border-radius: 0px;\n",
3131       "           border: 0px solid #000000;\n",
3132       "         }\n",
3133       "         input[type=range]::-moz-range-thumb {\n",
3134       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
3135       "           border: 1px solid #ABABAB;\n",
3136       "           height: 13px;\n",
3137       "           width: 25px;\n",
3138       "           border-radius: 20px;\n",
3139       "           background: #E0E0E0;\n",
3140       "           cursor: pointer;\n",
3141       "         }\n",
3142       "         input[type=range]::-ms-track {\n",
3143       "           height: 4px;\n",
3144       "           cursor: pointer;\n",
3145       "           animate: 0.2s;\n",
3146       "           background: transparent;\n",
3147       "           border-color: transparent;\n",
3148       "           color: transparent;\n",
3149       "         }\n",
3150       "         input[type=range]::-ms-fill-lower {\n",
3151       "           background: #E3E3E3;\n",
3152       "           border: 0px solid #000000;\n",
3153       "           border-radius: 0px;\n",
3154       "           box-shadow: 0px 0px 0px #000000;\n",
3155       "         }\n",
3156       "         input[type=range]::-ms-fill-upper {\n",
3157       "           background: #E3E3E3;\n",
3158       "           border: 0px solid #000000;\n",
3159       "           border-radius: 0px;\n",
3160       "           box-shadow: 0px 0px 0px #000000;\n",
3161       "         }\n",
3162       "         input[type=range]::-ms-thumb {\n",
3163       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
3164       "           border: 1px solid #ABABAB;\n",
3165       "           height: 13px;\n",
3166       "           width: 25px;\n",
3167       "           border-radius: 20px;\n",
3168       "           background: #E0E0E0;\n",
3169       "           cursor: pointer;\n",
3170       "         }\n",
3171       "         input[type=range]:focus::-ms-fill-lower {\n",
3172       "           background: #E3E3E3;\n",
3173       "         }\n",
3174       "         input[type=range]:focus::-ms-fill-upper {\n",
3175       "           background: #E3E3E3;\n",
3176       "         }\n",
3177       "/*\n",
3178       "// COMMON_CODE_BLOCK_END\n",
3179       "*/\n",
3180       "\t\t</style>\n",
3181       "   </head>\n",
3182       "<body>\n",
3183       "   <div class='threejs_container'>\n",
3184       "\t\t<div id='settings_2' class='settings'>\n",
3185       "\t\t\t<div class=group id='explode_2'>\n",
3186       "\t\t\t\t<strong>Explode</strong>\n",
3187       "\t\t\t\t<input id='explodeRange_2' type='range' min=0 max=6 step=0.01 value=0>\n",
3188       "\t\t\t\t<div class=indented><input id='explodeCheckbox_2' type='checkbox'>Automatic explosion</div>\n",
3189       "\t\t\t\t<div class=suboption>Exploding speed</div>\n",
3190       "\t\t\t\t<input id='explodingSpeedRange_2' type='range' min=0 max=0.5 step=0.001 value=0.05>\n",
3191       "\t\t\t</div>\n",
3192       "\t\n",
3193       "\t\t\t<div class=group id='transparency_2' class='transparency'>\n",
3194       "\t\t\t\t<strong>Transparency</strong>\n",
3195       "\t\t\t\t<input id='transparencyRange_2' type='range' min=0 max=1 step=0.01 value=0>\n",
3196       "\t\t\t</div>\n",
3197       "\t\t\t\n",
3198       "\t\t\t<div class=group id='rotation_2'>\n",
3199       "\t\t\t\t<strong>Rotation</strong>\n",
3200       "\t\t\t\t<div class=indented>\n",
3201       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationX_2'> x-axis</div>\n",
3202       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationY_2'> y-axis</div>\n",
3203       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationZ_2'> z-axis</div>\n",
3204       "\t\t\t\t\t<button id='resetButton_2'>Reset</button>\n",
3205       "\t\t\t\t</div>\n",
3206       "\n",
3207       "\t\t\t\t<div class=suboption>Rotation speed</div>\n",
3208       "\t\t\t\t<input id='rotationSpeedRange_2' type='range' min=0 max=5 step=0.01 value=2>\n",
3209       "\t\t\t</div>\n",
3210       "\n",
3211       "\n",
3212       "\t\t\t<div class=group id='display_2'>\n",
3213       "\t\t\t\t<strong>Display</strong>\n",
3214       "\t\t\t\t<div class=indented>\n",
3215       "\t\t\t\t\t<div id='shownObjectTypesList_2' class='shownObjectsList'></div>\n",
3216       "\t\t\t\t</div>\n",
3217       "\t\t\t\t<div class=suboption>Objects</div>\n",
3218       "\t\t\t\t<div class=indented>\n",
3219       "\t\t\t\t   <div id='shownObjectsList_2' class='shownObjectsList'></div>\n",
3220       "\t\t\t\t</div>\n",
3221       "\t\t\t</div>\n",
3222       "         \n",
3223       "         <div class=group id='camera_2'>\n",
3224       "            <strong>Camera</strong>\n",
3225       "            <div class=indented>\n",
3226       "               <form>\n",
3227       "                  <select id=\"cameraType_2\">\n",
3228       "                     <option value='perspective' selected> Perspective<br></option>\n",
3229       "                     <option value='orthographic' > Orthographic<br></option>\n",
3230       "                  </select>\n",
3231       "               </form>\n",
3232       "            </div>\n",
3233       "         </div>\n",
3234       "\n",
3235       "\t\t\t<div class=group id='svg_2'>\n",
3236       "\t\t\t\t<strong>SVG</strong>\n",
3237       "\t\t\t\t<div class=indented>\n",
3238       "\t\t\t\t\t<form>\n",
3239       "\t\t\t\t\t\t<input type=\"radio\" name='screenshotMode' value='download' id='download_2' checked> Download<br>\n",
3240       "\t\t\t\t\t\t<input type=\"radio\" name='screenshotMode' value='tab' id='tab_2' > New tab<br>\n",
3241       "\t\t\t\t\t</form>\n",
3242       "\t\t\t\t\t<button id='takeScreenshot_2'>Screenshot</button>\n",
3243       "\t\t\t\t</div>\n",
3244       "\t\t\t</div>\n",
3245       "\n",
3246       "\t\t</div>\t<!-- end of settings -->\n",
3247       "\t\t<img id='hideSettingsButton_2' class='hideSettingsButton' src='/kernelspecs/polymake/close.svg' width=20px\">\n",
3248       "\t\t<img id='showSettingsButton_2' class='showSettingsButton' src='/kernelspecs/polymake/menu.svg' width=20px\">\n",
3249       "<div id=\"model20732307065\"></div>\n",
3250       "</div>\n",
3251       "   <script>\n",
3252       "    requirejs.config({\n",
3253       "      paths: {\n",
3254       "        three: '/kernelspecs/polymake/three',\n",
3255       "        TrackballControls: '/kernelspecs/polymake/TrackballControls',\n",
3256       "        OrbitControls: '/kernelspecs/polymake/OrbitControls',\n",
3257       "        Projector: '/kernelspecs/polymake/Projector',\n",
3258       "        SVGRenderer: '/kernelspecs/polymake/SVGRenderer',\n",
3259       "        WEBGL: '/kernelspecs/polymake/WebGL',\n",
3260       "      },\n",
3261       "      shim: {\n",
3262       "        'three': { exports: 'THREE'},\n",
3263       "        'SVGRenderer': { deps: [ 'three' ], exports: 'THREE.SVGRenderer' },\n",
3264       "        'WEBGL': { deps: [ 'three' ], exports: 'THREE.WEBGL' },\n",
3265       "        'Projector': { deps: [ 'three' ], exports: 'THREE.Projector' },\n",
3266       "        'TrackballControls': { deps: [ 'three' ], exports: 'THREE.TrackballControls' },\n",
3267       "        'OrbitControls': { deps: [ 'three' ], exports: 'THREE.OrbitControls' },\n",
3268       "      }\n",
3269       "    });\n",
3270       "    \n",
3271       "    require(['three'],function(THREE){\n",
3272       "        window.THREE = THREE;\n",
3273       "      require(['TrackballControls', 'OrbitControls', 'Projector', 'SVGRenderer', 'WEBGL'],\n",
3274       "               function(TrackballControls, OrbitControls, Projector, SVGRenderer, WEBGL) {\n",
3275       "    THREE.TrackballControls = TrackballControls;\n",
3276       "    THREE.OrbitControls = OrbitControls;\n",
3277       "    THREE.Projector = Projector;\n",
3278       "    THREE.SVGRenderer = SVGRenderer;\n",
3279       "    THREE.WEBGL = WEBGL;\n",
3280       "\n",
3281       "// COMMON_CODE_BLOCK_BEGIN\n",
3282       "\n",
3283       "const intervalLength = 25; // for automatic animations\n",
3284       "const explodableModel = true; \n",
3285       "const modelContains = { points: false, pointlabels: false, lines: false, edgelabels: false, faces: false, arrowheads: false };\n",
3286       "const foldables = [];\n",
3287       "\n",
3288       "var three = document.getElementById(\"model20732307065\");\n",
3289       "var scene = new THREE.Scene();\n",
3290       "var renderer = new THREE.WebGLRenderer( { antialias: true } );\n",
3291       "var svgRenderer = new THREE.SVGRenderer( { antialias: true } );\n",
3292       "renderer.setPixelRatio( window.devicePixelRatio );\n",
3293       "renderer.setClearColor(0xFFFFFF, 1);\n",
3294       "svgRenderer.setClearColor(0xFFFFFF, 1);\n",
3295       "three.appendChild(renderer.domElement);\n",
3296       "\n",
3297       "var frustumSize = 4;\n",
3298       "var cameras = [new THREE.PerspectiveCamera(75, 1, 0.1, 1000), new THREE.OrthographicCamera()];\n",
3299       "cameras.forEach(function(cam) {\n",
3300       "    cam.position.set(0, 0, 5);\n",
3301       "    cam.lookAt(0, 0, 0);  \n",
3302       "    cam.up.set(0, 1, 0);         \n",
3303       "});\n",
3304       "var controls = [new THREE.TrackballControls(cameras[0], three), new THREE.OrbitControls(cameras[1], three)];\n",
3305       "var camera, control;\n",
3306       "\n",
3307       "controls[0].zoomSpeed = 0.2;\n",
3308       "controls[0].rotateSpeed = 4;\n",
3309       "\n",
3310       "\n",
3311       "// class to allow move points together with labels and spheres\n",
3312       "var PMPoint = function (x,y,z) {\n",
3313       "   this.vector = new THREE.Vector3(x,y,z);\n",
3314       "   this.sprite = null;\n",
3315       "   this.sphere = null;\n",
3316       "}\n",
3317       "PMPoint.prototype.addLabel = function(labelsprite) {\n",
3318       "   this.sprite = labelsprite;\n",
3319       "   this.sprite.position.copy(this.vector);\n",
3320       "}\n",
3321       "PMPoint.prototype.addSphere = function(spheremesh) {\n",
3322       "   this.sphere = spheremesh;\n",
3323       "   this.sphere.position.copy(this.vector);\n",
3324       "}\n",
3325       "PMPoint.prototype.set = function(x,y,z) {\n",
3326       "   this.vector.set(x,y,z);\n",
3327       "   if (this.sprite) {\n",
3328       "      this.sprite.position.copy(this.vector);\n",
3329       "   }\n",
3330       "   if (this.sphere) {\n",
3331       "      this.sphere.position.copy(this.vector);\n",
3332       "   }\n",
3333       "}\n",
3334       "PMPoint.prototype.radius = function() {\n",
3335       "   if (this.sphere) {\n",
3336       "      return this.sphere.geometry.parameters.radius;\n",
3337       "   } else {\n",
3338       "      return 0;\n",
3339       "   }\n",
3340       "};\n",
3341       "// select the target node\n",
3342       "var target = document.querySelector('#model20732307065');\n",
3343       "\n",
3344       "// create an observer instance\n",
3345       "var observer = new MutationObserver(function(mutations) {\n",
3346       "   mutations.forEach(function(mutation) {\n",
3347       "      if (mutation.removedNodes && mutation.removedNodes.length > 0) {\n",
3348       "         cancelAnimationFrame(renderId);\n",
3349       "         observer.disconnect();\n",
3350       "         console.log(\"cancelled frame \"+renderId);\n",
3351       "      }\n",
3352       "   });\n",
3353       "});\n",
3354       "\n",
3355       "// configuration of the observer:\n",
3356       "var config = { childList: true, characterData: true }\n",
3357       "\n",
3358       "// pass in the target node, as well as the observer options\n",
3359       "while (target) {\n",
3360       "   if (target.className==\"output\") {\n",
3361       "      observer.observe(target, config);\n",
3362       "      break;\n",
3363       "   }\n",
3364       "   target = target.parentNode;\n",
3365       "}\n",
3366       "\n",
3367       "// COMMON_CODE_BLOCK_END\n",
3368       "\n",
3369       "var obj0 = new THREE.Object3D();\n",
3370       "obj0.name = \"integer_hull\";\n",
3371       "obj0.userData.explodable = 1;\n",
3372       "obj0.userData.points = [];\n",
3373       "obj0.userData.points.push(new PMPoint(-1, -1, -1));\n",
3374       "obj0.userData.points.push(new PMPoint(-1, -1, 0));\n",
3375       "obj0.userData.points.push(new PMPoint(-1, 0, -1));\n",
3376       "obj0.userData.points.push(new PMPoint(-1, 0, 1));\n",
3377       "obj0.userData.points.push(new PMPoint(-1, 1, 0));\n",
3378       "obj0.userData.points.push(new PMPoint(0, -1, 0));\n",
3379       "obj0.userData.points.push(new PMPoint(0, -1, 1));\n",
3380       "obj0.userData.points.push(new PMPoint(0, 1, -1));\n",
3381       "obj0.userData.points.push(new PMPoint(0, 1, 1));\n",
3382       "obj0.userData.points.push(new PMPoint(1, 0, -1));\n",
3383       "obj0.userData.points.push(new PMPoint(1, 0, 1));\n",
3384       "obj0.userData.points.push(new PMPoint(1, 1, 0));\n",
3385       "\n",
3386       "obj0.userData.edgeindices = [0, 1, 0, 2, 1, 3, 2, 4, 3, 4, 0, 5, 1, 6, 3, 6, 5, 6, 2, 7, 4, 7, 3, 8, 4, 8, 0, 9, 5, 9, 7, 9, 6, 10, 8, 10, 9, 10, 7, 11, 8, 11, 9, 11, 10, 11];\n",
3387       "   <!-- Edge style -->\n",
3388       "obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
3389       "obj0.userData.facets = [[10, 6, 5, 9], [3, 6, 10, 8], [4, 3, 8], [5, 6, 1, 0], [1, 6, 3], [0, 1, 3, 4, 2], [2, 4, 7], [9, 5, 0], [9, 0, 2, 7], [11, 9, 7], [10, 11, 8], [10, 9, 11], [11, 7, 4, 8]];\n",
3390       "init_object(obj0);\n",
3391       "scene.add(obj0);\n",
3392       "\n",
3393       "var obj1 = new THREE.Object3D();\n",
3394       "obj1.name = \"Lattice points and vertices of integer_hull\";\n",
3395       "obj1.userData.explodable = 1;\n",
3396       "obj1.userData.points = [];\n",
3397       "obj1.userData.points.push(new PMPoint(0, 0, 0));\n",
3398       "obj1.userData.points.push(new PMPoint(-1, -1, -1));\n",
3399       "obj1.userData.points.push(new PMPoint(-1, -1, 0));\n",
3400       "obj1.userData.points.push(new PMPoint(-1, 0, -1));\n",
3401       "obj1.userData.points.push(new PMPoint(-1, 0, 0));\n",
3402       "obj1.userData.points.push(new PMPoint(-1, 0, 1));\n",
3403       "obj1.userData.points.push(new PMPoint(-1, 1, 0));\n",
3404       "obj1.userData.points.push(new PMPoint(0, -1, 0));\n",
3405       "obj1.userData.points.push(new PMPoint(0, -1, 1));\n",
3406       "obj1.userData.points.push(new PMPoint(0, 0, -1));\n",
3407       "obj1.userData.points.push(new PMPoint(0, 0, 1));\n",
3408       "obj1.userData.points.push(new PMPoint(0, 1, -1));\n",
3409       "obj1.userData.points.push(new PMPoint(0, 1, 0));\n",
3410       "obj1.userData.points.push(new PMPoint(0, 1, 1));\n",
3411       "obj1.userData.points.push(new PMPoint(1, 0, -1));\n",
3412       "obj1.userData.points.push(new PMPoint(1, 0, 0));\n",
3413       "obj1.userData.points.push(new PMPoint(1, 0, 1));\n",
3414       "obj1.userData.points.push(new PMPoint(1, 1, 0));\n",
3415       "\n",
3416       "obj1.userData.pointradii = 0.02;\n",
3417       "   <!-- Vertex style -->\n",
3418       "obj1.userData.pointmaterial = [new THREE.MeshBasicMaterial( { color: 0x1EFA1E, side: THREE.DoubleSide, transparent: false } ),\n",
3419       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } ),\n",
3420       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } ),\n",
3421       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } ),\n",
3422       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } ),\n",
3423       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } ),\n",
3424       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } ),\n",
3425       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } ),\n",
3426       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } ),\n",
3427       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } ),\n",
3428       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } ),\n",
3429       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } ),\n",
3430       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } ),\n",
3431       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } ),\n",
3432       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } ),\n",
3433       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } ),\n",
3434       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } ),\n",
3435       "new THREE.MeshBasicMaterial( { color: 0x469646, side: THREE.DoubleSide, transparent: false } )];\n",
3436       "init_object(obj1);\n",
3437       "scene.add(obj1);\n",
3438       "\n",
3439       "// COMMON_CODE_BLOCK_BEGIN\n",
3440       "function textSpriteMaterial(message, parameters) {\n",
3441       "    if ( parameters === undefined ) parameters = {};\n",
3442       "    var fontface = \"Helvetica\";\n",
3443       "    var fontsize = parameters.hasOwnProperty(\"fontsize\") ? parameters[\"fontsize\"] : 15;\n",
3444       "    fontsize = fontsize*10;\n",
3445       "    var lines = message.split('\\\\n');\n",
3446       "    var size = 512;\n",
3447       "    for(var i = 0; i<lines.length; i++){\n",
3448       "        var tmp = lines[i].length;\n",
3449       "        while(tmp*fontsize > size){\n",
3450       "           fontsize--;\n",
3451       "        }\n",
3452       "    }\n",
3453       "    \n",
3454       "    var canvas = document.createElement('canvas');\n",
3455       "    canvas.width = size;\n",
3456       "    canvas.height = size;\n",
3457       "    var context = canvas.getContext('2d');\n",
3458       "    context.fillStyle = \"rgba(255, 255, 255, 0)\";\n",
3459       "    context.fill();\n",
3460       "    context.font = fontsize + \"px \" + fontface;\n",
3461       "    \n",
3462       "    // text color\n",
3463       "    context.fillStyle = \"rgba(0, 0, 0, 1.0)\";\n",
3464       "     for(var i = 0; i<lines.length; i++){\n",
3465       "        context.fillText(lines[i], size/2, size/2+i*fontsize);\n",
3466       "     }\n",
3467       "    \n",
3468       "    // canvas contents will be used for a texture\n",
3469       "    var texture = new THREE.Texture(canvas);\n",
3470       "    texture.needsUpdate = true;\n",
3471       "    \n",
3472       "    var spriteMaterial = new THREE.SpriteMaterial({map: texture, depthTest: true, depthWrite: false, polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: 1 });\n",
3473       "    return spriteMaterial;\n",
3474       "}\n",
3475       "\n",
3476       "\n",
3477       "// ---------------------- INITIALIZING OBJECTS--------------------------------------\n",
3478       "// ---------------------------------------------------------------------------------\n",
3479       "\n",
3480       "function init_object(obj) {\n",
3481       "    if (obj.userData.hasOwnProperty(\"pointmaterial\")) {\n",
3482       "        init_points(obj);\n",
3483       "        modelContains.points = true;\n",
3484       "    }\n",
3485       "    if (obj.userData.hasOwnProperty(\"pointlabels\")) {\n",
3486       "        init_pointlabels(obj);\n",
3487       "        modelContains.pointlabels = true;\n",
3488       "    }\n",
3489       "    if (obj.userData.hasOwnProperty(\"edgematerial\")) {\n",
3490       "        init_lines(obj);\n",
3491       "        modelContains.lines = true;\n",
3492       "    }\n",
3493       "    if (obj.userData.hasOwnProperty(\"edgelabels\")) {\n",
3494       "        init_edgelabels(obj);\n",
3495       "        modelContains.edgelabels = true;\n",
3496       "    }\n",
3497       "    if (obj.userData.hasOwnProperty(\"arrowstyle\")) {\n",
3498       "        init_arrowheads(obj);\n",
3499       "        modelContains.arrowheads = true;\n",
3500       "    }\n",
3501       "    if (obj.userData.hasOwnProperty(\"facetmaterial\")) {\n",
3502       "        init_faces(obj);\n",
3503       "        modelContains.faces = true;\n",
3504       "    }\n",
3505       "}\n",
3506       "\n",
3507       "function init_points(obj) {\n",
3508       "    var pointgroup = new THREE.Group();\n",
3509       "    pointgroup.name = \"points\";\n",
3510       "    var points = obj.userData.points;\n",
3511       "    var radii = obj.userData.pointradii;\n",
3512       "    var materials = obj.userData.pointmaterial;\n",
3513       "    var geometry,material;\n",
3514       "    if (!Array.isArray(radii)) {\n",
3515       "        geometry = new THREE.SphereBufferGeometry(radii);  \n",
3516       "    }\n",
3517       "    if (!Array.isArray(materials)) {\n",
3518       "        material = materials;\n",
3519       "    }\n",
3520       "    for (var i=0; i<points.length; i++) {\n",
3521       "        var point = points[i];\n",
3522       "        if (Array.isArray(radii)) {\n",
3523       "            if (radii[i] == 0) {\n",
3524       "                continue;\n",
3525       "            }\n",
3526       "            geometry = new THREE.SphereBufferGeometry(radii[i]);  \n",
3527       "        } \n",
3528       "        if (Array.isArray(materials)) {\n",
3529       "            material = materials[i];     \n",
3530       "        } \n",
3531       "        var sphere = new THREE.Mesh(geometry, material);\n",
3532       "        point.addSphere(sphere);\n",
3533       "        pointgroup.add(sphere);\n",
3534       "    }\n",
3535       "    obj.add(pointgroup);\n",
3536       "}\n",
3537       "\n",
3538       "function init_pointlabels(obj) {\n",
3539       "    var points = obj.userData.points;\n",
3540       "    var labels = obj.userData.pointlabels;\n",
3541       "    var pointlabels = new THREE.Group();\n",
3542       "    pointlabels.name = \"pointlabels\";\n",
3543       "    if (Array.isArray(labels)) {\n",
3544       "        for (var i=0; i<points.length; i++) {\n",
3545       "            var point = points[i];\n",
3546       "            var spriteMaterial = textSpriteMaterial( labels[i] );\n",
3547       "\t        var sprite = new THREE.Sprite(spriteMaterial);\n",
3548       "            point.addLabel(sprite);\n",
3549       "            pointlabels.add(sprite);\n",
3550       "        }\n",
3551       "    } else {\n",
3552       "        var spriteMaterial = textSpriteMaterial( labels );\n",
3553       "        for (var i=0; i<points.length; i++) {\n",
3554       "            var point = points[i];\n",
3555       "\t        var sprite = new THREE.Sprite(spriteMaterial);\n",
3556       "            point.addLabel(sprite);\n",
3557       "            pointlabels.add(sprite);\n",
3558       "        }\n",
3559       "    }\n",
3560       "    obj.add(pointlabels);\n",
3561       "}\n",
3562       "\n",
3563       "function init_lines(obj) {\n",
3564       "    var edgeindices = obj.userData.edgeindices;\n",
3565       "    var points = obj.userData.points;\n",
3566       "    var materials = obj.userData.edgematerial;\n",
3567       "    var geometry = new THREE.BufferGeometry();\n",
3568       "    var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 );\n",
3569       "    var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 );\n",
3570       "    var geometry = new THREE.BufferGeometry();\n",
3571       "    geometry.setAttribute('position', bufattr);\n",
3572       "    if (Array.isArray(materials)) {     \n",
3573       "        for (var i=0; i<materials.length; i++) {\n",
3574       "            geometry.addGroup(2*i,2,i);\n",
3575       "        }\n",
3576       "    }\n",
3577       "    var lines = new THREE.LineSegments(geometry, materials);\n",
3578       "    lines.name = \"lines\";\n",
3579       "    obj.add(lines);\n",
3580       "    updateEdgesPosition(obj);\n",
3581       "}\n",
3582       "\n",
3583       "function init_edgelabels(obj) {\n",
3584       "    var points = obj.userData.points;\n",
3585       "    var edgeindices = obj.userData.edgeindices;\n",
3586       "    var labels = obj.userData.edgelabels;\n",
3587       "    var edgelabels = new THREE.Group();\n",
3588       "    edgelabels.name = \"edgelabels\";\n",
3589       "    if (Array.isArray(labels)) {\n",
3590       "        for (var i=0; i<edgeindices.length; i=i+2) {\n",
3591       "            var point = points[i];\n",
3592       "            var spriteMaterial = textSpriteMaterial( labels[i] );\n",
3593       "            var sprite = new THREE.Sprite(spriteMaterial);\n",
3594       "            sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5));\n",
3595       "            edgelabels.add(sprite);\n",
3596       "        }\n",
3597       "    } else {\n",
3598       "        var spriteMaterial = textSpriteMaterial( labels );\n",
3599       "        for (var i=0; i<points.length; i++) {\n",
3600       "            var point = points[i];\n",
3601       "            var sprite = new THREE.Sprite(spriteMaterial);\n",
3602       "            sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5));\n",
3603       "            pointlabels.add(sprite);\n",
3604       "        }\n",
3605       "    }\n",
3606       "    obj.add(edgelabels);\n",
3607       "}\n",
3608       "\n",
3609       "function init_arrowheads(obj) {\n",
3610       "    var arrowheads = new THREE.Group();\n",
3611       "    arrowheads.name = \"arrowheads\";\n",
3612       "    var arrowstyle = obj.userData.arrowstyle;\n",
3613       "    var edgeindices = obj.userData.edgeindices;\n",
3614       "    var edgematerials = obj.userData.edgematerial;\n",
3615       "    var points = obj.userData.points;\n",
3616       "    var material;\n",
3617       "    if (!Array.isArray(edgematerials)) {\n",
3618       "        material = new THREE.MeshBasicMaterial( {color: edgematerials.color} );\n",
3619       "    }\n",
3620       "\n",
3621       "    for (var i=0; i<edgeindices.length; i=i+2) {\n",
3622       "        var start = points[edgeindices[i]];\n",
3623       "        var end = points[edgeindices[i+1]];\n",
3624       "        var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius();\n",
3625       "        if (dist <= 0) {\n",
3626       "            continue;\n",
3627       "        }\n",
3628       "        var dir = new THREE.Vector3().subVectors(end.vector,start.vector);\n",
3629       "        dir.normalize();\n",
3630       "        var axis = new THREE.Vector3().set(dir.z,0,-dir.x);\n",
3631       "        axis.normalize();\n",
3632       "        var radians = Math.acos( dir.y );\n",
3633       "        var radius = dist/25;\n",
3634       "        var height = dist/5;\n",
3635       "        var geometry = new THREE.ConeBufferGeometry(radius,height);\n",
3636       "        var position = new THREE.Vector3().addVectors(start.vector,dir.clone().multiplyScalar(start.radius()+dist-height/2));\n",
3637       "        if (Array.isArray(edgematerials)) {\n",
3638       "            material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} );\n",
3639       "        }\n",
3640       "        var cone = new THREE.Mesh( geometry, material );\n",
3641       "        cone.quaternion.setFromAxisAngle(axis,radians);;\n",
3642       "        cone.position.copy(position);;\n",
3643       "        arrowheads.add(cone);\n",
3644       "    }\n",
3645       "    obj.add(arrowheads);\n",
3646       "}\n",
3647       "\n",
3648       "function init_faces(obj) {\n",
3649       "    var points = obj.userData.points;\n",
3650       "    var facets = obj.userData.facets;\n",
3651       "    obj.userData.triangleindices = [];\n",
3652       "    for (var i=0; i<facets.length; i++) {\n",
3653       "        facet = facets[i];\n",
3654       "        for (var t=0; t<facet.length-2; t++) {\n",
3655       "            obj.userData.triangleindices.push(facet[0],facet[t+1],facet[t+2]);  \n",
3656       "        }\n",
3657       "    }\n",
3658       "    var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 );\n",
3659       "    var bufattr = new THREE.Float32BufferAttribute(bufarr,3);\n",
3660       "    \n",
3661       "    var materials = obj.userData.facetmaterial;\n",
3662       "    var geometry = new THREE.BufferGeometry();\n",
3663       "    geometry.setAttribute('position',bufattr);\n",
3664       "    if (Array.isArray(materials)) {\n",
3665       "        var tricount = 0;\n",
3666       "        var facet;\n",
3667       "        for (var i=0; i<facets.length; i++) {\n",
3668       "            facet = facets[i];\n",
3669       "            geometry.addGroup(tricount,(facet.length-2)*3,i);\n",
3670       "            tricount += (facet.length-2)*3;\n",
3671       "        }\n",
3672       "    }\n",
3673       "    var mesh = new THREE.Mesh(geometry, materials);\n",
3674       "    mesh.name = \"faces\";\n",
3675       "    obj.add(mesh); \n",
3676       "    updateFacesPosition(obj);\n",
3677       "}\n",
3678       "// //INITIALIZING\n",
3679       "\n",
3680       "\n",
3681       "function updateFacesPosition(obj) {\n",
3682       "    var points = obj.userData.points;\n",
3683       "    var indices = obj.userData.triangleindices;\n",
3684       "    var faces = obj.getObjectByName(\"faces\");\n",
3685       "    var ba = faces.geometry.getAttribute(\"position\");\n",
3686       "    for (var i=0; i<indices.length; i++) {\n",
3687       "        ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z); \n",
3688       "    }\n",
3689       "    faces.geometry.attributes.position.needsUpdate = true;\n",
3690       "    \n",
3691       "}\n",
3692       "\n",
3693       "function updateEdgesPosition(obj) {\n",
3694       "    var points = obj.userData.points;\n",
3695       "    var indices = obj.userData.edgeindices;\n",
3696       "    var lines = obj.getObjectByName(\"lines\");\n",
3697       "    var ba = lines.geometry.getAttribute(\"position\"); \n",
3698       "    for (var i=0; i<indices.length; i++) {\n",
3699       "        ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z); \n",
3700       "    }\n",
3701       "    lines.geometry.attributes.position.needsUpdate = true;\n",
3702       "}\n",
3703       "\n",
3704       "function onWindowResize() {\n",
3705       "    renderer.setSize( three.clientWidth, three.clientHeight );\n",
3706       "    svgRenderer.setSize( three.clientWidth, three.clientHeight );\n",
3707       "    updateCamera();\n",
3708       "}\n",
3709       "\n",
3710       "function updateCamera() {\n",
3711       "    var width = three.clientWidth;\n",
3712       "    var height = three.clientHeight;\n",
3713       "    var aspect = width / height;\n",
3714       "    if (camera.type == \"OrthographicCamera\") {\n",
3715       "        camera.left = frustumSize * aspect / - 2;\n",
3716       "        camera.right = frustumSize * aspect / 2;\n",
3717       "        camera.top = frustumSize / 2;\n",
3718       "        camera.bottom = - frustumSize / 2;\n",
3719       "    } else if (camera.type == \"PerspectiveCamera\") {\n",
3720       "        camera.aspect = aspect;\n",
3721       "    }\n",
3722       "    camera.updateProjectionMatrix();\n",
3723       "}\n",
3724       "\n",
3725       "function changeCamera(event) {\n",
3726       "    var selindex = event.currentTarget.selectedIndex;\n",
3727       "    camera = cameras[selindex];\n",
3728       "    control = controls[selindex];\n",
3729       "    control.enabled = true; \n",
3730       "    for (var i=0; i<controls.length; i++) {\n",
3731       "        if (i!=selindex) {\n",
3732       "            controls[i].enabled = false;\n",
3733       "        }\n",
3734       "    }\n",
3735       "    updateCamera();\n",
3736       "}\n",
3737       "\n",
3738       "var camtypenode = document.getElementById('cameraType_2');\n",
3739       "camtypenode.onchange = changeCamera;\n",
3740       "camtypenode.dispatchEvent(new Event('change'));\n",
3741       "\n",
3742       "onWindowResize();\n",
3743       "window.addEventListener('resize', onWindowResize);\t\n",
3744       "\n",
3745       "\n",
3746       "var xRotationEnabled = false;\n",
3747       "var yRotationEnabled = false;\n",
3748       "var zRotationEnabled = false;\n",
3749       "var rotationSpeedFactor = 1;\n",
3750       "var settingsShown = false;\n",
3751       "var labelsShown = true;\n",
3752       "var intervals = [];\n",
3753       "var timeouts = [];\n",
3754       "var explodingSpeed = 0.05;\n",
3755       "var explodeScale = 0;\n",
3756       "var XMLS = new XMLSerializer();\n",
3757       "var svgElement;\n",
3758       "var renderId;\n",
3759       "\n",
3760       "var render = function () {\n",
3761       "\n",
3762       "\trenderId = requestAnimationFrame(render);\n",
3763       "\n",
3764       "//\tcomment in for automatic explosion\n",
3765       "//\texplode(updateFactor());\n",
3766       "\n",
3767       "    var phi = 0.02 * rotationSpeedFactor;\n",
3768       "\n",
3769       "    if (xRotationEnabled) {\n",
3770       "        scene.rotation.x += phi;\n",
3771       "    }\n",
3772       "    if (yRotationEnabled) {\n",
3773       "        scene.rotation.y += phi;\n",
3774       "    }\n",
3775       "    if (zRotationEnabled) {\n",
3776       "        scene.rotation.z += phi;\n",
3777       "    }\n",
3778       "\n",
3779       "    control.update();\n",
3780       "    renderer.render(scene, camera);\n",
3781       "};\n",
3782       "\n",
3783       "if ( THREE.WEBGL.isWebGLAvailable() ) {\n",
3784       "\trender();\n",
3785       "} else {\n",
3786       "\tvar warning = WEBGL.getWebGLErrorMessage();\n",
3787       "\tthree.appendChild( warning );\n",
3788       "}\n",
3789       "    \n",
3790       "function changeTransparency() {\n",
3791       "    var opacity = 1-Number(event.currentTarget.value);\n",
3792       "    for (var i=0; i<scene.children.length; i++) {\n",
3793       "        child = scene.children[i];\n",
3794       "        if ( child.userData.hasOwnProperty(\"facetmaterial\") ) {\n",
3795       "            if (Array.isArray(child.userData.facetmaterial)) {\n",
3796       "                for (var j=0; j<child.userData.facetmaterial.length; j++) {\n",
3797       "                    child.userData.facetmaterial[j].opacity = opacity;\n",
3798       "                }\n",
3799       "            } else {\n",
3800       "                child.userData.facetmaterial.opacity = opacity;\n",
3801       "            }    \n",
3802       "        }\n",
3803       "    }\n",
3804       "}\n",
3805       "\n",
3806       "function changeRotationX(event){\n",
3807       "    xRotationEnabled = event.currentTarget.checked;\n",
3808       "}\t\n",
3809       "\n",
3810       "function changeRotationY(event){\n",
3811       "    yRotationEnabled = event.currentTarget.checked;\n",
3812       "}\t\n",
3813       "\n",
3814       "function changeRotationZ(event){\n",
3815       "    zRotationEnabled = event.currentTarget.checked;\n",
3816       "}\t\n",
3817       "\n",
3818       "\n",
3819       "function changeRotationSpeedFactor(event){\n",
3820       "    rotationSpeedFactor = Number(event.currentTarget.value);\n",
3821       "}\n",
3822       "\n",
3823       "function resetScene(){\n",
3824       "    scene.rotation.set(0,0,0);\n",
3825       "    camera.position.set(0,0,5);\n",
3826       "    camera.up.set(0,1,0);\n",
3827       "}\n",
3828       "\n",
3829       "function showSettings(event){\n",
3830       "    document.getElementById('settings_2').style.visibility = 'visible';\n",
3831       "    document.getElementById('showSettingsButton_2').style.visibility = 'hidden';\n",
3832       "    document.getElementById('hideSettingsButton_2').style.visibility = 'visible';\n",
3833       "    settingsShown = true;\n",
3834       "}\n",
3835       "\n",
3836       "function hideSettings(event){\n",
3837       "    document.getElementById('settings_2').style.visibility = 'hidden';\n",
3838       "    document.getElementById('showSettingsButton_2').style.visibility = 'visible';\n",
3839       "    document.getElementById('hideSettingsButton_2').style.visibility = 'hidden';\n",
3840       "    settingsShown = false;\n",
3841       "}\n",
3842       "\n",
3843       "\n",
3844       "\n",
3845       "var pos = 150* Math.PI;\n",
3846       "\n",
3847       "function updateFactor() {\n",
3848       "    pos++;\n",
3849       "    return Math.sin(.01*pos)+1;\n",
3850       "}\n",
3851       "\n",
3852       "// ------------------------ FOLDING ------------------------------------------------\n",
3853       "// ---------------------------------------------------------------------------------\n",
3854       "// rotate point p around axis defined by points p1 and p2 by given angle\n",
3855       "function rotate(p, p1, p2, angle ){   \n",
3856       "    angle = -angle;\n",
3857       "    var x = p.x, y = p.y, z = p.z, \n",
3858       "    a = p1.x, b = p1.y, c = p1.z, \n",
3859       "    u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z;\n",
3860       "    var result = [];\n",
3861       "    var L = u*u + v*v + w*w;\n",
3862       "    var sqrt = Math.sqrt;\n",
3863       "    var cos = Math.cos;\n",
3864       "    var sin = Math.sin;\n",
3865       "\n",
3866       "    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))/L;\n",
3867       "    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))/L;\n",
3868       "    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))/L;\n",
3869       "\n",
3870       "    return result;\n",
3871       "}\n",
3872       "\n",
3873       "var fold = function(event){\n",
3874       "    var obj = foldables[Number(event.currentTarget.name)];\n",
3875       "    var foldvalue = Number(event.currentTarget.value);\n",
3876       "    var scale = foldvalue - obj.userData.oldscale;\n",
3877       "\n",
3878       "    for (var j=0; j<obj.userData.axes.length; j++) {\n",
3879       "        rotateVertices(obj, j, scale);\n",
3880       "    }\n",
3881       "    update(obj);\n",
3882       "    obj.userData.oldscale += scale;\n",
3883       "    lookAtBarycenter(obj);\n",
3884       "}\n",
3885       "\n",
3886       "function lookAtBarycenter(obj){\n",
3887       "    control.target = barycenter(obj);\n",
3888       "}\n",
3889       "\n",
3890       "function barycenter(obj) {\n",
3891       "    var center = new THREE.Vector3(0,0,0);\n",
3892       "    var points = obj.userData.points;\n",
3893       "    for (var i=0; i<points.length; i++){\n",
3894       "        center.add(points[i].vector);\n",
3895       "    }\n",
3896       "    center.divideScalar(points.length);\n",
3897       "    return center;\n",
3898       "}\n",
3899       "\n",
3900       "function rotateVertices(obj, edge, scale) {\n",
3901       "    var axes = obj.userData.axes;\n",
3902       "    var subtrees = obj.userData.subtrees;\n",
3903       "    var points = obj.userData.points;\n",
3904       "    var angles = obj.userData.angles;\n",
3905       "    if (edge < axes.length){\n",
3906       "        for (var j=0; j<subtrees[edge].length; j++){\n",
3907       "            var rotP = rotate(points[subtrees[edge][j]].vector, points[axes[edge][0]].vector,points[axes[edge][1]].vector, scale * (Math.PI - angles[edge]));\n",
3908       "            points[subtrees[edge][j]].set(rotP[0],rotP[1],rotP[2]);\n",
3909       "        }\n",
3910       "    }\n",
3911       "}\n",
3912       "\n",
3913       "function update(obj) {\n",
3914       "   updateFacesPosition(obj);\n",
3915       "   updateEdgesPosition(obj);\n",
3916       "}\n",
3917       "\n",
3918       "if (foldables.length) {\n",
3919       "    var settings = document.getElementById('settings_2');\n",
3920       "    var foldDiv = document.createElement('div');\n",
3921       "    foldDiv.id = 'fold_2';\n",
3922       "    var title = document.createElement('strong');\n",
3923       "    title.innerHTML = 'Fold';\n",
3924       "    foldDiv.appendChild(title);\n",
3925       "    foldDiv.className = 'group';\n",
3926       "    for (var i=0; i<foldables.length; i++) {\n",
3927       "        var range = document.createElement('input');\n",
3928       "        range.type = 'range';\n",
3929       "        range.min = 0;\n",
3930       "        range.max = 1;\n",
3931       "        range.value = 0;\n",
3932       "        range.step = 0.001;\n",
3933       "        range.name = String(i);\n",
3934       "        range.oninput = fold;\n",
3935       "        foldDiv.appendChild(range);\n",
3936       "    }\n",
3937       "    lookAtBarycenter(foldables[0]);\n",
3938       "    settings.insertBefore(foldDiv,settings.childNodes[0]);\n",
3939       "}\n",
3940       "\n",
3941       "    \n",
3942       "// ---------------------- EXPLOSION ------------------------------------------------\n",
3943       "// ---------------------------------------------------------------------------------\n",
3944       "\n",
3945       "if (explodableModel) {\n",
3946       "    for (var i=0; i<scene.children.length; i++) {\n",
3947       "        obj = scene.children[i];\n",
3948       "        if ( obj.userData.explodable ) {\n",
3949       "            computeCentroid(obj);\n",
3950       "        }\n",
3951       "    }\n",
3952       "    document.getElementById('explodeRange_2').oninput = triggerExplode;\n",
3953       "    document.getElementById('explodeCheckbox_2').onchange = triggerAutomaticExplode;\n",
3954       "    document.getElementById('explodingSpeedRange_2').oninput = setExplodingSpeed;\n",
3955       "}\n",
3956       "\n",
3957       "function computeCentroid(obj) {\n",
3958       "    centroid = new THREE.Vector3();\n",
3959       "    obj.userData.points.forEach(function(pmpoint) {\n",
3960       "        centroid.add(pmpoint.vector);\t\t\t\n",
3961       "    });\n",
3962       "    centroid.divideScalar(obj.userData.points.length);\n",
3963       "    obj.userData.centroid = centroid;\n",
3964       "}\n",
3965       "\n",
3966       "function explode(factor) {\n",
3967       "    for (var i=0; i<scene.children.length; i++) {\n",
3968       "        var obj = scene.children[i];\n",
3969       "        if (obj.userData.hasOwnProperty(\"centroid\")) { \n",
3970       "            var c = obj.userData.centroid;\n",
3971       "            obj.position.set(c.x*factor, c.y*factor, c.z*factor);\n",
3972       "        }\n",
3973       "    }\t\n",
3974       "}\n",
3975       "\n",
3976       "function triggerExplode(event){\n",
3977       "    explodeScale = Number(event.currentTarget.value);\n",
3978       "    explode(explodeScale);\n",
3979       "}\n",
3980       "\n",
3981       "function setExplodingSpeed(event){\n",
3982       "    explodingSpeed = Number(event.currentTarget.value);\n",
3983       "}\n",
3984       "\n",
3985       "function triggerAutomaticExplode(event){\n",
3986       "    if (event.currentTarget.checked){\n",
3987       "        startExploding();\n",
3988       "    } else {\n",
3989       "        clearIntervals();\n",
3990       "    }\t\n",
3991       "}\n",
3992       "\n",
3993       "function startExploding(){\n",
3994       "    intervals.push(setInterval(explodingInterval, 25));\n",
3995       "}\n",
3996       "\n",
3997       "\n",
3998       "function explodingInterval(){\n",
3999       "    explodeScale += explodingSpeed;\n",
4000       "    if (explodeScale <= 6){ \n",
4001       "        explode(explodeScale);\n",
4002       "    }\n",
4003       "    else{\n",
4004       "        explode(6);\n",
4005       "        explodeScale = 6;\n",
4006       "        clearIntervals();\n",
4007       "        timeouts.push(setTimeout(startUnexploding, 3000));\n",
4008       "    }\n",
4009       "    document.getElementById('explodeRange_2').value = explodeScale;\n",
4010       "}\n",
4011       "\n",
4012       "\n",
4013       "function startUnexploding(){\n",
4014       "    intervals.push(setInterval(unexplodingInterval, 25));\n",
4015       "}\n",
4016       "\n",
4017       "function unexplodingInterval(){\n",
4018       "    explodeScale -= explodingSpeed;\n",
4019       "    if (explodeScale >= 0){\t\n",
4020       "        explode(explodeScale);\n",
4021       "    }\n",
4022       "    else {\n",
4023       "        explode(0);\n",
4024       "        explodeScale = 0;\n",
4025       "        clearIntervals();\n",
4026       "        timeouts.push(setTimeout(startExploding, 3000));\n",
4027       "    }\n",
4028       "    document.getElementById('explodeRange_2').value = explodeScale;\n",
4029       "}\n",
4030       "\n",
4031       "function clearIntervals(){\n",
4032       "    intervals.forEach(function(interval){\n",
4033       "        clearInterval(interval);\n",
4034       "    });\n",
4035       "    intervals = [];\n",
4036       "    timeouts.forEach(function(timeout){\n",
4037       "        clearTimeout(timeout);\n",
4038       "    });\n",
4039       "    timeouts = [];\n",
4040       "}\n",
4041       "\n",
4042       "// ---------------------- DISPLAY --------------------------------------------------\n",
4043       "// ---------------------------------------------------------------------------------\n",
4044       "\n",
4045       "const objectTypeInnerHTMLs = { points: \"Points\", pointlabels: \"Point labels\", lines: \"Edges\", edgelabels: \"Edge labels\", faces: \"Faces\", arrowheads: \"Arrow heads\" };\n",
4046       "const objectTypeVisible = {};\n",
4047       "Object.assign(objectTypeVisible,modelContains);\n",
4048       "const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort();\n",
4049       "const shownObjectTypesList = document.getElementById('shownObjectTypesList_2');\n",
4050       "\n",
4051       "function setVisibility(bool,objname) {\n",
4052       "    for (var i=0; i<scene.children.length; i++){\n",
4053       "        var obj = scene.children[i].getObjectByName(objname);\n",
4054       "        if (obj) {\n",
4055       "            obj.visible = bool;\n",
4056       "        }\n",
4057       "    }\n",
4058       "}\n",
4059       "\n",
4060       "function toggleObjectTypeVisibility(event){\n",
4061       "    var name = event.currentTarget.name;\n",
4062       "    var checked = event.currentTarget.checked;\n",
4063       "    objectTypeVisible[name] = checked;\n",
4064       "    setVisibility(checked,name);\n",
4065       "}\n",
4066       "\n",
4067       "for (var i=0; i<sortedObjectTypeKeys.length; i++){\n",
4068       "    var key = sortedObjectTypeKeys[i];\n",
4069       "    if (modelContains[key]) {\n",
4070       "        var objTypeNode = document.createElement('span');\n",
4071       "        objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '<br>';\n",
4072       "        var checkbox = document.createElement('input');\n",
4073       "        checkbox.type = 'checkbox';\n",
4074       "        checkbox.checked = true;\n",
4075       "        checkbox.name = key;\n",
4076       "        checkbox.onchange = toggleObjectTypeVisibility;\n",
4077       "        shownObjectTypesList.appendChild(checkbox);\n",
4078       "        shownObjectTypesList.appendChild(objTypeNode);\n",
4079       "    }\n",
4080       "}\n",
4081       "\n",
4082       "// ------------------------------------------------------\n",
4083       "\n",
4084       "function toggleObjectVisibility(event){\n",
4085       "    var nr = Number(event.currentTarget.name);\n",
4086       "    scene.children[nr].visible = event.currentTarget.checked;\n",
4087       "}\n",
4088       "\n",
4089       "// append checkboxes for displaying or hiding objects\n",
4090       "var shownObjectsList = document.getElementById('shownObjectsList_2');\n",
4091       "for (var i=0; i<scene.children.length; i++){\n",
4092       "    obj = scene.children[i];\n",
4093       "    var objNode = document.createElement('span');\n",
4094       "    objNode.innerHTML = obj.name + '<br>';\n",
4095       "    var checkbox = document.createElement('input');\n",
4096       "    checkbox.type = 'checkbox';\n",
4097       "    checkbox.checked = true;\n",
4098       "    checkbox.name = String(i);\n",
4099       "    checkbox.onchange = toggleObjectVisibility;\n",
4100       "    shownObjectsList.appendChild(checkbox);\n",
4101       "    shownObjectsList.appendChild(objNode);\n",
4102       "}\n",
4103       "\n",
4104       "// ---------------------- SVG ------------------------------------------------------\n",
4105       "// ---------------------------------------------------------------------------------\n",
4106       "\n",
4107       "function takeSvgScreenshot() {\n",
4108       "    if (objectTypeVisible[\"pointlabels\"]) {\n",
4109       "        setVisibility(false,\"pointlabels\");\n",
4110       "    }\n",
4111       "    if (objectTypeVisible[\"edgelabels\"]) {\n",
4112       "        setVisibility(false,\"edgelabels\");\n",
4113       "    }\n",
4114       "    svgRenderer.render(scene,camera);\n",
4115       "    svgElement = XMLS.serializeToString(svgRenderer.domElement);\n",
4116       "    \n",
4117       "    if (objectTypeVisible[\"pointlabels\"]) {\n",
4118       "        setVisibility(true,\"pointlabels\");\n",
4119       "    }\n",
4120       "    if (objectTypeVisible[\"edgelabels\"]) {\n",
4121       "        setVisibility(true,\"edgelabels\");\n",
4122       "    }\n",
4123       "\n",
4124       "    if (document.getElementById('tab_2').checked){\n",
4125       "        //show in new tab\n",
4126       "        var myWindow = window.open(\"\",\"\");\n",
4127       "        myWindow.document.body.innerHTML = svgElement;\n",
4128       "    } else{\n",
4129       "        // download svg file \n",
4130       "        download(\"screenshot.svg\", svgElement);\n",
4131       "    }\n",
4132       "}\n",
4133       "\n",
4134       "function download(filename, text) {\n",
4135       "    var element = document.createElement('a');\n",
4136       "    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));\n",
4137       "    element.setAttribute('download', filename);\n",
4138       "\n",
4139       "    element.style.display = 'none';\n",
4140       "    document.body.appendChild(element);\n",
4141       "\n",
4142       "    element.click();\n",
4143       "\n",
4144       "    document.body.removeChild(element);\n",
4145       "}\n",
4146       "\n",
4147       "\n",
4148       "document.getElementById('transparencyRange_2').oninput = changeTransparency;\n",
4149       "document.getElementById('changeRotationX_2').onchange = changeRotationX;\n",
4150       "document.getElementById('changeRotationY_2').onchange = changeRotationY;\n",
4151       "document.getElementById('changeRotationZ_2').onchange = changeRotationZ;\n",
4152       "document.getElementById('resetButton_2').onclick = resetScene;\n",
4153       "document.getElementById('rotationSpeedRange_2').oninput = changeRotationSpeedFactor;\n",
4154       "document.getElementById('takeScreenshot_2').onclick = takeSvgScreenshot;\n",
4155       "document.getElementById('showSettingsButton_2').onclick = showSettings;\n",
4156       "document.getElementById('hideSettingsButton_2').onclick = hideSettings;\n",
4157       "\n",
4158       "\n",
4159       "// ------------------ SHORTCUTS --------------------------------------------\n",
4160       "// -------------------------------------------------------------------------\n",
4161       "\n",
4162       "/**\n",
4163       " * http://www.openjs.com/scripts/events/keyboard_shortcuts/\n",
4164       " * Version : 2.01.B\n",
4165       " * By Binny V A\n",
4166       " * License : BSD\n",
4167       " */\n",
4168       "shortcut = {\n",
4169       "\t'all_shortcuts':{},//All the shortcuts are stored in this array\n",
4170       "\t'add': function(shortcut_combination,callback,opt) {\n",
4171       "\t\t//Provide a set of default options\n",
4172       "\t\tvar default_options = {\n",
4173       "\t\t\t'type':'keydown',\n",
4174       "\t\t\t'propagate':false,\n",
4175       "\t\t\t'disable_in_input':false,\n",
4176       "\t\t\t'target':document,\n",
4177       "\t\t\t'keycode':false\n",
4178       "\t\t}\n",
4179       "\t\tif(!opt) opt = default_options;\n",
4180       "\t\telse {\n",
4181       "\t\t\tfor(var dfo in default_options) {\n",
4182       "\t\t\t\tif(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];\n",
4183       "\t\t\t}\n",
4184       "\t\t}\n",
4185       "\n",
4186       "\t\tvar ele = opt.target;\n",
4187       "\t\tif(typeof opt.target == 'string') ele = document.getElementById(opt.target);\n",
4188       "\t\tvar ths = this;\n",
4189       "\t\tshortcut_combination = shortcut_combination.toLowerCase();\n",
4190       "\n",
4191       "\t\t//The function to be called at keypress\n",
4192       "\t\tvar func = function(e) {\n",
4193       "\t\t\te = e || window.event;\n",
4194       "\t\t\t\n",
4195       "\t\t\tif(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields\n",
4196       "\t\t\t\tvar element;\n",
4197       "\t\t\t\tif(e.target) element=e.target;\n",
4198       "\t\t\t\telse if(e.srcElement) element=e.srcElement;\n",
4199       "\t\t\t\tif(element.nodeType==3) element=element.parentNode;\n",
4200       "\n",
4201       "\t\t\t\tif(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;\n",
4202       "\t\t\t}\n",
4203       "\t\n",
4204       "\t\t\t//Find Which key is pressed\n",
4205       "\t\t\tif (e.keyCode) code = e.keyCode;\n",
4206       "\t\t\telse if (e.which) code = e.which;\n",
4207       "\t\t\tvar character = String.fromCharCode(code).toLowerCase();\n",
4208       "\t\t\t\n",
4209       "\t\t\tif(code == 188) character=\",\"; //If the user presses , when the type is onkeydown\n",
4210       "\t\t\tif(code == 190) character=\".\"; //If the user presses , when the type is onkeydown\n",
4211       "\n",
4212       "\t\t\tvar keys = shortcut_combination.split(\"+\");\n",
4213       "\t\t\t//Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked\n",
4214       "\t\t\tvar kp = 0;\n",
4215       "\t\t\t\n",
4216       "\t\t\t//Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken\n",
4217       "\t\t\tvar shift_nums = {\n",
4218       "\t\t\t\t\"`\":\"~\",\n",
4219       "\t\t\t\t\"1\":\"!\",\n",
4220       "\t\t\t\t\"2\":\"@\",\n",
4221       "\t\t\t\t\"3\":\"#\",\n",
4222       "\t\t\t\t\"4\":\"$\",\n",
4223       "\t\t\t\t\"5\":\"%\",\n",
4224       "\t\t\t\t\"6\":\"^\",\n",
4225       "\t\t\t\t\"7\":\"&\",\n",
4226       "\t\t\t\t\"8\":\"*\",\n",
4227       "\t\t\t\t\"9\":\"(\",\n",
4228       "\t\t\t\t\"0\":\")\",\n",
4229       "\t\t\t\t\"-\":\"_\",\n",
4230       "\t\t\t\t\"=\":\"+\",\n",
4231       "\t\t\t\t\";\":\":\",\n",
4232       "\t\t\t\t\"'\":\"\\\"\",\n",
4233       "\t\t\t\t\",\":\"<\",\n",
4234       "\t\t\t\t\".\":\">\",\n",
4235       "\t\t\t\t\"/\":\"?\",\n",
4236       "\t\t\t\t\"\\\\\":\"|\"\n",
4237       "\t\t\t}\n",
4238       "\t\t\t//Special Keys - and their codes\n",
4239       "\t\t\tvar special_keys = {\n",
4240       "\t\t\t\t'esc':27,\n",
4241       "\t\t\t\t'escape':27,\n",
4242       "\t\t\t\t'tab':9,\n",
4243       "\t\t\t\t'space':32,\n",
4244       "\t\t\t\t'return':13,\n",
4245       "\t\t\t\t'enter':13,\n",
4246       "\t\t\t\t'backspace':8,\n",
4247       "\t\n",
4248       "\t\t\t\t'scrolllock':145,\n",
4249       "\t\t\t\t'scroll_lock':145,\n",
4250       "\t\t\t\t'scroll':145,\n",
4251       "\t\t\t\t'capslock':20,\n",
4252       "\t\t\t\t'caps_lock':20,\n",
4253       "\t\t\t\t'caps':20,\n",
4254       "\t\t\t\t'numlock':144,\n",
4255       "\t\t\t\t'num_lock':144,\n",
4256       "\t\t\t\t'num':144,\n",
4257       "\t\t\t\t\n",
4258       "\t\t\t\t'pause':19,\n",
4259       "\t\t\t\t'break':19,\n",
4260       "\t\t\t\t\n",
4261       "\t\t\t\t'insert':45,\n",
4262       "\t\t\t\t'home':36,\n",
4263       "\t\t\t\t'delete':46,\n",
4264       "\t\t\t\t'end':35,\n",
4265       "\t\t\t\t\n",
4266       "\t\t\t\t'pageup':33,\n",
4267       "\t\t\t\t'page_up':33,\n",
4268       "\t\t\t\t'pu':33,\n",
4269       "\t\n",
4270       "\t\t\t\t'pagedown':34,\n",
4271       "\t\t\t\t'page_down':34,\n",
4272       "\t\t\t\t'pd':34,\n",
4273       "\t\n",
4274       "\t\t\t\t'left':37,\n",
4275       "\t\t\t\t'up':38,\n",
4276       "\t\t\t\t'right':39,\n",
4277       "\t\t\t\t'down':40,\n",
4278       "\t\n",
4279       "\t\t\t\t'f1':112,\n",
4280       "\t\t\t\t'f2':113,\n",
4281       "\t\t\t\t'f3':114,\n",
4282       "\t\t\t\t'f4':115,\n",
4283       "\t\t\t\t'f5':116,\n",
4284       "\t\t\t\t'f6':117,\n",
4285       "\t\t\t\t'f7':118,\n",
4286       "\t\t\t\t'f8':119,\n",
4287       "\t\t\t\t'f9':120,\n",
4288       "\t\t\t\t'f10':121,\n",
4289       "\t\t\t\t'f11':122,\n",
4290       "\t\t\t\t'f12':123\n",
4291       "\t\t\t}\n",
4292       "\t\n",
4293       "\t\t\tvar modifiers = { \n",
4294       "\t\t\t\tshift: { wanted:false, pressed:false},\n",
4295       "\t\t\t\tctrl : { wanted:false, pressed:false},\n",
4296       "\t\t\t\talt  : { wanted:false, pressed:false},\n",
4297       "\t\t\t\tmeta : { wanted:false, pressed:false}\t//Meta is Mac specific\n",
4298       "\t\t\t};\n",
4299       "                        \n",
4300       "\t\t\tif(e.ctrlKey)\tmodifiers.ctrl.pressed = true;\n",
4301       "\t\t\tif(e.shiftKey)\tmodifiers.shift.pressed = true;\n",
4302       "\t\t\tif(e.altKey)\tmodifiers.alt.pressed = true;\n",
4303       "\t\t\tif(e.metaKey)   modifiers.meta.pressed = true;\n",
4304       "                        \n",
4305       "\t\t\tfor(var i=0; k=keys[i],i<keys.length; i++) {\n",
4306       "\t\t\t\t//Modifiers\n",
4307       "\t\t\t\tif(k == 'ctrl' || k == 'control') {\n",
4308       "\t\t\t\t\tkp++;\n",
4309       "\t\t\t\t\tmodifiers.ctrl.wanted = true;\n",
4310       "\n",
4311       "\t\t\t\t} else if(k == 'shift') {\n",
4312       "\t\t\t\t\tkp++;\n",
4313       "\t\t\t\t\tmodifiers.shift.wanted = true;\n",
4314       "\n",
4315       "\t\t\t\t} else if(k == 'alt') {\n",
4316       "\t\t\t\t\tkp++;\n",
4317       "\t\t\t\t\tmodifiers.alt.wanted = true;\n",
4318       "\t\t\t\t} else if(k == 'meta') {\n",
4319       "\t\t\t\t\tkp++;\n",
4320       "\t\t\t\t\tmodifiers.meta.wanted = true;\n",
4321       "\t\t\t\t} else if(k.length > 1) { //If it is a special key\n",
4322       "\t\t\t\t\tif(special_keys[k] == code) kp++;\n",
4323       "\t\t\t\t\t\n",
4324       "\t\t\t\t} else if(opt['keycode']) {\n",
4325       "\t\t\t\t\tif(opt['keycode'] == code) kp++;\n",
4326       "\n",
4327       "\t\t\t\t} else { //The special keys did not match\n",
4328       "\t\t\t\t\tif(character == k) kp++;\n",
4329       "\t\t\t\t\telse {\n",
4330       "\t\t\t\t\t\tif(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase\n",
4331       "\t\t\t\t\t\t\tcharacter = shift_nums[character]; \n",
4332       "\t\t\t\t\t\t\tif(character == k) kp++;\n",
4333       "\t\t\t\t\t\t}\n",
4334       "\t\t\t\t\t}\n",
4335       "\t\t\t\t}\n",
4336       "\t\t\t}\n",
4337       "\t\t\t\n",
4338       "\t\t\tif(kp == keys.length && \n",
4339       "\t\t\t\t\t\tmodifiers.ctrl.pressed == modifiers.ctrl.wanted &&\n",
4340       "\t\t\t\t\t\tmodifiers.shift.pressed == modifiers.shift.wanted &&\n",
4341       "\t\t\t\t\t\tmodifiers.alt.pressed == modifiers.alt.wanted &&\n",
4342       "\t\t\t\t\t\tmodifiers.meta.pressed == modifiers.meta.wanted) {\n",
4343       "\t\t\t\tcallback(e);\n",
4344       "\t\n",
4345       "\t\t\t\tif(!opt['propagate']) { //Stop the event\n",
4346       "\t\t\t\t\t//e.cancelBubble is supported by IE - this will kill the bubbling process.\n",
4347       "\t\t\t\t\te.cancelBubble = true;\n",
4348       "\t\t\t\t\te.returnValue = false;\n",
4349       "\t\n",
4350       "\t\t\t\t\t//e.stopPropagation works in Firefox.\n",
4351       "\t\t\t\t\tif (e.stopPropagation) {\n",
4352       "\t\t\t\t\t\te.stopPropagation();\n",
4353       "\t\t\t\t\t\te.preventDefault();\n",
4354       "\t\t\t\t\t}\n",
4355       "\t\t\t\t\treturn false;\n",
4356       "\t\t\t\t}\n",
4357       "\t\t\t}\n",
4358       "\t\t}\n",
4359       "\t\tthis.all_shortcuts[shortcut_combination] = {\n",
4360       "\t\t\t'callback':func, \n",
4361       "\t\t\t'target':ele, \n",
4362       "\t\t\t'event': opt['type']\n",
4363       "\t\t};\n",
4364       "\t\t//Attach the function with the event\n",
4365       "\t\tif(ele.addEventListener) ele.addEventListener(opt['type'], func, false);\n",
4366       "\t\telse if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);\n",
4367       "\t\telse ele['on'+opt['type']] = func;\n",
4368       "\t},\n",
4369       "\n",
4370       "\t//Remove the shortcut - just specify the shortcut and I will remove the binding\n",
4371       "\t'remove':function(shortcut_combination) {\n",
4372       "\t\tshortcut_combination = shortcut_combination.toLowerCase();\n",
4373       "\t\tvar binding = this.all_shortcuts[shortcut_combination];\n",
4374       "\t\tdelete(this.all_shortcuts[shortcut_combination])\n",
4375       "\t\tif(!binding) return;\n",
4376       "\t\tvar type = binding['event'];\n",
4377       "\t\tvar ele = binding['target'];\n",
4378       "\t\tvar callback = binding['callback'];\n",
4379       "\n",
4380       "\t\tif(ele.detachEvent) ele.detachEvent('on'+type, callback);\n",
4381       "\t\telse if(ele.removeEventListener) ele.removeEventListener(type, callback, false);\n",
4382       "\t\telse ele['on'+type] = false;\n",
4383       "\t}\n",
4384       "}\n",
4385       "\n",
4386       "shortcut.add(\"Alt+Left\",function() {\n",
4387       "\tvar event = new Event('click');\n",
4388       "\tif (settingsShown){\n",
4389       "\t\tdocument.getElementById('hideSettingsButton_2').dispatchEvent(event);\n",
4390       "\t} else {\n",
4391       "\t\tdocument.getElementById('showSettingsButton_2').dispatchEvent(event);\n",
4392       "\t}\n",
4393       "});\n",
4394       "\n",
4395       "\n",
4396       "// COMMON_CODE_BLOCK_END\n",
4397       "\n",
4398       "});});\n",
4399       "      </script>\n",
4400       "   </body>\n",
4401       "</html>"
4402      ]
4403     },
4404     "metadata": {},
4405     "output_type": "display_data"
4406    }
4407   ],
4408   "source": [
4409    "$integer_hull=new Polytope<Rational>(POINTS=>$scaled_rs->LATTICE_POINTS);\n",
4410    "$integer_hull->VISUAL->LATTICE_COLORED;"
4411   ]
4412  },
4413  {
4414   "cell_type": "markdown",
4415   "metadata": {},
4416   "source": [
4417    "    \n"
4418   ]
4419  },
4420  {
4421   "cell_type": "markdown",
4422   "metadata": {},
4423   "source": [
4424    "\n",
4425    "In order to obtain the integer hull we simply define a new polytope `$integer_hull` as the convex hull of all `LATTICE_POINTS` contained in `$scaled_rs`.\n",
4426    "\n",
4427    "Note that if we give `POINTS` (in contrast to `VERTICES`) `polymake` constructs a polytope that is the convex hull of the given points regardless of whether they are vertices or not. I.e., redundacies are allowed here.\n",
4428    "\n",
4429    "If you specify `VERTICES` you have to make sure yourself that your points are actually vertices since `polymake` does not check this. You also need to specify the `LINEALITY_SPACE`, see [ Tutorial on polytopes](apps_polytope.ipynb).\n",
4430    "\n",
4431    "### Linear Programming\n",
4432    "\n",
4433    "Now that we have constructed a nice integral polytope we want to apply some linear program to it.\n",
4434    "\n",
4435    "First we define a `LinearProgram` with our favourite `LINEAR_OBJECTIVE`. The linear objective is an given as a vector of length d+1, d being the dimension of the space. The vector [c<sub>0</sub>,c<sub>1</sub>, ..., c<sub>d</sub>] corresponds to the linear objective c<sub>0</sub> + c<sub>1</sub>x<sub>1</sub> + ... + c<sub>d</sub>x<sub>d</sub>.\n",
4436    "\n",
4437    "    \n"
4438   ]
4439  },
4440  {
4441   "cell_type": "code",
4442   "execution_count": 15,
4443   "metadata": {},
4444   "outputs": [],
4445   "source": [
4446    "$objective=new LinearProgram<Rational>(LINEAR_OBJECTIVE=>[0,1,1,1]);"
4447   ]
4448  },
4449  {
4450   "cell_type": "markdown",
4451   "metadata": {},
4452   "source": [
4453    "\n",
4454    "Then we define a new polytope, which is a copy of our old one (`$inter_hull`) with the LP as an additional property.\n",
4455    "\n",
4456    "    \n"
4457   ]
4458  },
4459  {
4460   "cell_type": "code",
4461   "execution_count": 16,
4462   "metadata": {},
4463   "outputs": [],
4464   "source": [
4465    "$ilp=new Polytope<Rational>(VERTICES=>$integer_hull->VERTICES, LP=>$objective);"
4466   ]
4467  },
4468  {
4469   "attachments": {
4470    "ilp_max_face.png": {
4471     "image/png": "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"
4472    },
4473    "ilp_min_face.png": {
4474     "image/png": "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"
4475    }
4476   },
4477   "cell_type": "markdown",
4478   "metadata": {},
4479   "source": [
4480    "![ilp_min_face.png](attachment:ilp_min_face.png)\n",
4481    "![ilp_max_face.png](attachment:ilp_max_face.png)\n",
4482    "\n",
4483    "And now we can perform some computations:"
4484   ]
4485  },
4486  {
4487   "cell_type": "code",
4488   "execution_count": 17,
4489   "metadata": {},
4490   "outputs": [
4491    {
4492     "data": {
4493      "text/plain": [
4494       "2"
4495      ]
4496     },
4497     "execution_count": 17,
4498     "metadata": {},
4499     "output_type": "execute_result"
4500    }
4501   ],
4502   "source": [
4503    "print $ilp->LP->MAXIMAL_VALUE;"
4504   ]
4505  },
4506  {
4507   "cell_type": "code",
4508   "execution_count": 18,
4509   "metadata": {},
4510   "outputs": [
4511    {
4512     "data": {
4513      "text/plain": [
4514       "{8 10 11}"
4515      ]
4516     },
4517     "execution_count": 18,
4518     "metadata": {},
4519     "output_type": "execute_result"
4520    }
4521   ],
4522   "source": [
4523    "print $ilp->LP->MAXIMAL_FACE;"
4524   ]
4525  },
4526  {
4527   "cell_type": "code",
4528   "execution_count": 19,
4529   "metadata": {},
4530   "outputs": [
4531    {
4532     "data": {
4533      "text/html": [
4534       "<!--\n",
4535       "polymake for knusper\n",
4536       "Thu Aug 27 11:38:20 2020\n",
4537       "ilp\n",
4538       "-->\n",
4539       "\n",
4540       "\n",
4541       "<html>\n",
4542       "   <head>\n",
4543       "      <meta charset=utf-8>\n",
4544       "      <title>ilp</title>\n",
4545       "      <style>\n",
4546       "/*\n",
4547       "// COMMON_CODE_BLOCK_BEGIN\n",
4548       "*/\n",
4549       "         html {overflow: scroll;}\n",
4550       "         strong{font-size: 18px;}\n",
4551       "         canvas { z-index: 8; }\n",
4552       "         input[type='radio'] {margin-left:0;}\n",
4553       "         input[type='checkbox'] {margin-right:7px; margin-left: 0px; padding-left:0px;}\n",
4554       "         .group{padding-bottom: 15px;}\n",
4555       "         .settings * {z-index: 11; }\n",
4556       "         .settings{z-index: 10; font-family: Arial, Helvetica, sans-serif; margin-left: 30px; visibility: hidden; width: 14em; height: 96%; border: solid 1px silver; padding: 2px; overflow-y: scroll; box-sizing: border-box; background-color: white; position: absolute;}\n",
4557       "         .indented{margin-left: 20px; margin-top: 10px; padding-bottom: 0px;} \n",
4558       "         .shownObjectsList{overflow: auto; max-width: 150px; max-height: 150px;}\n",
4559       "         .showSettingsButton{visibility: visible; z-index: 12; position: absolute }\n",
4560       "         .hideSettingsButton{visibility: hidden; z-index: 12; position: absolute; opacity: 0.5}\n",
4561       "         button{margin-left: 0; margin-top: 10px}\n",
4562       "         img{cursor: pointer;}\n",
4563       "         .suboption{padding-top: 15px;}\n",
4564       "         #model31430920245 { width: 100%; height: 100%; }\n",
4565       "         .threejs_container { width: 100%; height: 75vh;}\n",
4566       "         .settings{max-height: 74vh} \n",
4567       "         input[type=range] {\n",
4568       "           -webkit-appearance: none;\n",
4569       "           padding:0; \n",
4570       "           width:90%; \n",
4571       "           margin-left: auto;\n",
4572       "           margin-right: auto;\n",
4573       "           margin-top: 15px;\n",
4574       "           margin-bottom: 15px;\n",
4575       "           display: block;\t\n",
4576       "         }\n",
4577       "         input[type=range]:focus {\n",
4578       "           outline: none;\n",
4579       "         }\n",
4580       "         input[type=range]::-webkit-slider-runnable-track {\n",
4581       "           height: 4px;\n",
4582       "           cursor: pointer;\n",
4583       "           animate: 0.2s;\n",
4584       "           box-shadow: 0px 0px 0px #000000;\n",
4585       "           background: #E3E3E3;\n",
4586       "           border-radius: 0px;\n",
4587       "           border: 0px solid #000000;\n",
4588       "         }\n",
4589       "         input[type=range]::-webkit-slider-thumb {\n",
4590       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
4591       "           border: 1px solid #ABABAB;\n",
4592       "           height: 13px;\n",
4593       "           width: 25px;\n",
4594       "           border-radius: 20px;\n",
4595       "           background: #E0E0E0;\n",
4596       "           cursor: pointer;\n",
4597       "           -webkit-appearance: none;\n",
4598       "           margin-top: -5px;\n",
4599       "         }\n",
4600       "         input[type=range]:focus::-webkit-slider-runnable-track {\n",
4601       "           background: #E3E3E3;\n",
4602       "         }\n",
4603       "         input[type=range]::-moz-range-track {\n",
4604       "           height: 4px;\n",
4605       "           cursor: pointer;\n",
4606       "           animate: 0.2s;\n",
4607       "           box-shadow: 0px 0px 0px #000000;\n",
4608       "           background: #E3E3E3;\n",
4609       "           border-radius: 0px;\n",
4610       "           border: 0px solid #000000;\n",
4611       "         }\n",
4612       "         input[type=range]::-moz-range-thumb {\n",
4613       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
4614       "           border: 1px solid #ABABAB;\n",
4615       "           height: 13px;\n",
4616       "           width: 25px;\n",
4617       "           border-radius: 20px;\n",
4618       "           background: #E0E0E0;\n",
4619       "           cursor: pointer;\n",
4620       "         }\n",
4621       "         input[type=range]::-ms-track {\n",
4622       "           height: 4px;\n",
4623       "           cursor: pointer;\n",
4624       "           animate: 0.2s;\n",
4625       "           background: transparent;\n",
4626       "           border-color: transparent;\n",
4627       "           color: transparent;\n",
4628       "         }\n",
4629       "         input[type=range]::-ms-fill-lower {\n",
4630       "           background: #E3E3E3;\n",
4631       "           border: 0px solid #000000;\n",
4632       "           border-radius: 0px;\n",
4633       "           box-shadow: 0px 0px 0px #000000;\n",
4634       "         }\n",
4635       "         input[type=range]::-ms-fill-upper {\n",
4636       "           background: #E3E3E3;\n",
4637       "           border: 0px solid #000000;\n",
4638       "           border-radius: 0px;\n",
4639       "           box-shadow: 0px 0px 0px #000000;\n",
4640       "         }\n",
4641       "         input[type=range]::-ms-thumb {\n",
4642       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
4643       "           border: 1px solid #ABABAB;\n",
4644       "           height: 13px;\n",
4645       "           width: 25px;\n",
4646       "           border-radius: 20px;\n",
4647       "           background: #E0E0E0;\n",
4648       "           cursor: pointer;\n",
4649       "         }\n",
4650       "         input[type=range]:focus::-ms-fill-lower {\n",
4651       "           background: #E3E3E3;\n",
4652       "         }\n",
4653       "         input[type=range]:focus::-ms-fill-upper {\n",
4654       "           background: #E3E3E3;\n",
4655       "         }\n",
4656       "/*\n",
4657       "// COMMON_CODE_BLOCK_END\n",
4658       "*/\n",
4659       "\t\t</style>\n",
4660       "   </head>\n",
4661       "<body>\n",
4662       "   <div class='threejs_container'>\n",
4663       "\t\t<div id='settings_3' class='settings'>\n",
4664       "\t\t\t<div class=group id='transparency_3' class='transparency'>\n",
4665       "\t\t\t\t<strong>Transparency</strong>\n",
4666       "\t\t\t\t<input id='transparencyRange_3' type='range' min=0 max=1 step=0.01 value=0>\n",
4667       "\t\t\t</div>\n",
4668       "\t\t\t\n",
4669       "\t\t\t<div class=group id='rotation_3'>\n",
4670       "\t\t\t\t<strong>Rotation</strong>\n",
4671       "\t\t\t\t<div class=indented>\n",
4672       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationX_3'> x-axis</div>\n",
4673       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationY_3'> y-axis</div>\n",
4674       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationZ_3'> z-axis</div>\n",
4675       "\t\t\t\t\t<button id='resetButton_3'>Reset</button>\n",
4676       "\t\t\t\t</div>\n",
4677       "\n",
4678       "\t\t\t\t<div class=suboption>Rotation speed</div>\n",
4679       "\t\t\t\t<input id='rotationSpeedRange_3' type='range' min=0 max=5 step=0.01 value=2>\n",
4680       "\t\t\t</div>\n",
4681       "\n",
4682       "\n",
4683       "\t\t\t<div class=group id='display_3'>\n",
4684       "\t\t\t\t<strong>Display</strong>\n",
4685       "\t\t\t\t<div class=indented>\n",
4686       "\t\t\t\t\t<div id='shownObjectTypesList_3' class='shownObjectsList'></div>\n",
4687       "\t\t\t\t</div>\n",
4688       "\t\t\t\t<div class=suboption>Objects</div>\n",
4689       "\t\t\t\t<div class=indented>\n",
4690       "\t\t\t\t   <div id='shownObjectsList_3' class='shownObjectsList'></div>\n",
4691       "\t\t\t\t</div>\n",
4692       "\t\t\t</div>\n",
4693       "         \n",
4694       "         <div class=group id='camera_3'>\n",
4695       "            <strong>Camera</strong>\n",
4696       "            <div class=indented>\n",
4697       "               <form>\n",
4698       "                  <select id=\"cameraType_3\">\n",
4699       "                     <option value='perspective' selected> Perspective<br></option>\n",
4700       "                     <option value='orthographic' > Orthographic<br></option>\n",
4701       "                  </select>\n",
4702       "               </form>\n",
4703       "            </div>\n",
4704       "         </div>\n",
4705       "\n",
4706       "\t\t\t<div class=group id='svg_3'>\n",
4707       "\t\t\t\t<strong>SVG</strong>\n",
4708       "\t\t\t\t<div class=indented>\n",
4709       "\t\t\t\t\t<form>\n",
4710       "\t\t\t\t\t\t<input type=\"radio\" name='screenshotMode' value='download' id='download_3' checked> Download<br>\n",
4711       "\t\t\t\t\t\t<input type=\"radio\" name='screenshotMode' value='tab' id='tab_3' > New tab<br>\n",
4712       "\t\t\t\t\t</form>\n",
4713       "\t\t\t\t\t<button id='takeScreenshot_3'>Screenshot</button>\n",
4714       "\t\t\t\t</div>\n",
4715       "\t\t\t</div>\n",
4716       "\n",
4717       "\t\t</div>\t<!-- end of settings -->\n",
4718       "\t\t<img id='hideSettingsButton_3' class='hideSettingsButton' src='/kernelspecs/polymake/close.svg' width=20px\">\n",
4719       "\t\t<img id='showSettingsButton_3' class='showSettingsButton' src='/kernelspecs/polymake/menu.svg' width=20px\">\n",
4720       "<div id=\"model31430920245\"></div>\n",
4721       "</div>\n",
4722       "   <script>\n",
4723       "    requirejs.config({\n",
4724       "      paths: {\n",
4725       "        three: '/kernelspecs/polymake/three',\n",
4726       "        TrackballControls: '/kernelspecs/polymake/TrackballControls',\n",
4727       "        OrbitControls: '/kernelspecs/polymake/OrbitControls',\n",
4728       "        Projector: '/kernelspecs/polymake/Projector',\n",
4729       "        SVGRenderer: '/kernelspecs/polymake/SVGRenderer',\n",
4730       "        WEBGL: '/kernelspecs/polymake/WebGL',\n",
4731       "      },\n",
4732       "      shim: {\n",
4733       "        'three': { exports: 'THREE'},\n",
4734       "        'SVGRenderer': { deps: [ 'three' ], exports: 'THREE.SVGRenderer' },\n",
4735       "        'WEBGL': { deps: [ 'three' ], exports: 'THREE.WEBGL' },\n",
4736       "        'Projector': { deps: [ 'three' ], exports: 'THREE.Projector' },\n",
4737       "        'TrackballControls': { deps: [ 'three' ], exports: 'THREE.TrackballControls' },\n",
4738       "        'OrbitControls': { deps: [ 'three' ], exports: 'THREE.OrbitControls' },\n",
4739       "      }\n",
4740       "    });\n",
4741       "    \n",
4742       "    require(['three'],function(THREE){\n",
4743       "        window.THREE = THREE;\n",
4744       "      require(['TrackballControls', 'OrbitControls', 'Projector', 'SVGRenderer', 'WEBGL'],\n",
4745       "               function(TrackballControls, OrbitControls, Projector, SVGRenderer, WEBGL) {\n",
4746       "    THREE.TrackballControls = TrackballControls;\n",
4747       "    THREE.OrbitControls = OrbitControls;\n",
4748       "    THREE.Projector = Projector;\n",
4749       "    THREE.SVGRenderer = SVGRenderer;\n",
4750       "    THREE.WEBGL = WEBGL;\n",
4751       "\n",
4752       "// COMMON_CODE_BLOCK_BEGIN\n",
4753       "\n",
4754       "const intervalLength = 25; // for automatic animations\n",
4755       "const explodableModel = false; \n",
4756       "const modelContains = { points: false, pointlabels: false, lines: false, edgelabels: false, faces: false, arrowheads: false };\n",
4757       "const foldables = [];\n",
4758       "\n",
4759       "var three = document.getElementById(\"model31430920245\");\n",
4760       "var scene = new THREE.Scene();\n",
4761       "var renderer = new THREE.WebGLRenderer( { antialias: true } );\n",
4762       "var svgRenderer = new THREE.SVGRenderer( { antialias: true } );\n",
4763       "renderer.setPixelRatio( window.devicePixelRatio );\n",
4764       "renderer.setClearColor(0xFFFFFF, 1);\n",
4765       "svgRenderer.setClearColor(0xFFFFFF, 1);\n",
4766       "three.appendChild(renderer.domElement);\n",
4767       "\n",
4768       "var frustumSize = 4;\n",
4769       "var cameras = [new THREE.PerspectiveCamera(75, 1, 0.1, 1000), new THREE.OrthographicCamera()];\n",
4770       "cameras.forEach(function(cam) {\n",
4771       "    cam.position.set(0, 0, 5);\n",
4772       "    cam.lookAt(0, 0, 0);  \n",
4773       "    cam.up.set(0, 1, 0);         \n",
4774       "});\n",
4775       "var controls = [new THREE.TrackballControls(cameras[0], three), new THREE.OrbitControls(cameras[1], three)];\n",
4776       "var camera, control;\n",
4777       "\n",
4778       "controls[0].zoomSpeed = 0.2;\n",
4779       "controls[0].rotateSpeed = 4;\n",
4780       "\n",
4781       "\n",
4782       "// class to allow move points together with labels and spheres\n",
4783       "var PMPoint = function (x,y,z) {\n",
4784       "   this.vector = new THREE.Vector3(x,y,z);\n",
4785       "   this.sprite = null;\n",
4786       "   this.sphere = null;\n",
4787       "}\n",
4788       "PMPoint.prototype.addLabel = function(labelsprite) {\n",
4789       "   this.sprite = labelsprite;\n",
4790       "   this.sprite.position.copy(this.vector);\n",
4791       "}\n",
4792       "PMPoint.prototype.addSphere = function(spheremesh) {\n",
4793       "   this.sphere = spheremesh;\n",
4794       "   this.sphere.position.copy(this.vector);\n",
4795       "}\n",
4796       "PMPoint.prototype.set = function(x,y,z) {\n",
4797       "   this.vector.set(x,y,z);\n",
4798       "   if (this.sprite) {\n",
4799       "      this.sprite.position.copy(this.vector);\n",
4800       "   }\n",
4801       "   if (this.sphere) {\n",
4802       "      this.sphere.position.copy(this.vector);\n",
4803       "   }\n",
4804       "}\n",
4805       "PMPoint.prototype.radius = function() {\n",
4806       "   if (this.sphere) {\n",
4807       "      return this.sphere.geometry.parameters.radius;\n",
4808       "   } else {\n",
4809       "      return 0;\n",
4810       "   }\n",
4811       "};\n",
4812       "// select the target node\n",
4813       "var target = document.querySelector('#model31430920245');\n",
4814       "\n",
4815       "// create an observer instance\n",
4816       "var observer = new MutationObserver(function(mutations) {\n",
4817       "   mutations.forEach(function(mutation) {\n",
4818       "      if (mutation.removedNodes && mutation.removedNodes.length > 0) {\n",
4819       "         cancelAnimationFrame(renderId);\n",
4820       "         observer.disconnect();\n",
4821       "         console.log(\"cancelled frame \"+renderId);\n",
4822       "      }\n",
4823       "   });\n",
4824       "});\n",
4825       "\n",
4826       "// configuration of the observer:\n",
4827       "var config = { childList: true, characterData: true }\n",
4828       "\n",
4829       "// pass in the target node, as well as the observer options\n",
4830       "while (target) {\n",
4831       "   if (target.className==\"output\") {\n",
4832       "      observer.observe(target, config);\n",
4833       "      break;\n",
4834       "   }\n",
4835       "   target = target.parentNode;\n",
4836       "}\n",
4837       "\n",
4838       "// COMMON_CODE_BLOCK_END\n",
4839       "\n",
4840       "var obj0 = new THREE.Object3D();\n",
4841       "obj0.name = \"ilp\";\n",
4842       "obj0.userData.explodable = 1;\n",
4843       "obj0.userData.points = [];\n",
4844       "obj0.userData.points.push(new PMPoint(-1, -1, -1));\n",
4845       "obj0.userData.points.push(new PMPoint(-1, -1, 0));\n",
4846       "obj0.userData.points.push(new PMPoint(-1, 0, -1));\n",
4847       "obj0.userData.points.push(new PMPoint(-1, 0, 1));\n",
4848       "obj0.userData.points.push(new PMPoint(-1, 1, 0));\n",
4849       "obj0.userData.points.push(new PMPoint(0, -1, 0));\n",
4850       "obj0.userData.points.push(new PMPoint(0, -1, 1));\n",
4851       "obj0.userData.points.push(new PMPoint(0, 1, -1));\n",
4852       "obj0.userData.points.push(new PMPoint(0, 1, 1));\n",
4853       "obj0.userData.points.push(new PMPoint(1, 0, -1));\n",
4854       "obj0.userData.points.push(new PMPoint(1, 0, 1));\n",
4855       "obj0.userData.points.push(new PMPoint(1, 1, 0));\n",
4856       "\n",
4857       "obj0.userData.pointradii = 0.02;\n",
4858       "   <!-- Vertex style -->\n",
4859       "obj0.userData.pointmaterial = [new THREE.MeshBasicMaterial( { color: 0xFFFF00, side: THREE.DoubleSide, transparent: false } ),\n",
4860       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
4861       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
4862       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
4863       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
4864       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
4865       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
4866       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
4867       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
4868       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
4869       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ),\n",
4870       "new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } )];\n",
4871       "obj0.userData.pointlabels = [\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"11\"];\n",
4872       "obj0.userData.edgeindices = [0, 1, 0, 2, 1, 3, 2, 4, 3, 4, 0, 5, 1, 6, 3, 6, 5, 6, 2, 7, 4, 7, 3, 8, 4, 8, 0, 9, 5, 9, 7, 9, 6, 10, 8, 10, 9, 10, 7, 11, 8, 11, 9, 11, 10, 11];\n",
4873       "   <!-- Edge style -->\n",
4874       "obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
4875       "obj0.userData.facets = [[10, 6, 5, 9], [3, 6, 10, 8], [4, 3, 8], [5, 6, 1, 0], [1, 6, 3], [0, 1, 3, 4, 2], [2, 4, 7], [9, 5, 0], [9, 0, 2, 7], [11, 9, 7], [10, 11, 8], [10, 9, 11], [11, 7, 4, 8]];\n",
4876       "   <!-- Facet style -->\n",
4877       "obj0.userData.facetmaterial = [new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } ),\n",
4878       "new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } ),\n",
4879       "new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } ),\n",
4880       "new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } ),\n",
4881       "new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } ),\n",
4882       "new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } ),\n",
4883       "new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } ),\n",
4884       "new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } ),\n",
4885       "new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } ),\n",
4886       "new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } ),\n",
4887       "new THREE.MeshBasicMaterial( { color: 0xFF0000, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } ),\n",
4888       "new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } ),\n",
4889       "new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } )];\n",
4890       "init_object(obj0);\n",
4891       "scene.add(obj0);\n",
4892       "\n",
4893       "// COMMON_CODE_BLOCK_BEGIN\n",
4894       "function textSpriteMaterial(message, parameters) {\n",
4895       "    if ( parameters === undefined ) parameters = {};\n",
4896       "    var fontface = \"Helvetica\";\n",
4897       "    var fontsize = parameters.hasOwnProperty(\"fontsize\") ? parameters[\"fontsize\"] : 15;\n",
4898       "    fontsize = fontsize*10;\n",
4899       "    var lines = message.split('\\\\n');\n",
4900       "    var size = 512;\n",
4901       "    for(var i = 0; i<lines.length; i++){\n",
4902       "        var tmp = lines[i].length;\n",
4903       "        while(tmp*fontsize > size){\n",
4904       "           fontsize--;\n",
4905       "        }\n",
4906       "    }\n",
4907       "    \n",
4908       "    var canvas = document.createElement('canvas');\n",
4909       "    canvas.width = size;\n",
4910       "    canvas.height = size;\n",
4911       "    var context = canvas.getContext('2d');\n",
4912       "    context.fillStyle = \"rgba(255, 255, 255, 0)\";\n",
4913       "    context.fill();\n",
4914       "    context.font = fontsize + \"px \" + fontface;\n",
4915       "    \n",
4916       "    // text color\n",
4917       "    context.fillStyle = \"rgba(0, 0, 0, 1.0)\";\n",
4918       "     for(var i = 0; i<lines.length; i++){\n",
4919       "        context.fillText(lines[i], size/2, size/2+i*fontsize);\n",
4920       "     }\n",
4921       "    \n",
4922       "    // canvas contents will be used for a texture\n",
4923       "    var texture = new THREE.Texture(canvas);\n",
4924       "    texture.needsUpdate = true;\n",
4925       "    \n",
4926       "    var spriteMaterial = new THREE.SpriteMaterial({map: texture, depthTest: true, depthWrite: false, polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: 1 });\n",
4927       "    return spriteMaterial;\n",
4928       "}\n",
4929       "\n",
4930       "\n",
4931       "// ---------------------- INITIALIZING OBJECTS--------------------------------------\n",
4932       "// ---------------------------------------------------------------------------------\n",
4933       "\n",
4934       "function init_object(obj) {\n",
4935       "    if (obj.userData.hasOwnProperty(\"pointmaterial\")) {\n",
4936       "        init_points(obj);\n",
4937       "        modelContains.points = true;\n",
4938       "    }\n",
4939       "    if (obj.userData.hasOwnProperty(\"pointlabels\")) {\n",
4940       "        init_pointlabels(obj);\n",
4941       "        modelContains.pointlabels = true;\n",
4942       "    }\n",
4943       "    if (obj.userData.hasOwnProperty(\"edgematerial\")) {\n",
4944       "        init_lines(obj);\n",
4945       "        modelContains.lines = true;\n",
4946       "    }\n",
4947       "    if (obj.userData.hasOwnProperty(\"edgelabels\")) {\n",
4948       "        init_edgelabels(obj);\n",
4949       "        modelContains.edgelabels = true;\n",
4950       "    }\n",
4951       "    if (obj.userData.hasOwnProperty(\"arrowstyle\")) {\n",
4952       "        init_arrowheads(obj);\n",
4953       "        modelContains.arrowheads = true;\n",
4954       "    }\n",
4955       "    if (obj.userData.hasOwnProperty(\"facetmaterial\")) {\n",
4956       "        init_faces(obj);\n",
4957       "        modelContains.faces = true;\n",
4958       "    }\n",
4959       "}\n",
4960       "\n",
4961       "function init_points(obj) {\n",
4962       "    var pointgroup = new THREE.Group();\n",
4963       "    pointgroup.name = \"points\";\n",
4964       "    var points = obj.userData.points;\n",
4965       "    var radii = obj.userData.pointradii;\n",
4966       "    var materials = obj.userData.pointmaterial;\n",
4967       "    var geometry,material;\n",
4968       "    if (!Array.isArray(radii)) {\n",
4969       "        geometry = new THREE.SphereBufferGeometry(radii);  \n",
4970       "    }\n",
4971       "    if (!Array.isArray(materials)) {\n",
4972       "        material = materials;\n",
4973       "    }\n",
4974       "    for (var i=0; i<points.length; i++) {\n",
4975       "        var point = points[i];\n",
4976       "        if (Array.isArray(radii)) {\n",
4977       "            if (radii[i] == 0) {\n",
4978       "                continue;\n",
4979       "            }\n",
4980       "            geometry = new THREE.SphereBufferGeometry(radii[i]);  \n",
4981       "        } \n",
4982       "        if (Array.isArray(materials)) {\n",
4983       "            material = materials[i];     \n",
4984       "        } \n",
4985       "        var sphere = new THREE.Mesh(geometry, material);\n",
4986       "        point.addSphere(sphere);\n",
4987       "        pointgroup.add(sphere);\n",
4988       "    }\n",
4989       "    obj.add(pointgroup);\n",
4990       "}\n",
4991       "\n",
4992       "function init_pointlabels(obj) {\n",
4993       "    var points = obj.userData.points;\n",
4994       "    var labels = obj.userData.pointlabels;\n",
4995       "    var pointlabels = new THREE.Group();\n",
4996       "    pointlabels.name = \"pointlabels\";\n",
4997       "    if (Array.isArray(labels)) {\n",
4998       "        for (var i=0; i<points.length; i++) {\n",
4999       "            var point = points[i];\n",
5000       "            var spriteMaterial = textSpriteMaterial( labels[i] );\n",
5001       "\t        var sprite = new THREE.Sprite(spriteMaterial);\n",
5002       "            point.addLabel(sprite);\n",
5003       "            pointlabels.add(sprite);\n",
5004       "        }\n",
5005       "    } else {\n",
5006       "        var spriteMaterial = textSpriteMaterial( labels );\n",
5007       "        for (var i=0; i<points.length; i++) {\n",
5008       "            var point = points[i];\n",
5009       "\t        var sprite = new THREE.Sprite(spriteMaterial);\n",
5010       "            point.addLabel(sprite);\n",
5011       "            pointlabels.add(sprite);\n",
5012       "        }\n",
5013       "    }\n",
5014       "    obj.add(pointlabels);\n",
5015       "}\n",
5016       "\n",
5017       "function init_lines(obj) {\n",
5018       "    var edgeindices = obj.userData.edgeindices;\n",
5019       "    var points = obj.userData.points;\n",
5020       "    var materials = obj.userData.edgematerial;\n",
5021       "    var geometry = new THREE.BufferGeometry();\n",
5022       "    var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 );\n",
5023       "    var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 );\n",
5024       "    var geometry = new THREE.BufferGeometry();\n",
5025       "    geometry.setAttribute('position', bufattr);\n",
5026       "    if (Array.isArray(materials)) {     \n",
5027       "        for (var i=0; i<materials.length; i++) {\n",
5028       "            geometry.addGroup(2*i,2,i);\n",
5029       "        }\n",
5030       "    }\n",
5031       "    var lines = new THREE.LineSegments(geometry, materials);\n",
5032       "    lines.name = \"lines\";\n",
5033       "    obj.add(lines);\n",
5034       "    updateEdgesPosition(obj);\n",
5035       "}\n",
5036       "\n",
5037       "function init_edgelabels(obj) {\n",
5038       "    var points = obj.userData.points;\n",
5039       "    var edgeindices = obj.userData.edgeindices;\n",
5040       "    var labels = obj.userData.edgelabels;\n",
5041       "    var edgelabels = new THREE.Group();\n",
5042       "    edgelabels.name = \"edgelabels\";\n",
5043       "    if (Array.isArray(labels)) {\n",
5044       "        for (var i=0; i<edgeindices.length; i=i+2) {\n",
5045       "            var point = points[i];\n",
5046       "            var spriteMaterial = textSpriteMaterial( labels[i] );\n",
5047       "            var sprite = new THREE.Sprite(spriteMaterial);\n",
5048       "            sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5));\n",
5049       "            edgelabels.add(sprite);\n",
5050       "        }\n",
5051       "    } else {\n",
5052       "        var spriteMaterial = textSpriteMaterial( labels );\n",
5053       "        for (var i=0; i<points.length; i++) {\n",
5054       "            var point = points[i];\n",
5055       "            var sprite = new THREE.Sprite(spriteMaterial);\n",
5056       "            sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5));\n",
5057       "            pointlabels.add(sprite);\n",
5058       "        }\n",
5059       "    }\n",
5060       "    obj.add(edgelabels);\n",
5061       "}\n",
5062       "\n",
5063       "function init_arrowheads(obj) {\n",
5064       "    var arrowheads = new THREE.Group();\n",
5065       "    arrowheads.name = \"arrowheads\";\n",
5066       "    var arrowstyle = obj.userData.arrowstyle;\n",
5067       "    var edgeindices = obj.userData.edgeindices;\n",
5068       "    var edgematerials = obj.userData.edgematerial;\n",
5069       "    var points = obj.userData.points;\n",
5070       "    var material;\n",
5071       "    if (!Array.isArray(edgematerials)) {\n",
5072       "        material = new THREE.MeshBasicMaterial( {color: edgematerials.color} );\n",
5073       "    }\n",
5074       "\n",
5075       "    for (var i=0; i<edgeindices.length; i=i+2) {\n",
5076       "        var start = points[edgeindices[i]];\n",
5077       "        var end = points[edgeindices[i+1]];\n",
5078       "        var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius();\n",
5079       "        if (dist <= 0) {\n",
5080       "            continue;\n",
5081       "        }\n",
5082       "        var dir = new THREE.Vector3().subVectors(end.vector,start.vector);\n",
5083       "        dir.normalize();\n",
5084       "        var axis = new THREE.Vector3().set(dir.z,0,-dir.x);\n",
5085       "        axis.normalize();\n",
5086       "        var radians = Math.acos( dir.y );\n",
5087       "        var radius = dist/25;\n",
5088       "        var height = dist/5;\n",
5089       "        var geometry = new THREE.ConeBufferGeometry(radius,height);\n",
5090       "        var position = new THREE.Vector3().addVectors(start.vector,dir.clone().multiplyScalar(start.radius()+dist-height/2));\n",
5091       "        if (Array.isArray(edgematerials)) {\n",
5092       "            material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} );\n",
5093       "        }\n",
5094       "        var cone = new THREE.Mesh( geometry, material );\n",
5095       "        cone.quaternion.setFromAxisAngle(axis,radians);;\n",
5096       "        cone.position.copy(position);;\n",
5097       "        arrowheads.add(cone);\n",
5098       "    }\n",
5099       "    obj.add(arrowheads);\n",
5100       "}\n",
5101       "\n",
5102       "function init_faces(obj) {\n",
5103       "    var points = obj.userData.points;\n",
5104       "    var facets = obj.userData.facets;\n",
5105       "    obj.userData.triangleindices = [];\n",
5106       "    for (var i=0; i<facets.length; i++) {\n",
5107       "        facet = facets[i];\n",
5108       "        for (var t=0; t<facet.length-2; t++) {\n",
5109       "            obj.userData.triangleindices.push(facet[0],facet[t+1],facet[t+2]);  \n",
5110       "        }\n",
5111       "    }\n",
5112       "    var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 );\n",
5113       "    var bufattr = new THREE.Float32BufferAttribute(bufarr,3);\n",
5114       "    \n",
5115       "    var materials = obj.userData.facetmaterial;\n",
5116       "    var geometry = new THREE.BufferGeometry();\n",
5117       "    geometry.setAttribute('position',bufattr);\n",
5118       "    if (Array.isArray(materials)) {\n",
5119       "        var tricount = 0;\n",
5120       "        var facet;\n",
5121       "        for (var i=0; i<facets.length; i++) {\n",
5122       "            facet = facets[i];\n",
5123       "            geometry.addGroup(tricount,(facet.length-2)*3,i);\n",
5124       "            tricount += (facet.length-2)*3;\n",
5125       "        }\n",
5126       "    }\n",
5127       "    var mesh = new THREE.Mesh(geometry, materials);\n",
5128       "    mesh.name = \"faces\";\n",
5129       "    obj.add(mesh); \n",
5130       "    updateFacesPosition(obj);\n",
5131       "}\n",
5132       "// //INITIALIZING\n",
5133       "\n",
5134       "\n",
5135       "function updateFacesPosition(obj) {\n",
5136       "    var points = obj.userData.points;\n",
5137       "    var indices = obj.userData.triangleindices;\n",
5138       "    var faces = obj.getObjectByName(\"faces\");\n",
5139       "    var ba = faces.geometry.getAttribute(\"position\");\n",
5140       "    for (var i=0; i<indices.length; i++) {\n",
5141       "        ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z); \n",
5142       "    }\n",
5143       "    faces.geometry.attributes.position.needsUpdate = true;\n",
5144       "    \n",
5145       "}\n",
5146       "\n",
5147       "function updateEdgesPosition(obj) {\n",
5148       "    var points = obj.userData.points;\n",
5149       "    var indices = obj.userData.edgeindices;\n",
5150       "    var lines = obj.getObjectByName(\"lines\");\n",
5151       "    var ba = lines.geometry.getAttribute(\"position\"); \n",
5152       "    for (var i=0; i<indices.length; i++) {\n",
5153       "        ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z); \n",
5154       "    }\n",
5155       "    lines.geometry.attributes.position.needsUpdate = true;\n",
5156       "}\n",
5157       "\n",
5158       "function onWindowResize() {\n",
5159       "    renderer.setSize( three.clientWidth, three.clientHeight );\n",
5160       "    svgRenderer.setSize( three.clientWidth, three.clientHeight );\n",
5161       "    updateCamera();\n",
5162       "}\n",
5163       "\n",
5164       "function updateCamera() {\n",
5165       "    var width = three.clientWidth;\n",
5166       "    var height = three.clientHeight;\n",
5167       "    var aspect = width / height;\n",
5168       "    if (camera.type == \"OrthographicCamera\") {\n",
5169       "        camera.left = frustumSize * aspect / - 2;\n",
5170       "        camera.right = frustumSize * aspect / 2;\n",
5171       "        camera.top = frustumSize / 2;\n",
5172       "        camera.bottom = - frustumSize / 2;\n",
5173       "    } else if (camera.type == \"PerspectiveCamera\") {\n",
5174       "        camera.aspect = aspect;\n",
5175       "    }\n",
5176       "    camera.updateProjectionMatrix();\n",
5177       "}\n",
5178       "\n",
5179       "function changeCamera(event) {\n",
5180       "    var selindex = event.currentTarget.selectedIndex;\n",
5181       "    camera = cameras[selindex];\n",
5182       "    control = controls[selindex];\n",
5183       "    control.enabled = true; \n",
5184       "    for (var i=0; i<controls.length; i++) {\n",
5185       "        if (i!=selindex) {\n",
5186       "            controls[i].enabled = false;\n",
5187       "        }\n",
5188       "    }\n",
5189       "    updateCamera();\n",
5190       "}\n",
5191       "\n",
5192       "var camtypenode = document.getElementById('cameraType_3');\n",
5193       "camtypenode.onchange = changeCamera;\n",
5194       "camtypenode.dispatchEvent(new Event('change'));\n",
5195       "\n",
5196       "onWindowResize();\n",
5197       "window.addEventListener('resize', onWindowResize);\t\n",
5198       "\n",
5199       "\n",
5200       "var xRotationEnabled = false;\n",
5201       "var yRotationEnabled = false;\n",
5202       "var zRotationEnabled = false;\n",
5203       "var rotationSpeedFactor = 1;\n",
5204       "var settingsShown = false;\n",
5205       "var labelsShown = true;\n",
5206       "var intervals = [];\n",
5207       "var timeouts = [];\n",
5208       "var explodingSpeed = 0.05;\n",
5209       "var explodeScale = 0;\n",
5210       "var XMLS = new XMLSerializer();\n",
5211       "var svgElement;\n",
5212       "var renderId;\n",
5213       "\n",
5214       "var render = function () {\n",
5215       "\n",
5216       "\trenderId = requestAnimationFrame(render);\n",
5217       "\n",
5218       "//\tcomment in for automatic explosion\n",
5219       "//\texplode(updateFactor());\n",
5220       "\n",
5221       "    var phi = 0.02 * rotationSpeedFactor;\n",
5222       "\n",
5223       "    if (xRotationEnabled) {\n",
5224       "        scene.rotation.x += phi;\n",
5225       "    }\n",
5226       "    if (yRotationEnabled) {\n",
5227       "        scene.rotation.y += phi;\n",
5228       "    }\n",
5229       "    if (zRotationEnabled) {\n",
5230       "        scene.rotation.z += phi;\n",
5231       "    }\n",
5232       "\n",
5233       "    control.update();\n",
5234       "    renderer.render(scene, camera);\n",
5235       "};\n",
5236       "\n",
5237       "if ( THREE.WEBGL.isWebGLAvailable() ) {\n",
5238       "\trender();\n",
5239       "} else {\n",
5240       "\tvar warning = WEBGL.getWebGLErrorMessage();\n",
5241       "\tthree.appendChild( warning );\n",
5242       "}\n",
5243       "    \n",
5244       "function changeTransparency() {\n",
5245       "    var opacity = 1-Number(event.currentTarget.value);\n",
5246       "    for (var i=0; i<scene.children.length; i++) {\n",
5247       "        child = scene.children[i];\n",
5248       "        if ( child.userData.hasOwnProperty(\"facetmaterial\") ) {\n",
5249       "            if (Array.isArray(child.userData.facetmaterial)) {\n",
5250       "                for (var j=0; j<child.userData.facetmaterial.length; j++) {\n",
5251       "                    child.userData.facetmaterial[j].opacity = opacity;\n",
5252       "                }\n",
5253       "            } else {\n",
5254       "                child.userData.facetmaterial.opacity = opacity;\n",
5255       "            }    \n",
5256       "        }\n",
5257       "    }\n",
5258       "}\n",
5259       "\n",
5260       "function changeRotationX(event){\n",
5261       "    xRotationEnabled = event.currentTarget.checked;\n",
5262       "}\t\n",
5263       "\n",
5264       "function changeRotationY(event){\n",
5265       "    yRotationEnabled = event.currentTarget.checked;\n",
5266       "}\t\n",
5267       "\n",
5268       "function changeRotationZ(event){\n",
5269       "    zRotationEnabled = event.currentTarget.checked;\n",
5270       "}\t\n",
5271       "\n",
5272       "\n",
5273       "function changeRotationSpeedFactor(event){\n",
5274       "    rotationSpeedFactor = Number(event.currentTarget.value);\n",
5275       "}\n",
5276       "\n",
5277       "function resetScene(){\n",
5278       "    scene.rotation.set(0,0,0);\n",
5279       "    camera.position.set(0,0,5);\n",
5280       "    camera.up.set(0,1,0);\n",
5281       "}\n",
5282       "\n",
5283       "function showSettings(event){\n",
5284       "    document.getElementById('settings_3').style.visibility = 'visible';\n",
5285       "    document.getElementById('showSettingsButton_3').style.visibility = 'hidden';\n",
5286       "    document.getElementById('hideSettingsButton_3').style.visibility = 'visible';\n",
5287       "    settingsShown = true;\n",
5288       "}\n",
5289       "\n",
5290       "function hideSettings(event){\n",
5291       "    document.getElementById('settings_3').style.visibility = 'hidden';\n",
5292       "    document.getElementById('showSettingsButton_3').style.visibility = 'visible';\n",
5293       "    document.getElementById('hideSettingsButton_3').style.visibility = 'hidden';\n",
5294       "    settingsShown = false;\n",
5295       "}\n",
5296       "\n",
5297       "\n",
5298       "\n",
5299       "var pos = 150* Math.PI;\n",
5300       "\n",
5301       "function updateFactor() {\n",
5302       "    pos++;\n",
5303       "    return Math.sin(.01*pos)+1;\n",
5304       "}\n",
5305       "\n",
5306       "// ------------------------ FOLDING ------------------------------------------------\n",
5307       "// ---------------------------------------------------------------------------------\n",
5308       "// rotate point p around axis defined by points p1 and p2 by given angle\n",
5309       "function rotate(p, p1, p2, angle ){   \n",
5310       "    angle = -angle;\n",
5311       "    var x = p.x, y = p.y, z = p.z, \n",
5312       "    a = p1.x, b = p1.y, c = p1.z, \n",
5313       "    u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z;\n",
5314       "    var result = [];\n",
5315       "    var L = u*u + v*v + w*w;\n",
5316       "    var sqrt = Math.sqrt;\n",
5317       "    var cos = Math.cos;\n",
5318       "    var sin = Math.sin;\n",
5319       "\n",
5320       "    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))/L;\n",
5321       "    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))/L;\n",
5322       "    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))/L;\n",
5323       "\n",
5324       "    return result;\n",
5325       "}\n",
5326       "\n",
5327       "var fold = function(event){\n",
5328       "    var obj = foldables[Number(event.currentTarget.name)];\n",
5329       "    var foldvalue = Number(event.currentTarget.value);\n",
5330       "    var scale = foldvalue - obj.userData.oldscale;\n",
5331       "\n",
5332       "    for (var j=0; j<obj.userData.axes.length; j++) {\n",
5333       "        rotateVertices(obj, j, scale);\n",
5334       "    }\n",
5335       "    update(obj);\n",
5336       "    obj.userData.oldscale += scale;\n",
5337       "    lookAtBarycenter(obj);\n",
5338       "}\n",
5339       "\n",
5340       "function lookAtBarycenter(obj){\n",
5341       "    control.target = barycenter(obj);\n",
5342       "}\n",
5343       "\n",
5344       "function barycenter(obj) {\n",
5345       "    var center = new THREE.Vector3(0,0,0);\n",
5346       "    var points = obj.userData.points;\n",
5347       "    for (var i=0; i<points.length; i++){\n",
5348       "        center.add(points[i].vector);\n",
5349       "    }\n",
5350       "    center.divideScalar(points.length);\n",
5351       "    return center;\n",
5352       "}\n",
5353       "\n",
5354       "function rotateVertices(obj, edge, scale) {\n",
5355       "    var axes = obj.userData.axes;\n",
5356       "    var subtrees = obj.userData.subtrees;\n",
5357       "    var points = obj.userData.points;\n",
5358       "    var angles = obj.userData.angles;\n",
5359       "    if (edge < axes.length){\n",
5360       "        for (var j=0; j<subtrees[edge].length; j++){\n",
5361       "            var rotP = rotate(points[subtrees[edge][j]].vector, points[axes[edge][0]].vector,points[axes[edge][1]].vector, scale * (Math.PI - angles[edge]));\n",
5362       "            points[subtrees[edge][j]].set(rotP[0],rotP[1],rotP[2]);\n",
5363       "        }\n",
5364       "    }\n",
5365       "}\n",
5366       "\n",
5367       "function update(obj) {\n",
5368       "   updateFacesPosition(obj);\n",
5369       "   updateEdgesPosition(obj);\n",
5370       "}\n",
5371       "\n",
5372       "if (foldables.length) {\n",
5373       "    var settings = document.getElementById('settings_3');\n",
5374       "    var foldDiv = document.createElement('div');\n",
5375       "    foldDiv.id = 'fold_3';\n",
5376       "    var title = document.createElement('strong');\n",
5377       "    title.innerHTML = 'Fold';\n",
5378       "    foldDiv.appendChild(title);\n",
5379       "    foldDiv.className = 'group';\n",
5380       "    for (var i=0; i<foldables.length; i++) {\n",
5381       "        var range = document.createElement('input');\n",
5382       "        range.type = 'range';\n",
5383       "        range.min = 0;\n",
5384       "        range.max = 1;\n",
5385       "        range.value = 0;\n",
5386       "        range.step = 0.001;\n",
5387       "        range.name = String(i);\n",
5388       "        range.oninput = fold;\n",
5389       "        foldDiv.appendChild(range);\n",
5390       "    }\n",
5391       "    lookAtBarycenter(foldables[0]);\n",
5392       "    settings.insertBefore(foldDiv,settings.childNodes[0]);\n",
5393       "}\n",
5394       "\n",
5395       "    \n",
5396       "// ---------------------- EXPLOSION ------------------------------------------------\n",
5397       "// ---------------------------------------------------------------------------------\n",
5398       "\n",
5399       "if (explodableModel) {\n",
5400       "    for (var i=0; i<scene.children.length; i++) {\n",
5401       "        obj = scene.children[i];\n",
5402       "        if ( obj.userData.explodable ) {\n",
5403       "            computeCentroid(obj);\n",
5404       "        }\n",
5405       "    }\n",
5406       "    document.getElementById('explodeRange_3').oninput = triggerExplode;\n",
5407       "    document.getElementById('explodeCheckbox_3').onchange = triggerAutomaticExplode;\n",
5408       "    document.getElementById('explodingSpeedRange_3').oninput = setExplodingSpeed;\n",
5409       "}\n",
5410       "\n",
5411       "function computeCentroid(obj) {\n",
5412       "    centroid = new THREE.Vector3();\n",
5413       "    obj.userData.points.forEach(function(pmpoint) {\n",
5414       "        centroid.add(pmpoint.vector);\t\t\t\n",
5415       "    });\n",
5416       "    centroid.divideScalar(obj.userData.points.length);\n",
5417       "    obj.userData.centroid = centroid;\n",
5418       "}\n",
5419       "\n",
5420       "function explode(factor) {\n",
5421       "    for (var i=0; i<scene.children.length; i++) {\n",
5422       "        var obj = scene.children[i];\n",
5423       "        if (obj.userData.hasOwnProperty(\"centroid\")) { \n",
5424       "            var c = obj.userData.centroid;\n",
5425       "            obj.position.set(c.x*factor, c.y*factor, c.z*factor);\n",
5426       "        }\n",
5427       "    }\t\n",
5428       "}\n",
5429       "\n",
5430       "function triggerExplode(event){\n",
5431       "    explodeScale = Number(event.currentTarget.value);\n",
5432       "    explode(explodeScale);\n",
5433       "}\n",
5434       "\n",
5435       "function setExplodingSpeed(event){\n",
5436       "    explodingSpeed = Number(event.currentTarget.value);\n",
5437       "}\n",
5438       "\n",
5439       "function triggerAutomaticExplode(event){\n",
5440       "    if (event.currentTarget.checked){\n",
5441       "        startExploding();\n",
5442       "    } else {\n",
5443       "        clearIntervals();\n",
5444       "    }\t\n",
5445       "}\n",
5446       "\n",
5447       "function startExploding(){\n",
5448       "    intervals.push(setInterval(explodingInterval, 25));\n",
5449       "}\n",
5450       "\n",
5451       "\n",
5452       "function explodingInterval(){\n",
5453       "    explodeScale += explodingSpeed;\n",
5454       "    if (explodeScale <= 6){ \n",
5455       "        explode(explodeScale);\n",
5456       "    }\n",
5457       "    else{\n",
5458       "        explode(6);\n",
5459       "        explodeScale = 6;\n",
5460       "        clearIntervals();\n",
5461       "        timeouts.push(setTimeout(startUnexploding, 3000));\n",
5462       "    }\n",
5463       "    document.getElementById('explodeRange_3').value = explodeScale;\n",
5464       "}\n",
5465       "\n",
5466       "\n",
5467       "function startUnexploding(){\n",
5468       "    intervals.push(setInterval(unexplodingInterval, 25));\n",
5469       "}\n",
5470       "\n",
5471       "function unexplodingInterval(){\n",
5472       "    explodeScale -= explodingSpeed;\n",
5473       "    if (explodeScale >= 0){\t\n",
5474       "        explode(explodeScale);\n",
5475       "    }\n",
5476       "    else {\n",
5477       "        explode(0);\n",
5478       "        explodeScale = 0;\n",
5479       "        clearIntervals();\n",
5480       "        timeouts.push(setTimeout(startExploding, 3000));\n",
5481       "    }\n",
5482       "    document.getElementById('explodeRange_3').value = explodeScale;\n",
5483       "}\n",
5484       "\n",
5485       "function clearIntervals(){\n",
5486       "    intervals.forEach(function(interval){\n",
5487       "        clearInterval(interval);\n",
5488       "    });\n",
5489       "    intervals = [];\n",
5490       "    timeouts.forEach(function(timeout){\n",
5491       "        clearTimeout(timeout);\n",
5492       "    });\n",
5493       "    timeouts = [];\n",
5494       "}\n",
5495       "\n",
5496       "// ---------------------- DISPLAY --------------------------------------------------\n",
5497       "// ---------------------------------------------------------------------------------\n",
5498       "\n",
5499       "const objectTypeInnerHTMLs = { points: \"Points\", pointlabels: \"Point labels\", lines: \"Edges\", edgelabels: \"Edge labels\", faces: \"Faces\", arrowheads: \"Arrow heads\" };\n",
5500       "const objectTypeVisible = {};\n",
5501       "Object.assign(objectTypeVisible,modelContains);\n",
5502       "const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort();\n",
5503       "const shownObjectTypesList = document.getElementById('shownObjectTypesList_3');\n",
5504       "\n",
5505       "function setVisibility(bool,objname) {\n",
5506       "    for (var i=0; i<scene.children.length; i++){\n",
5507       "        var obj = scene.children[i].getObjectByName(objname);\n",
5508       "        if (obj) {\n",
5509       "            obj.visible = bool;\n",
5510       "        }\n",
5511       "    }\n",
5512       "}\n",
5513       "\n",
5514       "function toggleObjectTypeVisibility(event){\n",
5515       "    var name = event.currentTarget.name;\n",
5516       "    var checked = event.currentTarget.checked;\n",
5517       "    objectTypeVisible[name] = checked;\n",
5518       "    setVisibility(checked,name);\n",
5519       "}\n",
5520       "\n",
5521       "for (var i=0; i<sortedObjectTypeKeys.length; i++){\n",
5522       "    var key = sortedObjectTypeKeys[i];\n",
5523       "    if (modelContains[key]) {\n",
5524       "        var objTypeNode = document.createElement('span');\n",
5525       "        objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '<br>';\n",
5526       "        var checkbox = document.createElement('input');\n",
5527       "        checkbox.type = 'checkbox';\n",
5528       "        checkbox.checked = true;\n",
5529       "        checkbox.name = key;\n",
5530       "        checkbox.onchange = toggleObjectTypeVisibility;\n",
5531       "        shownObjectTypesList.appendChild(checkbox);\n",
5532       "        shownObjectTypesList.appendChild(objTypeNode);\n",
5533       "    }\n",
5534       "}\n",
5535       "\n",
5536       "// ------------------------------------------------------\n",
5537       "\n",
5538       "function toggleObjectVisibility(event){\n",
5539       "    var nr = Number(event.currentTarget.name);\n",
5540       "    scene.children[nr].visible = event.currentTarget.checked;\n",
5541       "}\n",
5542       "\n",
5543       "// append checkboxes for displaying or hiding objects\n",
5544       "var shownObjectsList = document.getElementById('shownObjectsList_3');\n",
5545       "for (var i=0; i<scene.children.length; i++){\n",
5546       "    obj = scene.children[i];\n",
5547       "    var objNode = document.createElement('span');\n",
5548       "    objNode.innerHTML = obj.name + '<br>';\n",
5549       "    var checkbox = document.createElement('input');\n",
5550       "    checkbox.type = 'checkbox';\n",
5551       "    checkbox.checked = true;\n",
5552       "    checkbox.name = String(i);\n",
5553       "    checkbox.onchange = toggleObjectVisibility;\n",
5554       "    shownObjectsList.appendChild(checkbox);\n",
5555       "    shownObjectsList.appendChild(objNode);\n",
5556       "}\n",
5557       "\n",
5558       "// ---------------------- SVG ------------------------------------------------------\n",
5559       "// ---------------------------------------------------------------------------------\n",
5560       "\n",
5561       "function takeSvgScreenshot() {\n",
5562       "    if (objectTypeVisible[\"pointlabels\"]) {\n",
5563       "        setVisibility(false,\"pointlabels\");\n",
5564       "    }\n",
5565       "    if (objectTypeVisible[\"edgelabels\"]) {\n",
5566       "        setVisibility(false,\"edgelabels\");\n",
5567       "    }\n",
5568       "    svgRenderer.render(scene,camera);\n",
5569       "    svgElement = XMLS.serializeToString(svgRenderer.domElement);\n",
5570       "    \n",
5571       "    if (objectTypeVisible[\"pointlabels\"]) {\n",
5572       "        setVisibility(true,\"pointlabels\");\n",
5573       "    }\n",
5574       "    if (objectTypeVisible[\"edgelabels\"]) {\n",
5575       "        setVisibility(true,\"edgelabels\");\n",
5576       "    }\n",
5577       "\n",
5578       "    if (document.getElementById('tab_3').checked){\n",
5579       "        //show in new tab\n",
5580       "        var myWindow = window.open(\"\",\"\");\n",
5581       "        myWindow.document.body.innerHTML = svgElement;\n",
5582       "    } else{\n",
5583       "        // download svg file \n",
5584       "        download(\"screenshot.svg\", svgElement);\n",
5585       "    }\n",
5586       "}\n",
5587       "\n",
5588       "function download(filename, text) {\n",
5589       "    var element = document.createElement('a');\n",
5590       "    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));\n",
5591       "    element.setAttribute('download', filename);\n",
5592       "\n",
5593       "    element.style.display = 'none';\n",
5594       "    document.body.appendChild(element);\n",
5595       "\n",
5596       "    element.click();\n",
5597       "\n",
5598       "    document.body.removeChild(element);\n",
5599       "}\n",
5600       "\n",
5601       "\n",
5602       "document.getElementById('transparencyRange_3').oninput = changeTransparency;\n",
5603       "document.getElementById('changeRotationX_3').onchange = changeRotationX;\n",
5604       "document.getElementById('changeRotationY_3').onchange = changeRotationY;\n",
5605       "document.getElementById('changeRotationZ_3').onchange = changeRotationZ;\n",
5606       "document.getElementById('resetButton_3').onclick = resetScene;\n",
5607       "document.getElementById('rotationSpeedRange_3').oninput = changeRotationSpeedFactor;\n",
5608       "document.getElementById('takeScreenshot_3').onclick = takeSvgScreenshot;\n",
5609       "document.getElementById('showSettingsButton_3').onclick = showSettings;\n",
5610       "document.getElementById('hideSettingsButton_3').onclick = hideSettings;\n",
5611       "\n",
5612       "\n",
5613       "// ------------------ SHORTCUTS --------------------------------------------\n",
5614       "// -------------------------------------------------------------------------\n",
5615       "\n",
5616       "/**\n",
5617       " * http://www.openjs.com/scripts/events/keyboard_shortcuts/\n",
5618       " * Version : 2.01.B\n",
5619       " * By Binny V A\n",
5620       " * License : BSD\n",
5621       " */\n",
5622       "shortcut = {\n",
5623       "\t'all_shortcuts':{},//All the shortcuts are stored in this array\n",
5624       "\t'add': function(shortcut_combination,callback,opt) {\n",
5625       "\t\t//Provide a set of default options\n",
5626       "\t\tvar default_options = {\n",
5627       "\t\t\t'type':'keydown',\n",
5628       "\t\t\t'propagate':false,\n",
5629       "\t\t\t'disable_in_input':false,\n",
5630       "\t\t\t'target':document,\n",
5631       "\t\t\t'keycode':false\n",
5632       "\t\t}\n",
5633       "\t\tif(!opt) opt = default_options;\n",
5634       "\t\telse {\n",
5635       "\t\t\tfor(var dfo in default_options) {\n",
5636       "\t\t\t\tif(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];\n",
5637       "\t\t\t}\n",
5638       "\t\t}\n",
5639       "\n",
5640       "\t\tvar ele = opt.target;\n",
5641       "\t\tif(typeof opt.target == 'string') ele = document.getElementById(opt.target);\n",
5642       "\t\tvar ths = this;\n",
5643       "\t\tshortcut_combination = shortcut_combination.toLowerCase();\n",
5644       "\n",
5645       "\t\t//The function to be called at keypress\n",
5646       "\t\tvar func = function(e) {\n",
5647       "\t\t\te = e || window.event;\n",
5648       "\t\t\t\n",
5649       "\t\t\tif(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields\n",
5650       "\t\t\t\tvar element;\n",
5651       "\t\t\t\tif(e.target) element=e.target;\n",
5652       "\t\t\t\telse if(e.srcElement) element=e.srcElement;\n",
5653       "\t\t\t\tif(element.nodeType==3) element=element.parentNode;\n",
5654       "\n",
5655       "\t\t\t\tif(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;\n",
5656       "\t\t\t}\n",
5657       "\t\n",
5658       "\t\t\t//Find Which key is pressed\n",
5659       "\t\t\tif (e.keyCode) code = e.keyCode;\n",
5660       "\t\t\telse if (e.which) code = e.which;\n",
5661       "\t\t\tvar character = String.fromCharCode(code).toLowerCase();\n",
5662       "\t\t\t\n",
5663       "\t\t\tif(code == 188) character=\",\"; //If the user presses , when the type is onkeydown\n",
5664       "\t\t\tif(code == 190) character=\".\"; //If the user presses , when the type is onkeydown\n",
5665       "\n",
5666       "\t\t\tvar keys = shortcut_combination.split(\"+\");\n",
5667       "\t\t\t//Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked\n",
5668       "\t\t\tvar kp = 0;\n",
5669       "\t\t\t\n",
5670       "\t\t\t//Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken\n",
5671       "\t\t\tvar shift_nums = {\n",
5672       "\t\t\t\t\"`\":\"~\",\n",
5673       "\t\t\t\t\"1\":\"!\",\n",
5674       "\t\t\t\t\"2\":\"@\",\n",
5675       "\t\t\t\t\"3\":\"#\",\n",
5676       "\t\t\t\t\"4\":\"$\",\n",
5677       "\t\t\t\t\"5\":\"%\",\n",
5678       "\t\t\t\t\"6\":\"^\",\n",
5679       "\t\t\t\t\"7\":\"&\",\n",
5680       "\t\t\t\t\"8\":\"*\",\n",
5681       "\t\t\t\t\"9\":\"(\",\n",
5682       "\t\t\t\t\"0\":\")\",\n",
5683       "\t\t\t\t\"-\":\"_\",\n",
5684       "\t\t\t\t\"=\":\"+\",\n",
5685       "\t\t\t\t\";\":\":\",\n",
5686       "\t\t\t\t\"'\":\"\\\"\",\n",
5687       "\t\t\t\t\",\":\"<\",\n",
5688       "\t\t\t\t\".\":\">\",\n",
5689       "\t\t\t\t\"/\":\"?\",\n",
5690       "\t\t\t\t\"\\\\\":\"|\"\n",
5691       "\t\t\t}\n",
5692       "\t\t\t//Special Keys - and their codes\n",
5693       "\t\t\tvar special_keys = {\n",
5694       "\t\t\t\t'esc':27,\n",
5695       "\t\t\t\t'escape':27,\n",
5696       "\t\t\t\t'tab':9,\n",
5697       "\t\t\t\t'space':32,\n",
5698       "\t\t\t\t'return':13,\n",
5699       "\t\t\t\t'enter':13,\n",
5700       "\t\t\t\t'backspace':8,\n",
5701       "\t\n",
5702       "\t\t\t\t'scrolllock':145,\n",
5703       "\t\t\t\t'scroll_lock':145,\n",
5704       "\t\t\t\t'scroll':145,\n",
5705       "\t\t\t\t'capslock':20,\n",
5706       "\t\t\t\t'caps_lock':20,\n",
5707       "\t\t\t\t'caps':20,\n",
5708       "\t\t\t\t'numlock':144,\n",
5709       "\t\t\t\t'num_lock':144,\n",
5710       "\t\t\t\t'num':144,\n",
5711       "\t\t\t\t\n",
5712       "\t\t\t\t'pause':19,\n",
5713       "\t\t\t\t'break':19,\n",
5714       "\t\t\t\t\n",
5715       "\t\t\t\t'insert':45,\n",
5716       "\t\t\t\t'home':36,\n",
5717       "\t\t\t\t'delete':46,\n",
5718       "\t\t\t\t'end':35,\n",
5719       "\t\t\t\t\n",
5720       "\t\t\t\t'pageup':33,\n",
5721       "\t\t\t\t'page_up':33,\n",
5722       "\t\t\t\t'pu':33,\n",
5723       "\t\n",
5724       "\t\t\t\t'pagedown':34,\n",
5725       "\t\t\t\t'page_down':34,\n",
5726       "\t\t\t\t'pd':34,\n",
5727       "\t\n",
5728       "\t\t\t\t'left':37,\n",
5729       "\t\t\t\t'up':38,\n",
5730       "\t\t\t\t'right':39,\n",
5731       "\t\t\t\t'down':40,\n",
5732       "\t\n",
5733       "\t\t\t\t'f1':112,\n",
5734       "\t\t\t\t'f2':113,\n",
5735       "\t\t\t\t'f3':114,\n",
5736       "\t\t\t\t'f4':115,\n",
5737       "\t\t\t\t'f5':116,\n",
5738       "\t\t\t\t'f6':117,\n",
5739       "\t\t\t\t'f7':118,\n",
5740       "\t\t\t\t'f8':119,\n",
5741       "\t\t\t\t'f9':120,\n",
5742       "\t\t\t\t'f10':121,\n",
5743       "\t\t\t\t'f11':122,\n",
5744       "\t\t\t\t'f12':123\n",
5745       "\t\t\t}\n",
5746       "\t\n",
5747       "\t\t\tvar modifiers = { \n",
5748       "\t\t\t\tshift: { wanted:false, pressed:false},\n",
5749       "\t\t\t\tctrl : { wanted:false, pressed:false},\n",
5750       "\t\t\t\talt  : { wanted:false, pressed:false},\n",
5751       "\t\t\t\tmeta : { wanted:false, pressed:false}\t//Meta is Mac specific\n",
5752       "\t\t\t};\n",
5753       "                        \n",
5754       "\t\t\tif(e.ctrlKey)\tmodifiers.ctrl.pressed = true;\n",
5755       "\t\t\tif(e.shiftKey)\tmodifiers.shift.pressed = true;\n",
5756       "\t\t\tif(e.altKey)\tmodifiers.alt.pressed = true;\n",
5757       "\t\t\tif(e.metaKey)   modifiers.meta.pressed = true;\n",
5758       "                        \n",
5759       "\t\t\tfor(var i=0; k=keys[i],i<keys.length; i++) {\n",
5760       "\t\t\t\t//Modifiers\n",
5761       "\t\t\t\tif(k == 'ctrl' || k == 'control') {\n",
5762       "\t\t\t\t\tkp++;\n",
5763       "\t\t\t\t\tmodifiers.ctrl.wanted = true;\n",
5764       "\n",
5765       "\t\t\t\t} else if(k == 'shift') {\n",
5766       "\t\t\t\t\tkp++;\n",
5767       "\t\t\t\t\tmodifiers.shift.wanted = true;\n",
5768       "\n",
5769       "\t\t\t\t} else if(k == 'alt') {\n",
5770       "\t\t\t\t\tkp++;\n",
5771       "\t\t\t\t\tmodifiers.alt.wanted = true;\n",
5772       "\t\t\t\t} else if(k == 'meta') {\n",
5773       "\t\t\t\t\tkp++;\n",
5774       "\t\t\t\t\tmodifiers.meta.wanted = true;\n",
5775       "\t\t\t\t} else if(k.length > 1) { //If it is a special key\n",
5776       "\t\t\t\t\tif(special_keys[k] == code) kp++;\n",
5777       "\t\t\t\t\t\n",
5778       "\t\t\t\t} else if(opt['keycode']) {\n",
5779       "\t\t\t\t\tif(opt['keycode'] == code) kp++;\n",
5780       "\n",
5781       "\t\t\t\t} else { //The special keys did not match\n",
5782       "\t\t\t\t\tif(character == k) kp++;\n",
5783       "\t\t\t\t\telse {\n",
5784       "\t\t\t\t\t\tif(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase\n",
5785       "\t\t\t\t\t\t\tcharacter = shift_nums[character]; \n",
5786       "\t\t\t\t\t\t\tif(character == k) kp++;\n",
5787       "\t\t\t\t\t\t}\n",
5788       "\t\t\t\t\t}\n",
5789       "\t\t\t\t}\n",
5790       "\t\t\t}\n",
5791       "\t\t\t\n",
5792       "\t\t\tif(kp == keys.length && \n",
5793       "\t\t\t\t\t\tmodifiers.ctrl.pressed == modifiers.ctrl.wanted &&\n",
5794       "\t\t\t\t\t\tmodifiers.shift.pressed == modifiers.shift.wanted &&\n",
5795       "\t\t\t\t\t\tmodifiers.alt.pressed == modifiers.alt.wanted &&\n",
5796       "\t\t\t\t\t\tmodifiers.meta.pressed == modifiers.meta.wanted) {\n",
5797       "\t\t\t\tcallback(e);\n",
5798       "\t\n",
5799       "\t\t\t\tif(!opt['propagate']) { //Stop the event\n",
5800       "\t\t\t\t\t//e.cancelBubble is supported by IE - this will kill the bubbling process.\n",
5801       "\t\t\t\t\te.cancelBubble = true;\n",
5802       "\t\t\t\t\te.returnValue = false;\n",
5803       "\t\n",
5804       "\t\t\t\t\t//e.stopPropagation works in Firefox.\n",
5805       "\t\t\t\t\tif (e.stopPropagation) {\n",
5806       "\t\t\t\t\t\te.stopPropagation();\n",
5807       "\t\t\t\t\t\te.preventDefault();\n",
5808       "\t\t\t\t\t}\n",
5809       "\t\t\t\t\treturn false;\n",
5810       "\t\t\t\t}\n",
5811       "\t\t\t}\n",
5812       "\t\t}\n",
5813       "\t\tthis.all_shortcuts[shortcut_combination] = {\n",
5814       "\t\t\t'callback':func, \n",
5815       "\t\t\t'target':ele, \n",
5816       "\t\t\t'event': opt['type']\n",
5817       "\t\t};\n",
5818       "\t\t//Attach the function with the event\n",
5819       "\t\tif(ele.addEventListener) ele.addEventListener(opt['type'], func, false);\n",
5820       "\t\telse if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);\n",
5821       "\t\telse ele['on'+opt['type']] = func;\n",
5822       "\t},\n",
5823       "\n",
5824       "\t//Remove the shortcut - just specify the shortcut and I will remove the binding\n",
5825       "\t'remove':function(shortcut_combination) {\n",
5826       "\t\tshortcut_combination = shortcut_combination.toLowerCase();\n",
5827       "\t\tvar binding = this.all_shortcuts[shortcut_combination];\n",
5828       "\t\tdelete(this.all_shortcuts[shortcut_combination])\n",
5829       "\t\tif(!binding) return;\n",
5830       "\t\tvar type = binding['event'];\n",
5831       "\t\tvar ele = binding['target'];\n",
5832       "\t\tvar callback = binding['callback'];\n",
5833       "\n",
5834       "\t\tif(ele.detachEvent) ele.detachEvent('on'+type, callback);\n",
5835       "\t\telse if(ele.removeEventListener) ele.removeEventListener(type, callback, false);\n",
5836       "\t\telse ele['on'+type] = false;\n",
5837       "\t}\n",
5838       "}\n",
5839       "\n",
5840       "shortcut.add(\"Alt+Left\",function() {\n",
5841       "\tvar event = new Event('click');\n",
5842       "\tif (settingsShown){\n",
5843       "\t\tdocument.getElementById('hideSettingsButton_3').dispatchEvent(event);\n",
5844       "\t} else {\n",
5845       "\t\tdocument.getElementById('showSettingsButton_3').dispatchEvent(event);\n",
5846       "\t}\n",
5847       "});\n",
5848       "\n",
5849       "\n",
5850       "// COMMON_CODE_BLOCK_END\n",
5851       "\n",
5852       "});});\n",
5853       "      </script>\n",
5854       "   </body>\n",
5855       "</html>"
5856      ]
5857     },
5858     "metadata": {},
5859     "output_type": "display_data"
5860    }
5861   ],
5862   "source": [
5863    "$ilp->VISUAL->MIN_MAX_FACE;"
5864   ]
5865  },
5866  {
5867   "cell_type": "markdown",
5868   "metadata": {},
5869   "source": [
5870    "\n",
5871    "Hence the LP attains its maximal value 2 on the  2-face spanned by the vertices 6, 9 and 10.\n",
5872    "\n",
5873    "`polymake` can visualise the polytope and highlight both its maximal and minimal face in a different (by default admittedly almost painful ;-) ) colour. Here you see the maximal face `{6 9 10}` in red and the minimal face `{0 3}` (on the opposite side of the polytope) in yellow.\n",
5874    "\n",
5875    "\n",
5876    "Note though that since we started out with a random polytope these results may vary if we perform the same computations another time on a different random polytope.\n",
5877    "\n",
5878    "    \n"
5879   ]
5880  },
5881  {
5882   "cell_type": "code",
5883   "execution_count": 20,
5884   "metadata": {},
5885   "outputs": [
5886    {
5887     "data": {
5888      "text/plain": [
5889       "1 -1 -1 -1\n",
5890       "1 -1 -1 0\n",
5891       "1 -1 0 -1\n",
5892       "1 -1 0 1\n",
5893       "1 -1 1 0\n",
5894       "1 0 -1 0\n",
5895       "1 0 -1 1\n",
5896       "1 0 1 -1\n",
5897       "1 0 1 1\n",
5898       "1 1 0 -1\n",
5899       "1 1 0 1\n",
5900       "1 1 1 0\n"
5901      ]
5902     },
5903     "execution_count": 20,
5904     "metadata": {},
5905     "output_type": "execute_result"
5906    }
5907   ],
5908   "source": [
5909    "print $ilp->VERTICES;"
5910   ]
5911  },
5912  {
5913   "cell_type": "markdown",
5914   "metadata": {},
5915   "source": [
5916    "\n",
5917    "### Hilbert bases\n",
5918    "\n",
5919    "Finally, we can have `polymake` compute and print a Hilbert basis for the cone spanned by `$ilp`.  Notice that this requires normaliz or 4ti2 to be installed in order to work.\n",
5920    "\n",
5921    "    \n"
5922   ]
5923  },
5924  {
5925   "cell_type": "code",
5926   "execution_count": 21,
5927   "metadata": {},
5928   "outputs": [
5929    {
5930     "data": {
5931      "text/plain": [
5932       "1 -1 -1 -1\n",
5933       "1 -1 -1 0\n",
5934       "1 -1 0 -1\n",
5935       "1 -1 0 0\n",
5936       "1 -1 0 1\n",
5937       "1 -1 1 0\n",
5938       "1 0 -1 0\n",
5939       "1 0 -1 1\n",
5940       "1 0 0 -1\n",
5941       "1 0 0 0\n",
5942       "1 0 0 1\n",
5943       "1 0 1 -1\n",
5944       "1 0 1 0\n",
5945       "1 0 1 1\n",
5946       "1 1 0 -1\n",
5947       "1 1 0 0\n",
5948       "1 1 0 1\n",
5949       "1 1 1 0\n"
5950      ]
5951     },
5952     "execution_count": 21,
5953     "metadata": {},
5954     "output_type": "execute_result"
5955    },
5956    {
5957     "data": {
5958      "text/html": [
5959       "<details><summary><pre style=\"display:inline\"><small>Click here for additional output</small></pre></summary>\n",
5960       "<pre>\n",
5961       "polymake: used package libnormaliz\n",
5962       "  [[wiki:external_software#Normaliz]] is a tool for computations in affine monoids, vector configurations, lattice polytopes, and rational cones.\n",
5963       "  Copyright by Winfried Bruns, Bogdan Ichim, Christof Soeger.\n",
5964       "  http://www.math.uos.de/normaliz/\n",
5965       "\n",
5966       "</pre>\n",
5967       "</details>\n"
5968      ]
5969     },
5970     "metadata": {},
5971     "output_type": "display_data"
5972    }
5973   ],
5974   "source": [
5975    "print $ilp->HILBERT_BASIS;"
5976   ]
5977  }
5978 ],
5979 "metadata": {
5980  "kernelspec": {
5981   "display_name": "polymake",
5982   "language": "polymake",
5983   "name": "polymake"
5984  },
5985  "language_info": {
5986   "codemirror_mode": "perl",
5987   "file_extension": ".pl",
5988   "mimetype": "text/x-polymake",
5989   "name": "polymake"
5990  }
5991 },
5992 "nbformat": 4,
5993 "nbformat_minor": 2
5994}
5995