Browse Source

first commit on the 1MW solar field.

Signed-off-by: Nicholas Tan Jerome <nicholas.jerome@kit.edu>
Nicholas Tan Jerome 7 years ago
parent
commit
27c6477a04
8 changed files with 3814 additions and 96 deletions
  1. 6 6
      core.py
  2. 1813 0
      index.html
  3. 1034 0
      static/OrbitControls.js
  4. BIN
      static/compass.png
  5. BIN
      static/needle.png
  6. 185 0
      static/scripts.js
  7. 248 90
      static/style.css
  8. 528 0
      static/three.min.js

+ 6 - 6
core.py

@@ -99,12 +99,12 @@ def fetchDataADEI():
         #print data
 
         last_value = data.split(",")[-1].strip()
-	try:
+        try:
             print last_value
             test_x = float(last_value)
         except ValueError:
             last_value = ""
- 	print last_value
+ 	    print last_value
         cache_data[param] = last_value
         #current_timestamp = strftime("%Y-%m-%d %H:%M:%S", gmtime())
         current_timestamp = strftime("%Y-%m-%d %H:%M:%S")
@@ -250,19 +250,19 @@ class StatusHandler(tornado.web.RequestHandler):
         #    return
 
         data = {
-            "style": style_data,
+            #"style": style_data,
             "varname": varname_data
         }
        
-        if "background" in config:
-            data["background"] = config["background"]    
+        #if "background" in config:
+        #    data["background"] = config["background"]    
         
         if "title" in config:
             data["title"] = config["title"]
         else:
             data["title"] = "BORA"
  
-        self.render('status.html', data=data)
+        self.render('index.html', data=data)
 
 
 class AdeiKatrinHandler(tornado.web.RequestHandler):

+ 1813 - 0
index.html

@@ -0,0 +1,1813 @@
+<!doctype html>
+
+<html lang="en">
+<head>
+  <meta charset="utf-8">
+  <title>The Vault GUI</title>
+
+  <link rel="stylesheet" href="{{ static_url("style.css") }}">
+  <link rel="stylesheet" href="//code.jquery.com/ui/1.12.0/themes/base/jquery-ui.css">
+  <!--[if lt IE 9]>
+    <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
+  <![endif]-->
+</head>
+
+<body>
+    <div id="container"></div>
+    <!--<div id="slider"></div>-->
+    <div id="slider-tooltip">123456</div>
+    <div id="obj-tooltip">12345</div>
+    <div id="val-tooltip">12345</div>
+    <div class="window-item window-unitem" id="message">
+        <div class="bar-header">
+            <div class="bar-title noselect">Message Log</div>
+            
+            <div class="bar-dropdown noselect">^</div>
+            <div class="bar-close noselect">&#215;</div>
+        </div>
+        <div class="bar-message">
+            <div class="bar-wrapper" style="height:200px; overflow-y:scroll;">
+            </div>
+        </div>
+    </div>
+    
+    <!--
+    <div class="window-item window-unitem" id="settings">
+        <div class="bar-header">
+            <div class="bar-title noselect">Settings</div>
+            
+            <div class="bar-dropdown noselect">^</div>
+            <div class="bar-close noselect">&#215;</div>
+        </div>
+        <div class="bar-settings">
+            <div class="bar-wrapper">
+                <div class="bar-setup">
+                    <span class="bl bar-hl">Start time</span>
+                    <span class="br bar-info">
+                        <input id="start_time" class="jscolor" value="1472688000">
+                    </span>
+                </div>
+                <div class="bar-setup">
+                    <span class="bl bar-hl">End time</span>
+                    <span class="br bar-info">
+                        <input id="end_time" class="jscolor" value="1472774400">
+                    </span>
+                </div>
+            </div>
+        </div>
+    </div>
+    -->
+    
+    <div class="window-item" id="orientation">
+        <div class="bar-header">
+            <div class="bar-title noselect">Orientation</div>
+            
+            <div class="bar-dropdown noselect">^</div>
+            <div class="bar-close noselect">&#215;</div>
+        </div>
+        <div class="bar-orientation">
+            <canvas class="bar-wrapper" id="compass" width="200" height="180"></canvas>
+        </div>
+    </div>
+    
+    
+    <div id="window-tab">
+        <div id="offMessage" class="noselect bar-pil">Message Log</div>
+        <div id="offOrientation" class="noselect bar-pil">Orientation</div>
+        <!--<div id="offSettings" class="noselect bar-pil">Settings</div>-->
+    </div>
+    
+    <div class="window-cp" id="control-panel">
+        <div class="bar-header">
+            <div id="toggleGUI" class="bar-button noselect">Show/Hide GUI</div>
+            <div id="showTabs" class="bar-button noselect">Windows</div>
+            <!--<div id="runSimulation" class="bar-button noselect">Run</div>-->
+            <!---
+            <div id="testTrigger" class="bar-button noselect">Test Trigger</div>
+            -->
+        </div>
+    </div>
+
+    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
+    <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
+    <script src="{{ static_url("scripts.js") }}"></script>
+    <script src="{{ static_url("three.min.js") }}"></script>
+    <script src="{{ static_url("OrbitControls.js") }}"></script>
+    <script>
+        // Global variable
+        var img = null,
+	        needle = null,
+	        ctx = null;
+
+        function clearCanvas() {
+	        // clear canvas
+	        ctx.clearRect(0, 0, 200, 200);
+        }
+
+        function draw(degrees) {
+            //console.log("Draw degree");
+            //console.log(degrees);
+
+	        clearCanvas();
+
+	        // Draw the compass onto the canvas
+	        ctx.drawImage(img, 0, 0);
+
+	        // Save the current drawing state
+	        ctx.save();
+
+	        // Now move across and down half the 
+	        ctx.translate(100, 100);
+
+	        // Rotate around this point
+	        ctx.rotate(degrees * (Math.PI / 180));
+
+	        // Draw the image back and up
+	        ctx.drawImage(needle, -100, -100);
+
+	        // Restore the previous drawing state
+	        ctx.restore();
+
+	        // Increment the angle of the needle by 5 degrees
+	        //degrees += 5;
+        }
+
+        function imgLoaded() {
+	        // Image loaded event complete.  Start the timer
+            draw(myvalue);
+	        //setInterval(draw, 100);
+        }
+
+        function init() {
+	        // Grab the compass element
+	        var canvas = document.getElementById('compass');
+
+	        // Canvas supported?
+	        if (canvas.getContext('2d')) {
+		        ctx = canvas.getContext('2d');
+
+		        // Load the needle image
+		        needle = new Image();
+		        needle.src = 'http://katrin.kit.edu/static/needle.png';
+
+		        // Load the compass image
+		        img = new Image();
+		        img.src = 'http://katrin.kit.edu/static/compass.png';
+		        img.onload = imgLoaded;
+	        } else {
+		        alert("Canvas not supported!");
+	        }
+        }
+    
+        var myvalue = 0;
+        init();
+        
+        
+    </script>
+    <script>
+        var camera, scene, renderer;
+        var container;
+        var mycontrol;
+        var enableControls = true;
+        var pv001;
+        var data;
+        var raycaster = new THREE.Raycaster();
+        var mouse = new THREE.Vector2();
+
+        function onMouseMove( event ) {
+	        // calculate mouse position in normalized device coordinates
+	        // (-1 to +1) for both components
+	        mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
+	        mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;		
+        }
+
+
+        init();
+        animate();
+        window.addEventListener( 'mousemove', onMouseMove, false );
+
+        function init() {
+            setMessage("3D", "Initialization.");
+            scene = new THREE.Scene();
+                
+            camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
+            camera.position.set(0, 45, 100);
+            camera.lookAt(scene.position);
+
+            container = document.getElementById( 'container' );
+            document.body.appendChild( container );
+            renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
+            renderer.setSize(window.innerWidth, window.innerHeight);
+            renderer.setClearColor( 0xffffff, 0);
+            container.appendChild(renderer.domElement);
+
+            mycontrol = new THREE.OrbitControls( camera );
+
+            var size = 40, step = 1;
+                
+            var geometry = new THREE.Geometry();
+            var material = new THREE.LineBasicMaterial({color: 0xe3e3e3, linewidth: 1, fog:true});
+
+            for ( var i = - size; i <= size; i += step ) {
+                geometry.vertices.push(new THREE.Vector3( -size, -0.04, i ));
+                geometry.vertices.push(new THREE.Vector3( size, -0.04, i ));
+                    
+                geometry.vertices.push(new THREE.Vector3( i, -0.04, -size ));
+                geometry.vertices.push(new THREE.Vector3( i, -0.04, size ));
+            }
+            var line = new THREE.LineSegments( geometry, material );
+            scene.add(line);
+            
+            setMessage("3D", "Added grid plane.");
+            /*
+            var geometry = new THREE.BoxGeometry( 1, 1, 1 );
+            var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
+            var cube = new THREE.Mesh( geometry, material );
+            */
+                
+            var light = new THREE.DirectionalLight( 0xffffff );
+            light.position.set( 0, 1, 1 ).normalize();
+            scene.add(light);
+            setMessage("3D", "Added directional light.");
+                
+            pv001 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv001.position.set(-18, 0.5, 29);
+            pv001.rotateY( Math.PI / 3 );
+            pv001.name = "2A_15_60e_001";
+            scene.add(pv001);
+            setMessage("3D", "Loaded PV001.");
+
+            pv002 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv002.position.set(-14, 0.5, 30);
+            pv002.rotateY( Math.PI / 3 );
+            pv002.name = "5A_15_60e_002";
+            scene.add(pv002);
+            setMessage("3D", "Loaded PV002.");
+
+            pv003 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv003.position.set(9.5, 0.5, 2);
+            pv003.rotateY( Math.PI / 3 );
+            pv003.name = "6A_30_60e_003";
+            scene.add(pv003);
+            setMessage("3D", "Loaded PV003.");
+
+            pv004 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv004.position.set(6, 0.5, 1);
+            pv004.rotateY( Math.PI / 3 );
+            pv004.name = "1A_30_60e_004";
+            scene.add(pv004);
+            setMessage("3D", "Loaded PV004.");
+
+            pv005 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv005.position.set(-8, 0.5, -3);
+            pv005.rotateY( Math.PI / 3 );
+            pv005.name = "6A_45_60e_005";
+            scene.add(pv005);
+            setMessage("3D", "Loaded PV005.");
+
+            pv006 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv006.position.set(-4.5, 0.5, -2);
+            pv006.rotateY( Math.PI / 3 );
+            pv006.name = "1A_45_60e_006";
+            scene.add(pv006);
+            setMessage("3D", "Loaded PV006.");
+
+            pv007 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv007.position.set(-5, 0.5, -16);
+            pv007.rotateY( Math.PI / 3 );
+            pv007.name = "6C_60_60e_007";
+            scene.add(pv007);
+            setMessage("3D", "Loaded PV007.");
+
+            pv008 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv008.position.set(-7, 0.5, -9);
+            pv008.rotateY( Math.PI / 3 );
+            pv008.name = "1C_60_60e_008";
+            scene.add(pv008);
+            setMessage("3D", "Loaded PV008.");
+
+            pv009 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv009.position.set(13, 0.5, 3);
+            pv009.rotateY( Math.PI / 4 );
+            pv009.name = "2A_15_45e_009";
+            scene.add(pv009);
+            setMessage("3D", "Loaded PV009.");
+
+            pv010 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv010.position.set(18, 0.5, 4);
+            pv010.rotateY( Math.PI / 4 );
+            pv010.name = "1A_15_45e_010";
+            scene.add(pv010);
+            setMessage("3D", "Loaded PV010.");
+
+            pv011 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv011.position.set(3.5, 0.5, -0.5);
+            pv011.rotateY( Math.PI / 4 );
+            pv011.name = "4A_15_45e_011";
+            scene.add(pv011);
+            setMessage("3D", "Loaded PV011.");
+
+            pv012 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv012.position.set(17, 0.5, -1);
+            pv012.rotateY( Math.PI / 4 );
+            pv012.name = "6A_30_45e_012";
+            scene.add(pv012);
+            setMessage("3D", "Loaded PV012.");
+
+            pv013 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv013.position.set(-2, 0.5, -1);
+            pv013.rotateY( Math.PI / 4 );
+            pv013.name = "2A_30_45e_013";
+            scene.add(pv013);
+            setMessage("3D", "Loaded PV013.");
+
+            pv014 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv014.position.set(9, 0.5, -3);
+            pv014.rotateY( Math.PI / 4 );
+            pv014.name = "2A_45_45e_014";
+            scene.add(pv014);
+            setMessage("3D", "Loaded PV014.");
+
+            pv015 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv015.position.set(12.5, 0.5, -2);
+            pv015.rotateY( Math.PI / 4 );
+            pv015.name = "4A_45_45e_015";
+            scene.add(pv015);
+            setMessage("3D", "Loaded PV015.");
+
+            pv016 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv016.position.set(-1, 0.5, -22);
+            pv016.rotateY( Math.PI / 4 );
+            pv016.name = "6A_60_45e_016";
+            scene.add(pv016);
+            setMessage("3D", "Loaded PV016.");
+
+            pv017 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv017.position.set(-2, 0.5, -26);
+            pv017.rotateY( Math.PI / 4 );
+            pv017.name = "2A_60_45e_017";
+            scene.add(pv017);
+            setMessage("3D", "Loaded PV017.");
+
+            pv018 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv018.position.set(-8.5, 0.5, 23);
+            pv018.rotateY( Math.PI / 6 );
+            pv018.name = "3A_15_30e_018";
+            scene.add(pv018);
+            setMessage("3D", "Loaded PV018.");
+
+            pv019 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv019.position.set(-10, 0.5, 26.5);
+            pv019.rotateY( Math.PI / 6 );
+            pv019.name = "1A_15_30e_019";
+            scene.add(pv019);
+            setMessage("3D", "Loaded PV019.");
+
+            pv020 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv020.position.set(6, 0.5, 14);
+            pv020.rotateY( Math.PI / 6 );
+            pv020.name = "1B_15_30e_020";
+            scene.add(pv020);
+            setMessage("3D", "Loaded PV020.");
+
+            pv021 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv021.position.set(12, 0.5, 19);
+            pv021.rotateY( Math.PI / 6 );
+            pv021.name = "1D_15_30e_021";
+            scene.add(pv021);
+            setMessage("3D", "Loaded PV021.");
+
+            pv022 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv022.position.set(6, 0.5, 17);
+            pv022.rotateY( Math.PI / 6 );
+            pv022.name = "1C_15_30e_022";
+            scene.add(pv022);
+            setMessage("3D", "Loaded PV022.");
+
+            pv023 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv023.position.set(9, 0.5, 18);
+            pv023.rotateY( Math.PI / 6 );
+            pv023.name = "5A_15_30e_023";
+            scene.add(pv023);
+            setMessage("3D", "Loaded PV023.");
+
+            pv024 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv024.position.set(-16, 0.5, 24);
+            pv024.rotateY( Math.PI / 6 );
+            pv024.name = "6D_30_30e_024";
+            scene.add(pv024);
+            setMessage("3D", "Loaded PV024.");
+
+            pv025 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv025.position.set(-15, 0.5, 26);
+            pv025.rotateY( Math.PI / 6 );
+            pv025.name = "3D_30_30e_025";
+            scene.add(pv025);
+            setMessage("3D", "Loaded PV025.");
+
+            pv026 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv026.position.set(1.5, 0.5, -7.5);
+            pv026.rotateY( Math.PI / 6 );
+            pv026.name = "6A_45_30e_026";
+            scene.add(pv026);
+            setMessage("3D", "Loaded PV026.");
+
+            pv027 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv027.position.set(-3, 0.5, -8.5);
+            pv027.rotateY( Math.PI / 6 );
+            pv027.name = "3A_45_30e_027";
+            scene.add(pv027);
+            setMessage("3D", "Loaded PV027.");
+
+            pv028 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv028.position.set(3, 0.5, -4.5);
+            pv028.rotateY( Math.PI / 6 );
+            pv028.name = "1A_45_30e_028";
+            scene.add(pv028);
+            setMessage("3D", "Loaded PV028.");
+
+            pv029 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv029.position.set(3, 0.5, -25);
+            pv029.rotateY( Math.PI / 6 );
+            pv029.name = "6A_60_30e_029";
+            scene.add(pv029);
+            setMessage("3D", "Loaded PV029.");
+
+            pv030 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv030.position.set(1, 0.5, -13);
+            pv030.rotateY( Math.PI / 6 );
+            pv030.name = "3A_60_30e_030";
+            scene.add(pv030);
+            setMessage("3D", "Loaded PV030.");
+
+            pv031 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv031.position.set(0, 0.5, -16);
+            pv031.rotateY( Math.PI / 6 );
+            pv031.name = "1A_60_30e_031";
+            scene.add(pv031);
+            setMessage("3D", "Loaded PV031.");
+
+            pv032 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv032.position.set(7, 0.5, 10.5);
+            pv032.rotateY( Math.PI / 12 );
+            pv032.name = "3A_15_15e_032";
+            scene.add(pv032);
+            setMessage("3D", "Loaded PV032.");
+
+            pv033 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv033.position.set(-10, 0.5, 29.5);
+            pv033.rotateY( Math.PI / 12 );
+            pv033.name = "1B_15_15e_033";
+            scene.add(pv033);
+            setMessage("3D", "Loaded PV033.");
+            
+            pv034 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv034.position.set(-11, 0.5, 31.5);
+            pv034.rotateY( Math.PI / 12 );
+            pv034.name = "4B_15_15e_034";
+            scene.add(pv034);
+            setMessage("3D", "Loaded PV034.");
+
+            pv035 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv035.position.set(-13, 0.5, 19);
+            pv035.rotateY( Math.PI / 12 );
+            pv035.name = "3A_30_15e_035";
+            scene.add(pv035);
+            setMessage("3D", "Loaded PV035.");
+
+            pv036 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv036.position.set(-13, 0.5, 21);
+            pv036.rotateY( Math.PI / 12 );
+            pv036.name = "1A_30_15e_036";
+            scene.add(pv036);
+            setMessage("3D", "Loaded PV036.");
+
+            pv037 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv037.position.set(-7, 0.5, 20);
+            pv037.rotateY( Math.PI / 12 );
+            pv037.name = "5A_30_15e_037";
+            scene.add(pv037);
+            setMessage("3D", "Loaded PV037.");
+
+            pv038 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv038.position.set(8, 0.5, -14);
+            pv038.rotateY( Math.PI / 12 );
+            pv038.name = "3A_45_15e_038";
+            scene.add(pv038);
+            setMessage("3D", "Loaded PV038.");
+
+            pv039 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv039.position.set(8, 0.5, -10);
+            pv039.rotateY( Math.PI / 12 );
+            pv039.name = "1A_45_15e_039";
+            scene.add(pv039);
+            setMessage("3D", "Loaded PV039.");
+
+            pv040 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv040.position.set(9, 0.5, -6.5);
+            pv040.rotateY( Math.PI / 12 );
+            pv040.name = "4A_45_15e_040";
+            scene.add(pv040);
+            setMessage("3D", "Loaded PV040.");
+
+            pv041 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv041.position.set(4, 0.5, -20.5);
+            pv041.rotateY( Math.PI / 12 );
+            pv041.name = "6A_60_15e_041";
+            scene.add(pv041);
+            setMessage("3D", "Loaded PV041.");
+
+            pv042 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv042.position.set(9, 0.5, -22);
+            pv042.rotateY( Math.PI / 12 );
+            pv042.name = "3A_60_15e_042";
+            scene.add(pv042);
+            setMessage("3D", "Loaded PV042.");
+
+            pv043 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv043.position.set(8, 0.5, -17.5);
+            pv043.rotateY( Math.PI / 12 );
+            pv043.name = "1A_60_15e_043";
+            scene.add(pv043);
+            setMessage("3D", "Loaded PV043.");
+
+            pv044 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv044.position.set(2, 0.5, 33);
+            pv044.rotateY( Math.PI );
+            pv044.name = "3B_15_00s_044";
+            scene.add(pv044);
+            setMessage("3D", "Loaded PV044.");
+
+            pv045 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv045.position.set(5, 0.5, 34.5);
+            pv045.rotateY( Math.PI );
+            pv045.name = "4B_15_00s_045";
+            scene.add(pv045);
+            setMessage("3D", "Loaded PV045."); 
+
+            pv046 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv046.position.set(-1, 0.5, 35);
+            pv046.rotateY( Math.PI );
+            pv046.name = "6A_02_00s_046";
+            scene.add(pv046);
+            setMessage("3D", "Loaded PV046.");
+
+            pv047 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv047.position.set(3, 0.5, 36);
+            pv047.rotateY( Math.PI );
+            pv047.name = "2A_02_00s_047";
+            scene.add(pv047);
+            setMessage("3D", "Loaded PV047.");
+
+            pv048 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv048.position.set(6, 0.5, 37);
+            pv048.rotateY( Math.PI );
+            pv048.name = "1A_02_00s_048";
+            scene.add(pv048);
+            setMessage("3D", "Loaded PV048.");
+
+            pv049 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv049.position.set(-11, 0.5, 14);
+            pv049.rotateY( Math.PI );
+            pv049.name = "3C_30_00s_049";
+            scene.add(pv049);
+            setMessage("3D", "Loaded PV049.");
+
+            pv050 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv050.position.set(-10.5, 0.5, 11);
+            pv050.rotateY( Math.PI );
+            pv050.name = "1A_30_00s_050";
+            scene.add(pv050);
+            setMessage("3D", "Loaded PV050.");
+
+            pv051 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv051.position.set(8, 0.5, 7.5);
+            pv051.rotateY( Math.PI );
+            pv051.name = "1B_30_00s_051";
+            scene.add(pv051);
+            setMessage("3D", "Loaded PV051.");
+
+            pv052 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv052.position.set(-10, 0.5, 8);
+            pv052.rotateY( Math.PI );
+            pv052.name = "1D_30_00s_052";
+            scene.add(pv052);
+            setMessage("3D", "Loaded PV052.");
+
+            pv053 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv053.position.set(3, 0.5, 25);
+            pv053.rotateY( Math.PI );
+            pv053.name = "1C_30_00s_053";
+            scene.add(pv053);
+            setMessage("3D", "Loaded PV053.");
+
+            pv054 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv054.position.set(2.5, 0.5, 28);
+            pv054.rotateY( Math.PI );
+            pv054.name = "4D_30_00s_054";
+            scene.add(pv054);
+            setMessage("3D", "Loaded PV054.");
+
+            pv055 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv055.position.set(15, 0.5, -7);
+            pv055.rotateY( Math.PI );
+            pv055.name = "3A_45_00s_055";
+            scene.add(pv055);
+            setMessage("3D", "Loaded PV055.");
+
+            pv056 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv056.position.set(15, 0.5, -11);
+            pv056.rotateY( Math.PI );
+            pv056.name = "4A_45_00s_056";
+            scene.add(pv056);
+            setMessage("3D", "Loaded PV056.");
+
+            pv057 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv057.position.set(9, 0.5, -27.5);
+            pv057.rotateY( Math.PI );
+            pv057.name = "6A_60_00s_057";
+            scene.add(pv057);
+            setMessage("3D", "Loaded PV057.");
+
+            pv058 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv058.position.set(0, 0.5, -30);
+            pv058.rotateY( Math.PI );
+            pv058.name = "3A_60_00s_058";
+            scene.add(pv058);
+            setMessage("3D", "Loaded PV058.");
+
+            pv059 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv059.position.set(8, 0.5, 25.5);
+            pv059.rotateY( 11 * Math.PI / 12 );
+            pv059.name = "3B_15_15w_059";
+            scene.add(pv059);
+            setMessage("3D", "Loaded PV059.");
+
+            pv060 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv060.position.set(2.5, 0.5, 31);
+            pv060.rotateY( 11 * Math.PI / 12 );
+            pv060.name = "1B_15_15w_060";
+            scene.add(pv060);
+            setMessage("3D", "Loaded PV060.");
+
+            pv061 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv061.position.set(9.5, 0.5, 35.5);
+            pv061.rotateY( 11 * Math.PI / 12 );
+            pv061.name = "4B_15_15w_061";
+            scene.add(pv061);
+            setMessage("3D", "Loaded PV061.");
+
+            pv062 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv062.position.set(8, 0.5, 22.15);
+            pv062.rotateY( 11 * Math.PI / 12 );
+            pv062.name = "3A_30_15w_062";
+            scene.add(pv062);
+            setMessage("3D", "Loaded PV062.");
+
+            pv063 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv063.position.set(12.5, 0.5, 23.25);
+            pv063.rotateY( 11 * Math.PI / 12 );
+            pv063.name = "1A_30_15w_063";
+            scene.add(pv063);
+            setMessage("3D", "Loaded PV063.");
+
+            pv064 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv064.position.set(3.5, 0.5, 21);
+            pv064.rotateY( 11 * Math.PI / 12 );
+            pv064.name = "5A_30_15w_064";
+            scene.add(pv064);
+            setMessage("3D", "Loaded PV064.");
+
+            pv065 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv065.position.set(16, 0.5, -19);
+            pv065.rotateY( 11 * Math.PI / 12 );
+            pv065.name = "3A_45_15w_065";
+            scene.add(pv065);
+            setMessage("3D", "Loaded PV065.");
+
+            pv066 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv066.position.set(17, 0.5, -22);
+            pv066.rotateY( 11 * Math.PI / 12 );
+            pv066.name = "1A_45_15w_066";
+            scene.add(pv066);
+            setMessage("3D", "Loaded PV066.");
+
+            pv067 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv067.position.set(15, 0.5, -15);
+            pv067.rotateY( 11 * Math.PI / 12 );
+            pv067.name = "4A_45_15w_067";
+            scene.add(pv067);
+            setMessage("3D", "Loaded PV067.");
+
+            pv068 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv068.position.set(15, 0.5, -27);
+            pv068.rotateY( 11 * Math.PI / 12 );
+            pv068.name = "6A_60_15w_068";
+            scene.add(pv068);
+            setMessage("3D", "Loaded PV068.");
+
+            pv069 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv069.position.set(20, 0.5, -25.75);
+            pv069.rotateY( 11 * Math.PI / 12 );
+            pv069.name = "3A_60_15w_069";
+            scene.add(pv069);
+            setMessage("3D", "Loaded PV069.");
+
+            pv070 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv070.position.set(25, 0.5, -24.5);
+            pv070.rotateY( 11 * Math.PI / 12 );
+            pv070.name = "1A_60_15w_070";
+            scene.add(pv070);
+            setMessage("3D", "Loaded PV070.");
+
+            pv071 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv071.position.set(17, 0.5, 25);
+            pv071.rotateY( 11 * Math.PI / 6 );
+            pv071.name = "3A_15_30w_071";
+            scene.add(pv071);
+            setMessage("3D", "Loaded PV071.");
+
+            pv072 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv072.position.set(6.75, 0.5, 32.5);
+            pv072.rotateY( 11 * Math.PI / 6 );
+            pv072.name = "1A_15_30w_072";
+            scene.add(pv072);
+            setMessage("3D", "Loaded PV072.");
+
+            pv073 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv073.position.set(10.5, 0.5, 38.25);
+            pv073.rotateY( 11 * Math.PI / 6 );
+            pv073.name = "1B_15_30w_073";
+            scene.add(pv073);
+            setMessage("3D", "Loaded PV073.");
+
+            pv074 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv074.position.set(12.5, 0.5, 27.5);
+            pv074.rotateY( 11 * Math.PI / 6 );
+            pv074.name = "1D_15_30w_074";
+            scene.add(pv074);
+            setMessage("3D", "Loaded PV074.");
+
+            pv075 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv075.position.set(7.5, 0.5, 29.5);
+            pv075.rotateY( 11 * Math.PI / 6 );
+            pv075.name = "1C_15_30w_075";
+            scene.add(pv075);
+
+            pv076 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv076.position.set(11, 0.5, 33.5);
+            pv076.rotateY( 11 * Math.PI / 6 );
+            pv076.name = "5D_15_30w_076";
+            scene.add(pv076);
+            setMessage("3D", "Loaded PV076.");
+
+            pv077 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv077.position.set(13, 0.5, 12);
+            pv077.rotateY( 11 * Math.PI / 6 );
+            pv077.name = "6D_30_30w_077";
+            scene.add(pv077);
+            setMessage("3D", "Loaded PV077.");
+
+            pv078 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv078.position.set(12, 0.5, 15);
+            pv078.rotateY( 11 * Math.PI / 6 );
+            pv078.name = "3D_30_30w_078";
+            scene.add(pv078);
+            setMessage("3D", "Loaded PV078.");
+
+            pv079 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv079.position.set(14, 0.5, 9);
+            pv079.rotateY( 11 * Math.PI / 6 );
+            pv079.name = "1D_30_30w_079";
+            scene.add(pv079);
+            setMessage("3D", "Loaded PV079.");
+
+            pv080 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv080.position.set(20, 0.5, -4);
+            pv080.rotateY( 11 * Math.PI / 6 );
+            pv080.name = "3A_45_30w_080";
+            scene.add(pv080);
+            setMessage("3D", "Loaded PV080.");
+
+            pv081 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv081.position.set(21, 0.5, -7);
+            pv081.rotateY( 11 * Math.PI / 6 );
+            pv081.name = "1A_45_30w_081";
+            scene.add(pv081);
+            setMessage("3D", "Loaded PV081.");
+
+            pv082 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv082.position.set(21.5, 0.5, -11);
+            pv082.rotateY( 11 * Math.PI / 6 );
+            pv082.name = "5A_45_30w_082";
+            scene.add(pv082);
+            setMessage("3D", "Loaded PV082.");
+
+            pv083 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv083.position.set(24, 0.5, -21);
+            pv083.rotateY( 11 * Math.PI / 6 );
+            pv083.name = "6A_60_30w_083";
+            scene.add(pv083);
+            setMessage("3D", "Loaded PV083.");
+
+            pv084 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv084.position.set(23, 0.5, -18);
+            pv084.rotateY( 11 * Math.PI / 6 );
+            pv084.name = "3A_60_30w_084";
+            scene.add(pv084);
+            setMessage("3D", "Loaded PV084.");
+
+            pv085 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv085.position.set(23, 0.5, -14);
+            pv085.rotateY( 11 * Math.PI / 6 );
+            pv085.name = "1A_60_30w_085";
+            scene.add(pv085);
+            setMessage("3D", "Loaded PV085.");
+
+            pv086 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv086.position.set(12, 0.5, 30.5);
+            pv086.rotateY( 7 * Math.PI / 4 );
+            pv086.name = "2A_15_45w_086";
+            scene.add(pv086);
+            setMessage("3D", "Loaded PV086.");
+
+            pv087 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv087.position.set(16, 0.5, 30.5);
+            pv087.rotateY( 7 * Math.PI / 4 );
+            pv087.name = "1A_15_45w_087";
+            scene.add(pv087);
+            setMessage("3D", "Loaded PV087.");
+
+            pv088 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv088.position.set(17, 0.5, 27.5);
+            pv088.rotateY( 7 * Math.PI / 4 );
+            pv088.name = "4A_15_45w_088";
+            scene.add(pv088);
+            setMessage("3D", "Loaded PV088.");
+
+            pv089 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv089.position.set(20, 0.5, 11);
+            pv089.rotateY( 7 * Math.PI / 4 );
+            pv089.name = "6A_30_45w_089";
+            scene.add(pv089);
+            setMessage("3D", "Loaded PV089.");
+
+            pv090 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv090.position.set(19, 0.5, 14);
+            pv090.rotateY( 7 * Math.PI / 4 );
+            pv090.name = "2A_30_45w_090";
+            scene.add(pv090);
+            setMessage("3D", "Loaded PV090.");
+
+            pv091 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv091.position.set(29, 0.5, -14);
+            pv091.rotateY( 7 * Math.PI / 4 );
+            pv091.name = "2C_45_45w_091";
+            scene.add(pv091);
+            setMessage("3D", "Loaded PV091.");
+
+            pv092 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv092.position.set(23, 0.5, 7);
+            pv092.rotateY( 7 * Math.PI / 4 );
+            pv092.name = "4C_45_45w_092";
+            scene.add(pv092);
+            setMessage("3D", "Loaded PV092.");
+
+            pv093 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv093.position.set(30, 0.5, -18);
+            pv093.rotateY( 7 * Math.PI / 4 );
+            pv093.name = "6A_60_45w_093";
+            scene.add(pv093);
+            setMessage("3D", "Loaded PV093.");
+
+            pv094 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv094.position.set(30, 0.5, -22);
+            pv094.rotateY( 7 * Math.PI / 4 );
+            pv094.name = "2A_60_45w_094";
+            scene.add(pv094);
+            setMessage("3D", "Loaded PV094.");
+
+            pv095 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv095.position.set(15, 0.5, 34);
+            pv095.rotateY( 5 * Math.PI / 3);
+            pv095.name = "6A_15_60w_095";
+            scene.add(pv095);
+            setMessage("3D", "Loaded PV095."); 
+
+            pv096 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv096.position.set(14, 0.5, 37);
+            pv096.rotateY( 5 * Math.PI / 3);
+            pv096.name = "2A_15_60w_096";
+            scene.add(pv096);
+            setMessage("3D", "Loaded PV096."); 
+
+            pv097 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv097.position.set(16, 0.5, 20);
+            pv097.rotateY( 5 * Math.PI / 3);
+            pv097.name = "6A_30_60w_097";
+            scene.add(pv097);
+            setMessage("3D", "Loaded PV097.");
+
+            pv098 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv098.position.set(17, 0.5, 17);
+            pv098.rotateY( 5 * Math.PI / 3);
+            pv098.name = "1A_30_60w_098";
+            scene.add(pv098);
+            setMessage("3D", "Loaded PV098.");
+
+            pv099 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv099.position.set(25, 0.5, -1);
+            pv099.rotateY( 5 * Math.PI / 3);
+            pv099.name = "6A_45_60w_099";
+            scene.add(pv099);
+            setMessage("3D", "Loaded PV099.");
+
+            pv100 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( { 
+                    color: 0xD3D3D3, 
+                    specular: 0x050505,
+                    shininess: 100
+                }) 
+            );
+            pv100.position.set(22, 0.5, 2);
+            pv100.rotateY( 5 * Math.PI / 3);
+            pv100.name = "1A_45_60w_100";
+            scene.add(pv100);
+            setMessage("3D", "Loaded PV100.");
+
+            pv101 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv101.position.set(28, 0.5, -10);
+            pv101.rotateY( 5 * Math.PI / 3);
+            pv101.name = "2C_60_60w_101";
+            scene.add(pv101);
+            setMessage("3D", "Loaded PV101.");
+
+            pv102 = new THREE.Mesh(
+                new THREE.CubeGeometry( 4, 1, 1 ),
+                new THREE.MeshPhongMaterial( {
+                    color: 0xD3D3D3,
+                    specular: 0x050505,
+                    shininess: 100
+                })
+            );
+            pv102.position.set(26, 0.5, -6);
+            pv102.rotateY( 5 * Math.PI / 3);
+            pv102.name = "1C_60_60w_102";
+            scene.add(pv102);
+            setMessage("3D", "Loaded PV102.");
+
+            //scene.fog = new THREE.FogExp2( 0x000000, 0.0128 );
+            //renderer.setClearColor( scene.fog.color, 1 );
+            render();
+        }
+            
+        function animate() {
+            requestAnimationFrame(animate);
+
+            if (enableControls){ 
+                mycontrol.enabled = true;
+            } else {
+                mycontrol.enabled = false;
+            }
+            
+            mycontrol.update();
+
+            render();
+        }
+        
+        var vector;    
+        function render() {
+            /*
+            var speed = 0.0002;
+            var distance = 200;
+            var timer = Date.now() * speed;
+            camera.position.x = Math.cos(timer) * distance;
+            camera.position.z = Math.sin(timer) * distance;
+            camera.lookAt(scene.position);
+            */
+            
+            // update the picking ray with the camera and mouse position	
+	        raycaster.setFromCamera( mouse, camera );	
+
+	        // calculate objects intersecting the picking ray
+	        var intersects = raycaster.intersectObjects( scene.children );
+
+	        for ( var i = 0; i < intersects.length; i++ ) {
+		        //intersects[ i ].object.material.color.set( 0xff0000 );
+                //$("#obj-tooltip").text(intersects[ i ].object.name); 
+                if (intersects[ i ].object.name != "") {
+                    $("#obj-tooltip").text("Module: " + intersects[ i ].object.name);
+                    $("#val-tooltip").text("Value: " + data[ intersects[ i ].object.name ]);
+                }
+            }
+            
+            renderer.render(scene, camera);
+            
+            vector = camera.getWorldDirection();
+            theta = Math.atan2(vector.x,vector.z);
+            theta = theta + 3.142; // add/minux pi to inverse
+            var degree = theta * (180/3.142);
+            //console.log(degree);
+            draw(degree);
+        }
+        
+        $("#testTrigger").click(function() {
+            console.log("clicked");
+            pv001.material.color.setHex( 0x00ff00 );
+            pv001.scale.y = 10;
+            pv001.position.y = 5.5;
+            setMessage("3D", "Updated PV001.");
+            render();
+        });
+
+        
+        $("#message").mousedown(function() {
+            console.log("clicked");
+            enableControls = false;
+            setMessage("GUI", "De-select main scene. Click on main scene to re-select.");
+            //render();
+        });
+        
+        $("#orientation").mousedown(function() {
+            console.log("clicked");
+            enableControls = false;
+            setMessage("GUI", "De-select main scene. Click on main scene to re-select.");
+            //render();
+        });
+        
+        $("#settings").mousedown(function() {
+            console.log("clicked");
+            enableControls = false;
+            setMessage("GUI", "De-select main scene. Click on main scene to re-select.");
+            //render();
+        });
+        
+        $("#slider").mousedown(function() {
+            console.log("clicked");
+            enableControls = false;
+            setMessage("GUI", "De-select main scene. Click on main scene to re-select.");
+            //render();
+        });
+        
+        $("#container").click(function() {
+            console.log("clicked");
+            enableControls = true;
+            animate();
+            setMessage("GUI", "Selected main scene.");
+        });
+    </script>
+<script>
+jQuery(window).load(function () {
+
+myTimer();
+var myVar = setInterval(myTimer, 10000);
+
+function myTimer() {
+    var dataToSend = {};
+    var object;
+    var colour;
+    var value;
+    
+    $.ajax({
+        url: '/getdata/',
+        type: 'GET',
+        data: dataToSend,
+        success: function (response) {
+            //var objresponse = JSON.parse(response);
+            console.log(response);
+            data = response;
+            var obj = response;
+            for (var prop in obj) {
+                value = obj[prop];
+                if (prop == "time") {
+                    $("#slider-tooltip").text(value);
+                } else {
+                    // 0 = red
+                    // 1 = green
+                    if (value == "") {             
+                        colour = "0x808080";
+                    } else {
+                        if ( value == 0) {
+                            colour = "0xff0000";
+                        } else  if (value == 3) {
+                            colour = "0x00ff00";
+                        }
+                    }
+                    object = scene.getObjectByName( prop, true );
+                    object.material.color.setHex( colour );
+                }
+            }
+        },
+        error: function () {
+            console.log("Error.")
+        }
+    });
+}
+
+});
+
+
+</script>
+</body>
+</html>

+ 1034 - 0
static/OrbitControls.js

@@ -0,0 +1,1034 @@
+/**
+ * @author qiao / https://github.com/qiao
+ * @author mrdoob / http://mrdoob.com
+ * @author alteredq / http://alteredqualia.com/
+ * @author WestLangley / http://github.com/WestLangley
+ * @author erich666 / http://erichaines.com
+ */
+
+// This set of controls performs orbiting, dollying (zooming), and panning.
+// Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
+//
+//    Orbit - left mouse / touch: one finger move
+//    Zoom - middle mouse, or mousewheel / touch: two finger spread or squish
+//    Pan - right mouse, or arrow keys / touch: three finter swipe
+
+THREE.OrbitControls = function ( object, domElement ) {
+
+	this.object = object;
+
+	this.domElement = ( domElement !== undefined ) ? domElement : document;
+
+	// Set to false to disable this control
+	this.enabled = true;
+
+	// "target" sets the location of focus, where the object orbits around
+	this.target = new THREE.Vector3();
+
+	// How far you can dolly in and out ( PerspectiveCamera only )
+	this.minDistance = 0;
+	this.maxDistance = Infinity;
+
+	// How far you can zoom in and out ( OrthographicCamera only )
+	this.minZoom = 0;
+	this.maxZoom = Infinity;
+
+	// How far you can orbit vertically, upper and lower limits.
+	// Range is 0 to Math.PI radians.
+	this.minPolarAngle = 0; // radians
+	this.maxPolarAngle = Math.PI; // radians
+
+	// How far you can orbit horizontally, upper and lower limits.
+	// If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
+	this.minAzimuthAngle = - Infinity; // radians
+	this.maxAzimuthAngle = Infinity; // radians
+
+	// Set to true to enable damping (inertia)
+	// If damping is enabled, you must call controls.update() in your animation loop
+	this.enableDamping = false;
+	this.dampingFactor = 0.25;
+
+	// This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
+	// Set to false to disable zooming
+	this.enableZoom = true;
+	this.zoomSpeed = 1.0;
+
+	// Set to false to disable rotating
+	this.enableRotate = true;
+	this.rotateSpeed = 1.0;
+
+	// Set to false to disable panning
+	this.enablePan = true;
+	this.keyPanSpeed = 7.0;	// pixels moved per arrow key push
+
+	// Set to true to automatically rotate around the target
+	// If auto-rotate is enabled, you must call controls.update() in your animation loop
+	this.autoRotate = false;
+	this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
+
+	// Set to false to disable use of the keys
+	this.enableKeys = true;
+
+	// The four arrow keys
+	this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
+
+	// Mouse buttons
+	this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT };
+
+	// for reset
+	this.target0 = this.target.clone();
+	this.position0 = this.object.position.clone();
+	this.zoom0 = this.object.zoom;
+
+	//
+	// public methods
+	//
+
+	this.getPolarAngle = function () {
+
+		return spherical.phi;
+
+	};
+
+	this.getAzimuthalAngle = function () {
+
+		return spherical.theta;
+
+	};
+
+	this.reset = function () {
+
+		scope.target.copy( scope.target0 );
+		scope.object.position.copy( scope.position0 );
+		scope.object.zoom = scope.zoom0;
+
+		scope.object.updateProjectionMatrix();
+		scope.dispatchEvent( changeEvent );
+
+		scope.update();
+
+		state = STATE.NONE;
+
+	};
+
+	// this method is exposed, but perhaps it would be better if we can make it private...
+	this.update = function() {
+
+		var offset = new THREE.Vector3();
+
+		// so camera.up is the orbit axis
+		var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) );
+		var quatInverse = quat.clone().inverse();
+
+		var lastPosition = new THREE.Vector3();
+		var lastQuaternion = new THREE.Quaternion();
+
+		return function update () {
+
+			var position = scope.object.position;
+
+			offset.copy( position ).sub( scope.target );
+
+			// rotate offset to "y-axis-is-up" space
+			offset.applyQuaternion( quat );
+
+			// angle from z-axis around y-axis
+			spherical.setFromVector3( offset );
+
+			if ( scope.autoRotate && state === STATE.NONE ) {
+
+				rotateLeft( getAutoRotationAngle() );
+
+			}
+
+			spherical.theta += sphericalDelta.theta;
+			spherical.phi += sphericalDelta.phi;
+
+			// restrict theta to be between desired limits
+			spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) );
+
+			// restrict phi to be between desired limits
+			spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) );
+
+			spherical.makeSafe();
+
+
+			spherical.radius *= scale;
+
+			// restrict radius to be between desired limits
+			spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) );
+
+			// move target to panned location
+			scope.target.add( panOffset );
+
+			offset.setFromSpherical( spherical );
+
+			// rotate offset back to "camera-up-vector-is-up" space
+			offset.applyQuaternion( quatInverse );
+
+			position.copy( scope.target ).add( offset );
+
+			scope.object.lookAt( scope.target );
+
+			if ( scope.enableDamping === true ) {
+
+				sphericalDelta.theta *= ( 1 - scope.dampingFactor );
+				sphericalDelta.phi *= ( 1 - scope.dampingFactor );
+
+			} else {
+
+				sphericalDelta.set( 0, 0, 0 );
+
+			}
+
+			scale = 1;
+			panOffset.set( 0, 0, 0 );
+
+			// update condition is:
+			// min(camera displacement, camera rotation in radians)^2 > EPS
+			// using small-angle approximation cos(x/2) = 1 - x^2 / 8
+
+			if ( zoomChanged ||
+				lastPosition.distanceToSquared( scope.object.position ) > EPS ||
+				8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) {
+
+				scope.dispatchEvent( changeEvent );
+
+				lastPosition.copy( scope.object.position );
+				lastQuaternion.copy( scope.object.quaternion );
+				zoomChanged = false;
+
+				return true;
+
+			}
+
+			return false;
+
+		};
+
+	}();
+
+	this.dispose = function() {
+
+		scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false );
+		scope.domElement.removeEventListener( 'mousedown', onMouseDown, false );
+		scope.domElement.removeEventListener( 'mousewheel', onMouseWheel, false );
+		scope.domElement.removeEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox
+
+		scope.domElement.removeEventListener( 'touchstart', onTouchStart, false );
+		scope.domElement.removeEventListener( 'touchend', onTouchEnd, false );
+		scope.domElement.removeEventListener( 'touchmove', onTouchMove, false );
+
+		document.removeEventListener( 'mousemove', onMouseMove, false );
+		document.removeEventListener( 'mouseup', onMouseUp, false );
+
+		window.removeEventListener( 'keydown', onKeyDown, false );
+
+		//scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?
+
+	};
+
+	//
+	// internals
+	//
+
+	var scope = this;
+
+	var changeEvent = { type: 'change' };
+	var startEvent = { type: 'start' };
+	var endEvent = { type: 'end' };
+
+	var STATE = { NONE : - 1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };
+
+	var state = STATE.NONE;
+
+	var EPS = 0.000001;
+
+	// current position in spherical coordinates
+	var spherical = new THREE.Spherical();
+	var sphericalDelta = new THREE.Spherical();
+
+	var scale = 1;
+	var panOffset = new THREE.Vector3();
+	var zoomChanged = false;
+
+	var rotateStart = new THREE.Vector2();
+	var rotateEnd = new THREE.Vector2();
+	var rotateDelta = new THREE.Vector2();
+
+	var panStart = new THREE.Vector2();
+	var panEnd = new THREE.Vector2();
+	var panDelta = new THREE.Vector2();
+
+	var dollyStart = new THREE.Vector2();
+	var dollyEnd = new THREE.Vector2();
+	var dollyDelta = new THREE.Vector2();
+
+	function getAutoRotationAngle() {
+
+		return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
+
+	}
+
+	function getZoomScale() {
+
+		return Math.pow( 0.95, scope.zoomSpeed );
+
+	}
+
+	function rotateLeft( angle ) {
+
+		sphericalDelta.theta -= angle;
+
+	}
+
+	function rotateUp( angle ) {
+
+		sphericalDelta.phi -= angle;
+
+	}
+
+	var panLeft = function() {
+
+		var v = new THREE.Vector3();
+
+		return function panLeft( distance, objectMatrix ) {
+
+			v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix
+			v.multiplyScalar( - distance );
+
+			panOffset.add( v );
+
+		};
+
+	}();
+
+	var panUp = function() {
+
+		var v = new THREE.Vector3();
+
+		return function panUp( distance, objectMatrix ) {
+
+			v.setFromMatrixColumn( objectMatrix, 1 ); // get Y column of objectMatrix
+			v.multiplyScalar( distance );
+
+			panOffset.add( v );
+
+		};
+
+	}();
+
+	// deltaX and deltaY are in pixels; right and down are positive
+	var pan = function() {
+
+		var offset = new THREE.Vector3();
+
+		return function pan ( deltaX, deltaY ) {
+
+			var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
+
+			if ( scope.object instanceof THREE.PerspectiveCamera ) {
+
+				// perspective
+				var position = scope.object.position;
+				offset.copy( position ).sub( scope.target );
+				var targetDistance = offset.length();
+
+				// half of the fov is center to top of screen
+				targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
+
+				// we actually don't use screenWidth, since perspective camera is fixed to screen height
+				panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix );
+				panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix );
+
+			} else if ( scope.object instanceof THREE.OrthographicCamera ) {
+
+				// orthographic
+				panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix );
+				panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix );
+
+			} else {
+
+				// camera neither orthographic nor perspective
+				console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
+				scope.enablePan = false;
+
+			}
+
+		};
+
+	}();
+
+	function dollyIn( dollyScale ) {
+
+		if ( scope.object instanceof THREE.PerspectiveCamera ) {
+
+			scale /= dollyScale;
+
+		} else if ( scope.object instanceof THREE.OrthographicCamera ) {
+
+			scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) );
+			scope.object.updateProjectionMatrix();
+			zoomChanged = true;
+
+		} else {
+
+			console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
+			scope.enableZoom = false;
+
+		}
+
+	}
+
+	function dollyOut( dollyScale ) {
+
+		if ( scope.object instanceof THREE.PerspectiveCamera ) {
+
+			scale *= dollyScale;
+
+		} else if ( scope.object instanceof THREE.OrthographicCamera ) {
+
+			scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) );
+			scope.object.updateProjectionMatrix();
+			zoomChanged = true;
+
+		} else {
+
+			console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
+			scope.enableZoom = false;
+
+		}
+
+	}
+
+	//
+	// event callbacks - update the object state
+	//
+
+	function handleMouseDownRotate( event ) {
+
+		//console.log( 'handleMouseDownRotate' );
+
+		rotateStart.set( event.clientX, event.clientY );
+
+	}
+
+	function handleMouseDownDolly( event ) {
+
+		//console.log( 'handleMouseDownDolly' );
+
+		dollyStart.set( event.clientX, event.clientY );
+
+	}
+
+	function handleMouseDownPan( event ) {
+
+		//console.log( 'handleMouseDownPan' );
+
+		panStart.set( event.clientX, event.clientY );
+
+	}
+
+	function handleMouseMoveRotate( event ) {
+
+		//console.log( 'handleMouseMoveRotate' );
+
+		rotateEnd.set( event.clientX, event.clientY );
+		rotateDelta.subVectors( rotateEnd, rotateStart );
+
+		var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
+
+		// rotating across whole screen goes 360 degrees around
+		rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
+
+		// rotating up and down along whole screen attempts to go 360, but limited to 180
+		rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
+
+		rotateStart.copy( rotateEnd );
+
+		scope.update();
+
+	}
+
+	function handleMouseMoveDolly( event ) {
+
+		//console.log( 'handleMouseMoveDolly' );
+
+		dollyEnd.set( event.clientX, event.clientY );
+
+		dollyDelta.subVectors( dollyEnd, dollyStart );
+
+		if ( dollyDelta.y > 0 ) {
+
+			dollyIn( getZoomScale() );
+
+		} else if ( dollyDelta.y < 0 ) {
+
+			dollyOut( getZoomScale() );
+
+		}
+
+		dollyStart.copy( dollyEnd );
+
+		scope.update();
+
+	}
+
+	function handleMouseMovePan( event ) {
+
+		//console.log( 'handleMouseMovePan' );
+
+		panEnd.set( event.clientX, event.clientY );
+
+		panDelta.subVectors( panEnd, panStart );
+
+		pan( panDelta.x, panDelta.y );
+
+		panStart.copy( panEnd );
+
+		scope.update();
+
+	}
+
+	function handleMouseUp( event ) {
+
+		//console.log( 'handleMouseUp' );
+
+	}
+
+	function handleMouseWheel( event ) {
+
+		//console.log( 'handleMouseWheel' );
+
+		var delta = 0;
+
+		if ( event.wheelDelta !== undefined ) {
+
+			// WebKit / Opera / Explorer 9
+
+			delta = event.wheelDelta;
+
+		} else if ( event.detail !== undefined ) {
+
+			// Firefox
+
+			delta = - event.detail;
+
+		}
+
+		if ( delta > 0 ) {
+
+			dollyOut( getZoomScale() );
+
+		} else if ( delta < 0 ) {
+
+			dollyIn( getZoomScale() );
+
+		}
+
+		scope.update();
+
+	}
+
+	function handleKeyDown( event ) {
+
+		//console.log( 'handleKeyDown' );
+
+		switch ( event.keyCode ) {
+
+			case scope.keys.UP:
+				pan( 0, scope.keyPanSpeed );
+				scope.update();
+				break;
+
+			case scope.keys.BOTTOM:
+				pan( 0, - scope.keyPanSpeed );
+				scope.update();
+				break;
+
+			case scope.keys.LEFT:
+				pan( scope.keyPanSpeed, 0 );
+				scope.update();
+				break;
+
+			case scope.keys.RIGHT:
+				pan( - scope.keyPanSpeed, 0 );
+				scope.update();
+				break;
+
+		}
+
+	}
+
+	function handleTouchStartRotate( event ) {
+
+		//console.log( 'handleTouchStartRotate' );
+
+		rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
+
+	}
+
+	function handleTouchStartDolly( event ) {
+
+		//console.log( 'handleTouchStartDolly' );
+
+		var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
+		var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
+
+		var distance = Math.sqrt( dx * dx + dy * dy );
+
+		dollyStart.set( 0, distance );
+
+	}
+
+	function handleTouchStartPan( event ) {
+
+		//console.log( 'handleTouchStartPan' );
+
+		panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
+
+	}
+
+	function handleTouchMoveRotate( event ) {
+
+		//console.log( 'handleTouchMoveRotate' );
+
+		rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
+		rotateDelta.subVectors( rotateEnd, rotateStart );
+
+		var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
+
+		// rotating across whole screen goes 360 degrees around
+		rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
+
+		// rotating up and down along whole screen attempts to go 360, but limited to 180
+		rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
+
+		rotateStart.copy( rotateEnd );
+
+		scope.update();
+
+	}
+
+	function handleTouchMoveDolly( event ) {
+
+		//console.log( 'handleTouchMoveDolly' );
+
+		var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
+		var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
+
+		var distance = Math.sqrt( dx * dx + dy * dy );
+
+		dollyEnd.set( 0, distance );
+
+		dollyDelta.subVectors( dollyEnd, dollyStart );
+
+		if ( dollyDelta.y > 0 ) {
+
+			dollyOut( getZoomScale() );
+
+		} else if ( dollyDelta.y < 0 ) {
+
+			dollyIn( getZoomScale() );
+
+		}
+
+		dollyStart.copy( dollyEnd );
+
+		scope.update();
+
+	}
+
+	function handleTouchMovePan( event ) {
+
+		//console.log( 'handleTouchMovePan' );
+
+		panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
+
+		panDelta.subVectors( panEnd, panStart );
+
+		pan( panDelta.x, panDelta.y );
+
+		panStart.copy( panEnd );
+
+		scope.update();
+
+	}
+
+	function handleTouchEnd( event ) {
+
+		//console.log( 'handleTouchEnd' );
+
+	}
+
+	//
+	// event handlers - FSM: listen for events and reset state
+	//
+
+	function onMouseDown( event ) {
+
+		if ( scope.enabled === false ) return;
+
+		event.preventDefault();
+
+		if ( event.button === scope.mouseButtons.ORBIT ) {
+
+			if ( scope.enableRotate === false ) return;
+
+			handleMouseDownRotate( event );
+
+			state = STATE.ROTATE;
+
+		} else if ( event.button === scope.mouseButtons.ZOOM ) {
+
+			if ( scope.enableZoom === false ) return;
+
+			handleMouseDownDolly( event );
+
+			state = STATE.DOLLY;
+
+		} else if ( event.button === scope.mouseButtons.PAN ) {
+
+			if ( scope.enablePan === false ) return;
+
+			handleMouseDownPan( event );
+
+			state = STATE.PAN;
+
+		}
+
+		if ( state !== STATE.NONE ) {
+
+			document.addEventListener( 'mousemove', onMouseMove, false );
+			document.addEventListener( 'mouseup', onMouseUp, false );
+
+			scope.dispatchEvent( startEvent );
+
+		}
+
+	}
+
+	function onMouseMove( event ) {
+
+		if ( scope.enabled === false ) return;
+
+		event.preventDefault();
+
+		if ( state === STATE.ROTATE ) {
+
+			if ( scope.enableRotate === false ) return;
+
+			handleMouseMoveRotate( event );
+
+		} else if ( state === STATE.DOLLY ) {
+
+			if ( scope.enableZoom === false ) return;
+
+			handleMouseMoveDolly( event );
+
+		} else if ( state === STATE.PAN ) {
+
+			if ( scope.enablePan === false ) return;
+
+			handleMouseMovePan( event );
+
+		}
+
+	}
+
+	function onMouseUp( event ) {
+
+		if ( scope.enabled === false ) return;
+
+		handleMouseUp( event );
+
+		document.removeEventListener( 'mousemove', onMouseMove, false );
+		document.removeEventListener( 'mouseup', onMouseUp, false );
+
+		scope.dispatchEvent( endEvent );
+
+		state = STATE.NONE;
+
+	}
+
+	function onMouseWheel( event ) {
+
+		if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return;
+
+		event.preventDefault();
+		event.stopPropagation();
+
+		handleMouseWheel( event );
+
+		scope.dispatchEvent( startEvent ); // not sure why these are here...
+		scope.dispatchEvent( endEvent );
+
+	}
+
+	function onKeyDown( event ) {
+
+		if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return;
+
+		handleKeyDown( event );
+
+	}
+
+	function onTouchStart( event ) {
+
+		if ( scope.enabled === false ) return;
+
+		switch ( event.touches.length ) {
+
+			case 1:	// one-fingered touch: rotate
+
+				if ( scope.enableRotate === false ) return;
+
+				handleTouchStartRotate( event );
+
+				state = STATE.TOUCH_ROTATE;
+
+				break;
+
+			case 2:	// two-fingered touch: dolly
+
+				if ( scope.enableZoom === false ) return;
+
+				handleTouchStartDolly( event );
+
+				state = STATE.TOUCH_DOLLY;
+
+				break;
+
+			case 3: // three-fingered touch: pan
+
+				if ( scope.enablePan === false ) return;
+
+				handleTouchStartPan( event );
+
+				state = STATE.TOUCH_PAN;
+
+				break;
+
+			default:
+
+				state = STATE.NONE;
+
+		}
+
+		if ( state !== STATE.NONE ) {
+
+			scope.dispatchEvent( startEvent );
+
+		}
+
+	}
+
+	function onTouchMove( event ) {
+
+		if ( scope.enabled === false ) return;
+
+		event.preventDefault();
+		event.stopPropagation();
+
+		switch ( event.touches.length ) {
+
+			case 1: // one-fingered touch: rotate
+
+				if ( scope.enableRotate === false ) return;
+				if ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?...
+
+				handleTouchMoveRotate( event );
+
+				break;
+
+			case 2: // two-fingered touch: dolly
+
+				if ( scope.enableZoom === false ) return;
+				if ( state !== STATE.TOUCH_DOLLY ) return; // is this needed?...
+
+				handleTouchMoveDolly( event );
+
+				break;
+
+			case 3: // three-fingered touch: pan
+
+				if ( scope.enablePan === false ) return;
+				if ( state !== STATE.TOUCH_PAN ) return; // is this needed?...
+
+				handleTouchMovePan( event );
+
+				break;
+
+			default:
+
+				state = STATE.NONE;
+
+		}
+
+	}
+
+	function onTouchEnd( event ) {
+
+		if ( scope.enabled === false ) return;
+
+		handleTouchEnd( event );
+
+		scope.dispatchEvent( endEvent );
+
+		state = STATE.NONE;
+
+	}
+
+	function onContextMenu( event ) {
+
+		event.preventDefault();
+
+	}
+
+	//
+
+	scope.domElement.addEventListener( 'contextmenu', onContextMenu, false );
+
+	scope.domElement.addEventListener( 'mousedown', onMouseDown, false );
+	scope.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
+	scope.domElement.addEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox
+
+	scope.domElement.addEventListener( 'touchstart', onTouchStart, false );
+	scope.domElement.addEventListener( 'touchend', onTouchEnd, false );
+	scope.domElement.addEventListener( 'touchmove', onTouchMove, false );
+
+	window.addEventListener( 'keydown', onKeyDown, false );
+
+	// force an update at start
+
+	this.update();
+
+};
+
+THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
+THREE.OrbitControls.prototype.constructor = THREE.OrbitControls;
+
+Object.defineProperties( THREE.OrbitControls.prototype, {
+
+	center: {
+
+		get: function () {
+
+			console.warn( 'THREE.OrbitControls: .center has been renamed to .target' );
+			return this.target;
+
+		}
+
+	},
+
+	// backward compatibility
+
+	noZoom: {
+
+		get: function () {
+
+			console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );
+			return ! this.enableZoom;
+
+		},
+
+		set: function ( value ) {
+
+			console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );
+			this.enableZoom = ! value;
+
+		}
+
+	},
+
+	noRotate: {
+
+		get: function () {
+
+			console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );
+			return ! this.enableRotate;
+
+		},
+
+		set: function ( value ) {
+
+			console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );
+			this.enableRotate = ! value;
+
+		}
+
+	},
+
+	noPan: {
+
+		get: function () {
+
+			console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );
+			return ! this.enablePan;
+
+		},
+
+		set: function ( value ) {
+
+			console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );
+			this.enablePan = ! value;
+
+		}
+
+	},
+
+	noKeys: {
+
+		get: function () {
+
+			console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );
+			return ! this.enableKeys;
+
+		},
+
+		set: function ( value ) {
+
+			console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );
+			this.enableKeys = ! value;
+
+		}
+
+	},
+
+	staticMoving : {
+
+		get: function () {
+
+			console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );
+			return ! this.enableDamping;
+
+		},
+
+		set: function ( value ) {
+
+			console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );
+			this.enableDamping = ! value;
+
+		}
+
+	},
+
+	dynamicDampingFactor : {
+
+		get: function () {
+
+			console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
+			return this.dampingFactor;
+
+		},
+
+		set: function ( value ) {
+
+			console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
+			this.dampingFactor = value;
+
+		}
+
+	}
+
+} );

BIN
static/compass.png


BIN
static/needle.png


+ 185 - 0
static/scripts.js

@@ -0,0 +1,185 @@
+$("#message").draggable();
+$("#orientation").draggable();
+$("#settings").draggable();
+
+
+function setMessage(bheader, bcontent) {
+    //console.log("Creating message");
+    var timeNow = new Date();
+    var hours   = timeNow.getHours();
+    var minutes = timeNow.getMinutes();
+    var seconds = timeNow.getSeconds();
+    //var timeString = "" + ((minutes > 12) ? - 12 : hours);
+    var timeString  = ((minutes < 10) ? "0" : "") + minutes;
+    timeString  += ((seconds < 10) ? ":0" : ":") + seconds;
+    
+    var html = "<div><span class='bar-hl'>";
+    //html += timeString;
+    html += bheader;
+    html += "</span><span class='bar-info'>";
+    html += bcontent;
+    html += "</span></div>";
+    
+    console.log(html);
+    $(".bar-message > .bar-wrapper").append(html);
+    $('.bar-message > .bar-wrapper').scrollTop($('.bar-message > .bar-wrapper')[0].scrollHeight);
+}
+
+$(".bar-dropdown").click(function() {
+    console.log($(this).parent().parent().attr('id'));
+    var _id = $(this).parent().parent().attr('id');
+    if (parseInt($(".bar-"+ _id).css("height")) > 0) {
+        $(".bar-dropdown", "#"+_id).css("transform", "rotate(180deg)");
+        $(".bar-"+ _id + "> .bar-wrapper").hide();
+        $(".bar-"+ _id).css("height", 0);
+        $("#"+_id).css("height", 36);
+    } else {
+        $(".bar-dropdown", "#"+_id).css("transform", "rotate(0deg)");
+        $(".bar-"+ _id).css("height", 200);
+        $("#"+_id).css("height", 236);
+        $(".bar-"+ _id + "> .bar-wrapper").show();
+    }
+});
+
+// master hide all elements on screen
+$("#toggleGUI").click(function() {
+    $(".window-item").toggle();
+});
+
+$("#showTabs").hover(
+    function() {
+        $("#window-tab").show();
+    }, function() {
+        $("#window-tab").hide();
+    }
+);
+
+$("#window-tab").hover(
+    function() {
+        $("#window-tab").show();
+    }, function() {
+        $("#window-tab").hide();
+    }
+);
+
+$("#offMessage").click(function() {
+    if ($("#message").is(":visible")) {
+        $("#message").removeClass("window-item");
+        $("#message").hide();
+    } else {
+        $("#message").addClass("window-item");
+        $("#message").show();
+    }
+});
+
+$("#offOrientation").click(function() {
+    if ($("#orientation").is(":visible")) {
+        $("#orientation").removeClass("window-item");
+        $("#orientation").hide();
+    } else {
+        $("#orientation").addClass("window-item");
+        $("#orientation").show();
+    }
+});
+
+$("#offSettings").click(function() {
+    if ($("#settings").is(":visible")) {
+        $("#settings").removeClass("window-item");
+        $("#settings").hide();
+    } else {
+        $("#settings").addClass("window-item");
+        $("#settings").show();
+    }
+});
+
+
+function setMessage(bheader, bcontent) {
+    //console.log("Creating message");
+    var timeNow = new Date();
+    var hours   = timeNow.getHours();
+    var minutes = timeNow.getMinutes();
+    var seconds = timeNow.getSeconds();
+    //var timeString = "" + ((minutes > 12) ? - 12 : hours);
+    var timeString  = ((minutes < 10) ? "0" : "") + minutes;
+    timeString  += ((seconds < 10) ? ":0" : ":") + seconds;
+    
+    var html = "<div><span class='bar-hl'>";
+    //html += timeString;
+    html += bheader;
+    html += "</span><span class='bar-info'>";
+    html += bcontent;
+    html += "</span></div>";
+    
+    //console.log(html);
+    $(".bar-message > .bar-wrapper").append(html);
+    $('.bar-message > .bar-wrapper').scrollTop($('.bar-message > .bar-wrapper')[0].scrollHeight);
+}
+
+$('#settings-box :checkbox').click(function() {
+    var $this = $(this);
+    // $this will contain a reference to the checkbox   
+    if ($this.is(':checked')) {
+        if (this.name == "wireframe") {
+            rcl2.addWireframe();
+            setMessage("tomo", "Add cube wireframe.");
+        }
+        // the checkbox was checked 
+    } else {
+        if (this.name == "wireframe") {
+            rcl2.removeWireframe();
+            setMessage("tomo", "Remove cube wireframe.");
+        }
+        // the checkbox was unchecked
+    }
+});
+
+$( "#bg-color" ).change(function() {
+    console.log(this.value);
+    rcl2.setBackgroundColor("#"+this.value);
+    setMessage("tomo", "Set background color: #" + this.value);
+});
+
+
+
+$( document ).ready(function() {
+    setMessage("GUI", "Initialized.");
+    
+    var date = new Date(parseInt( $("#start_time").val() )*1000);
+    // Hours part from the timestamp
+    var year = date.getUTCFullYear();
+    // Minutes part from the timestamp
+    var month = "0" + parseInt(date.getUTCMonth()+1);
+    // Seconds part from the timestamp
+    var day = "0" + date.getUTCDate();
+                
+    var hours = "0" + date.getUTCHours();
+    // Minutes part from the timestamp
+    var minutes = "0" + date.getUTCMinutes();
+    // Seconds part from the timestamp
+    var seconds = "0" + date.getUTCSeconds();
+
+    // Will display time in 10:30:23 format
+    var formattedTime = year + '-' + month.substr(-2) + '-' + day.substr(-2) + ' ' + hours.substr(-2) + ':' + minutes.substr(-2) + ':' + seconds.substr(-2);            
+    $("#slider-tooltip").text(formattedTime);
+    
+    // Handler for .ready() called.
+    $( "#slider-range" ).slider({
+        range: true,
+        min: 0,
+        max: 100,
+        values: [ 0, 100 ],
+        slide: function( event, ui ) {
+            console.log(ui.values);
+            rcl2.setMinSos(ui.values[0]/100.0);
+            rcl2.setMaxSos(ui.values[1]/100.0);
+          //$( "#amount" ).val( "$" + ui.values[ 0 ] + " - $" + ui.values[ 1 ] );
+        }
+    });
+    $("#slider").slider({
+        min: parseInt( $("#start_time").val() ),
+        max: parseInt( $("#end_time").val() ),
+        slide: function( event, ui ) {
+            console.log(ui.value);
+        }
+    });
+});

+ 248 - 90
static/style.css

@@ -1,136 +1,294 @@
-@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700);
+@import url(https://fonts.googleapis.com/css?family=Source+Code+Pro);
 
-html,
+/* http://meyerweb.com/eric/tools/css/reset/ 
+   v2.0 | 20110126
+   License: none (public domain)
+*/
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed, 
+figure, figcaption, footer, header, hgroup, 
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+	margin: 0;
+	padding: 0;
+	border: 0;
+	font-size: 100%;
+	font: inherit;
+	vertical-align: baseline;
+}
+/* HTML5 display-role reset for older browsers */
+article, aside, details, figcaption, figure, 
+footer, header, hgroup, menu, nav, section {
+	display: block;
+}
 body {
-    background-repeat: no-repeat;
-    background-attachment: fixed;
+	line-height: 1;
+}
+ol, ul {
+	list-style: none;
+}
+blockquote, q {
+	quotes: none;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+	content: '';
+	content: none;
+}
+table {
+	border-collapse: collapse;
+	border-spacing: 0;
 }
 
-p {
-    font-family: 'Open Sans', sans-serif;
-    font-size: 28px; 
+.noselect {
+  -webkit-touch-callout: none; /* iOS Safari */
+  -webkit-user-select: none;   /* Chrome/Safari/Opera */
+  -khtml-user-select: none;    /* Konqueror */
+  -moz-user-select: none;      /* Firefox */
+  -ms-user-select: none;       /* Internet Explorer/Edge */
+  user-select: none;           /* Non-prefixed version, currently
+                                  not supported by any browser */
 }
 
-span,
-.varval {
-    font-family: 'Open Sans', sans-serif;
-    font-size: 28px; 
-    font-weight: 400;
+.window-item,
+.window-cp,
+.window-unitem {
+    font-family: 'Source Code Pro';
+    border: 1px solid #333333;
+    border-radius: 10px;
+    padding: 0 10px 10px 10px;
+    background-color: rgba(210,210,210,0.5);
+    -webkit-box-shadow: 0px 0px 2px 2px rgba(0,0,0,0.58);
+    -moz-box-shadow: 0px 0px 2px 2px rgba(0,0,0,0.58);
+    box-shadow: 0px 0px 2px 2px rgba(0,0,0,0.58);
 }
 
-.button {
-    background-color: #4CAF50; /* Green */
-    border: none;
-    color: white;
-    padding: 15px 32px;
-    text-align: center;
-    text-decoration: none;
-    display: inline-block;
-    font-size: 16px;
-    margin: 4px 2px;
-    cursor: pointer;
+#slider {
+    position: absolute;
+    top: 10px;
+    left: 500px;
+    width: 20%;
+    
 }
 
-.button2 {background-color: #008CBA;} /* Blue */
-.button3 {background-color: #f44336;} /* Red */ 
-.showhide {
-    background-color: #e7e7e7;
-    color: black;
+#slider-tooltip {
     position: absolute;
-    left: 0;
-    bottom: 0;
+    top: 40px;
+    left: 500px;
+    width: 20%;
+    font-family: 'Source Code Pro';
+    color: #808080;
 }
 
-#tool-btn {
-    padding: 20px;
+#obj-tooltip {
     position: absolute;
-    left: 200px;
-    bottom: 0;
-    background-color: rgba(0, 0, 0, 0.7);
-    z-index: 100;
+    top: 40px;
+    right: 0px;
+    width: 20%;
+    font-family: 'Source Code Pro';
+    color: #808080;
 }
 
-.save,
-.add,
-.remove,
-.highlight {
-    background-color: #e7e7e7;
-    color: black;
+#val-tooltip {
+    position: absolute;
+    top: 80px;
+    right: 0px;
+    width: 20%;
+    font-family: 'Source Code Pro';
+    color: #808080;
 }
 
-.info {
-    color:ghostwhite;
+#message {
+    position: absolute;
+    top: 10px;
+    left: 10px;
+    width: 20%;
 }
 
-.button5 {background-color: #555555;} /* Black */
+#orientation {
+    position: absolute;
+    bottom: 10px;
+    right: 10px;
+    width: 200px;
+}
 
-.varbox {
+#settings {
     position: absolute;
-    width: 50px;
-    border: dashed 5px #ccc;
+    top: 100px;
+    right: 10px;
+    width: 200px;
 }
 
-.databox {
-    border: dashed 5px rgba(0,0,0,0);
+.bar-header {
+    /* flexbox setup */
+    display: -webkit-flex; /* Safari */
+    display: flex;
+    -webkit-flex-direction: row; /* Safari */
+    flex-direction:         row;
+    /*border: 1px solid #333333;*/
+    padding-right: 5px;
+    background-color: rgba(0,0,0,0.6);
 }
-.databox:hover {
-    z-index: 9999 !important;
+
+.bar-title {
+    text-align: center;
+    width: 100%;
+    padding: 10px;
+    /*border: 1px solid #333333;*/
+    margin-right: 5px;
+    color: white;
+    background-color: rgba(160,160,160,0.5);
 }
 
-.statusbox {
-    position: absolute;
-    width: 50px;
+.bar-dropdown,
+.bar-close {
+    text-align: center;
+    width: 16px;
+    height: 16px;
     padding: 5px;
+    /*border: 1px solid #333333;*/
+    background-color: rgba(160,160,160,0.5);
+    color: white;
 }
 
-#page_info {
-    position: absolute;
-    top: 10px;
-    left: 20px;
-    font-family: 'Open Sans', sans-serif;
-    font-size: 16px;
-    color: darkgray;
+.bar-title:hover {
+    color: #f7b733;
+    cursor: pointer;
 }
 
-.box_highlight {
-    border-color: red;
+.bar-dropdown:hover,
+.bar-close:hover {
+    background-color:#f7b733;
+    cursor: pointer;
 }
 
-.glowing_border {
-    border: 2px solid #FF0000;
-    border-radius: 7px;
+.bar-settings {
+    background-color: rgba(21, 21, 21, .4);
+    height: 200px;
+    font-size: 12px;
+    /*
+    transition-property: all;
+	transition-duration: .5s;
+	transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
+    */
 }
 
-[tooltip]:before {
-    /* needed - do not touch */
-    content: attr(tooltip);
-    position: absolute;
-    opacity: 0;
-    
-    /* customizable */
-    transition: all 0.15s ease;
-    padding: 10px;
+.bar-message {
+    overflow-x: hidden;
+    overflow-y: hidden;
+    background-color: rgba(21, 21, 21, .4);
+    height: 200px;
+    font-size: 12px;
+    /*
+    transition-property: all;
+	transition-duration: .5s;
+	transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
+    */
+}
+
+.bar-orientation {
+    overflow-x: hidden;
+    overflow-y: hidden;
+    background-color: rgba(21, 21, 21, .4);
+    height: 200px;
+    font-size: 12px;
+    /*
+    transition-property: all;
+	transition-duration: .5s;
+	transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
+    */
+}
+
+.bar-wrapper > div {
+    margin-bottom: 5px;
+}
+
+.bar-hl {
+    color: #f7b733;
+    margin-right: 5px;
+}
+
+.bar-info {
     color: #fff;
-    border-radius: 10px;
-    box-shadow: 2px 2px 1px silver;
-    font-family: 'Open Sans', sans-serif;
-    text-align:center;
 }
 
-[tooltip]:hover:before {
-    /* needed - do not touch */
-    opacity: 1;
-    
-    /* customizable */
-    background: black;
+.bar-button {
+    text-align: center;
     width: 150px;
-    margin-top: -25px;
-    margin-left: 20px;
+    padding: 10px;
+    color: white;
+    background-color: rgba(160,160,160,0.5);
+}
+
+#control-panel {
+    width: 450px;
+    position: absolute;
+    bottom: 10px;
+    left: 10px;
+}
+
+.bar-button:hover {
+    background-color: #f7b733;
+}
+
+.bar-pil {
+    width: 100px;
+    font-size: 12px;
+    font-family: 'Source Code Pro';
+    padding: 0 10px 10px 10px;
+    background-color: rgba(160,160,160,1.0);
+    text-align: center;
+    padding: 10px;
+    /*border: 1px solid #333333;*/
+    margin-right: 5px;
+    color: white;
+}
+
+.bar-pil:hover {
+    background-color:#f7b733;
+    cursor: pointer;
+}
+
+#window-tab {
+    display: none;
+    position: absolute;
+    left: 180px;
+    bottom: 58px;
 }
 
-[tooltip]:not([tooltip-persistent]):before {
-    pointer-events: none;
+.bar-setup {
+    /* flexbox setup */
+    display: -webkit-flex; /* Safari */
+    display: flex;
+    -webkit-flex-direction: row; /* Safari */
+    flex-direction:         row;
 }
 
+.bl, .br {
+    flex: 1;
+}
 
+#bg-color {
+    width: 50px;
+}
 
+#start_time {
+    width: 70px;
+}
+
+#end_time {
+    width: 70px;
+}
+
+#slider-range {
+    margin-right: 20px;
+}

File diff suppressed because it is too large
+ 528 - 0
static/three.min.js


Some files were not shown because too many files changed in this diff