web viewer 3d finished

Tue, 04 Apr 2017 00:47:22 +0200

author
mdd
date
Tue, 04 Apr 2017 00:47:22 +0200
changeset 11
098335a1d510
parent 10
d26669bf424e
child 12
b3cf0176512e

web viewer 3d finished

cylindertransport-web.py file | annotate | diff | comparison | revisions
cylindertransport.py file | annotate | diff | comparison | revisions
data.py file | annotate | diff | comparison | revisions
stlviewer.css file | annotate | diff | comparison | revisions
stlviewer.html file | annotate | diff | comparison | revisions
stlviewer.js file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cylindertransport-web.py	Tue Apr 04 00:47:22 2017 +0200
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import cgi, data, json, config
+from cylindertransport import CylinderSpacerCalculator
+
+# enable debugging
+import cgitb, sys
+sys.stderr = sys.stdout
+#cgitb.enable()
+
+
+def do_action(args):
+    if args["action"].value == "calculate":
+        cylinders = args.getlist("cylinders[]")
+        calc = CylinderSpacerCalculator(cylinders)
+        calc.calculate()
+        print json.dumps({
+            "objects": calc.circles,
+            "scale3d": config.SCALE3D
+            })
+    else:
+        print "unknown Action %s" % args["action"].value
+
+
+
+
+
+
+print("Content-Type: text/html;charset=utf-8")
+print("")
+
+args = cgi.FieldStorage()
+if "action" in args:
+    do_action(args)
+else:
+    # display the html content
+    content = open("stlviewer.html", "r").read()
+    cyls = ""
+    for cyl in sorted(data.CYLINDER.keys()):
+        cyls += "<li key=\"%s\" weight=\"%s\">%s</li>" % (
+            cyl, data.CYLINDER[cyl][3], data.CYLINDER[cyl][4]);
+    content = content.replace("<!-- PLACEHOLDER CYLINDERS -->", cyls)
+
+    print content
--- a/cylindertransport.py	Mon Apr 03 20:04:15 2017 +0200
+++ b/cylindertransport.py	Tue Apr 04 00:47:22 2017 +0200
@@ -52,30 +52,36 @@
             x_2 = offset(r_2, i)
             posx = (x_1 + x_2) - (r_1 + r_2)
             if posx >= self.space_min:
-                print "// %s Pipe (%.1fmm), Cylinder spacing: %imm" % (
-                    pipe[0], pipe[1], posx)
-                return [r_1, i, r_2, pipe[0]]
+                #print "// %s Pipe (%.1fmm), Cylinder spacing: %imm" % (
+                #    pipe[0], pipe[1], posx)
+                return [r_1, i, r_2, pipe]
         print "// Abort: no suitable pipe found"
         sys.exit(1)
 
-    def _circle(self, posx, radius, txt="", size=1.0):
+    def _circle(self, posx, radius, data, cylinder = ""):
         """
         Push the circle definition for later rendering
         """
+        if cylinder == "":
+            size = 0.5
+            txt = data[0]
+        else:
+            size = 1.0
+            txt = "Tank " + cylinder
         self.circles.append([
-            posx, radius, txt, size
+            posx, radius, txt, size, data, cylinder
             ])
 
-    def _calculate(self):
+    def calculate(self):
         """
         Calculate all cylinder and spacer circles
         """
         # first bottle spacer
         r_1 = CYLINDER[self.cylinders[0]][0] / 2
         r_2 = CYLINDER[self.cylinders[1]][0] / 2
-        r_1, r_2, r_3, label = self.calc_min(r_1, r_2)
+        r_1, r_2, r_3, data = self.calc_min(r_1, r_2)
         posx = self.margin + r_2 # start offset x
-        self._circle(posx, r_2, label, 0.5)
+        self._circle(posx, r_2, data)
         self.scad["spacer"] += "spacer(%f, %f, %f, %f);\n" % (
             posx * SCALE3D, r_2 * SCALE3D, r_3 * SCALE3D,
             CYLINDER[self.cylinders[0]][1] * SCALE3D)
@@ -84,16 +90,17 @@
         for i in range(0, len(self.cylinders) - 1):
             r_1 = CYLINDER[self.cylinders[i]][0] / 2
             r_2 = CYLINDER[self.cylinders[i+1]][0] / 2
-            r_1, r_2, r_3, label = self.calc_min(r_1, r_2)
+            r_1, r_2, r_3, data = self.calc_min(r_1, r_2)
             # draw cylinder
-            self._circle(posx, r_1, "Tank " + self.cylinders[i])
+            self._circle(posx, r_1,
+                CYLINDER[self.cylinders[i]], self.cylinders[i])
             self.scad["cylinder"] += "tank(%f, %f, %f);\n" % (
                 posx * SCALE3D, r_1 * SCALE3D,
                 CYLINDER[self.cylinders[i]][1] * SCALE3D)
             sx1 = posx + r_1
             posx += offset(r_1, r_2)
             # draw right spacer
-            self._circle(posx, r_2, label, 0.5)
+            self._circle(posx, r_2, data)
             self.scad["spacer"] += "spacer(%f, %f, %f, %f);\n" % (
                 posx * SCALE3D, r_2 * SCALE3D, r_1 * SCALE3D,
                 CYLINDER[self.cylinders[i]][1] * SCALE3D)
@@ -101,7 +108,8 @@
             sx2 = posx - r_3
             if i == (len(self.cylinders) - 2):
                 # draw last bottle
-                self._circle(posx, r_3, "Tank " + self.cylinders[i + 1])
+                self._circle(posx, r_3,
+                    CYLINDER[self.cylinders[i + 1]], self.cylinders[i + 1])
                 self.scad["cylinder"] += "tank(%f, %f, %f);\n" % (
                     posx * SCALE3D, r_3 * SCALE3D,
                     CYLINDER[self.cylinders[i + 1]][1] * SCALE3D)
@@ -110,7 +118,7 @@
             self.spacings.append([sx1, sx2])
 
         # last bottle spacer pipe
-        self._circle(posx, r_2, label, 0.5)
+        self._circle(posx, r_2, data)
         self.scad["spacer"] += "spacer(%f, %f, %f, %f);\n" % (
             posx * SCALE3D, r_2 * SCALE3D, r_3 * SCALE3D,
             CYLINDER[self.cylinders[-1]][1] * SCALE3D)
@@ -129,11 +137,11 @@
         """
         Start the calculation and return rendered PIL image object
         """
-        self.width = self._calculate()
+        self.width = self.calculate()
         image = Image.new('1', (self.width, 250)) # create new image
         draw = ImageDraw.Draw(image)
         # draw calculated circles
-        for posx, radius, txt, size in self.circles:
+        for posx, radius, txt, size, data, cylinder in self.circles:
             draw.arc([posx - radius, self.margin, \
                 posx + radius, 2 * radius + self.margin], \
                 0, 360, 'white')
@@ -189,7 +197,8 @@
     if (options.scad != ""):
         with open(options.scad, "w") as fd:
             fd.write(worker.scad["tmpl"])
-            fd.write("translate([%f,0,0]) {\n" % (((worker.width - 2 * worker.margin) / -2)*worker.scale3d)) # center the object
+            fd.write("translate([%f,0,0]) {\n" % (
+                ((worker.width - 2 * worker.margin) / -2) * SCALE3D)) # center the object
             fd.write(worker.scad["cylinder"])
             fd.write(worker.scad["spacer"])
             fd.write("}\n")
--- a/data.py	Mon Apr 03 20:04:15 2017 +0200
+++ b/data.py	Tue Apr 04 00:47:22 2017 +0200
@@ -1,16 +1,18 @@
+# -*- coding: UTF-8 -*-
+
 # Durchmesser, Laenge, Volumen und Gewicht der verfuegbaren Tauchflaschen
 CYLINDER = {
-	"03"	: [100, 515, 3,  4.7],
-	"05"	: [140, 466, 5,	 5.7],
-	"07"	: [140, 605, 7,  8.8],
-	"08"	: [171, 490, 8,  10.4],
-	"10"	: [171, 595, 10, 12.4],
-	"12S"	: [204, 550, 12, 15.4],
-	"12L"	: [171, 690, 12, 14.5],
-	"15"	: [204, 640, 15, 18.1],
-	"16"	: [204, 670, 16, 19.5],
-	"18"	: [204, 710, 18, 20.5],
-	"20"	: [204, 810, 20, 22.0],
+	"03"	: [100, 515, 3,  4.7,	"Stahl, 3ℓ"],
+	"05"	: [140, 466, 5,	 5.7,	"Stahl, 5ℓ"],
+	"07"	: [140, 605, 7,  8.8,	"Stahl, 7ℓ"],
+	"08"	: [171, 490, 8,  10.4,	"Stahl, 8ℓ"],
+	"10"	: [171, 595, 10, 12.4,	"Stahl, 10ℓ"],
+	"12S"	: [204, 550, 12, 15.4,	"Stahl, 12ℓ kurz"],
+	"12L"	: [171, 690, 12, 14.5,	"Stahl, 12ℓ lang"],
+	"15"	: [204, 640, 15, 18.1,	"Stahl, 15ℓ"],
+	"16"	: [204, 670, 16, 19.5,	"Stahl, 16ℓ"],
+	"18"	: [204, 710, 18, 20.5,	"Stahl, 18ℓ"],
+	"20"	: [204, 810, 20, 22.0,	"Stahl, 20ℓ"],
 }
 
 # Standard Rohrdurchmesser (Mr. Baumarkt)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stlviewer.css	Tue Apr 04 00:47:22 2017 +0200
@@ -0,0 +1,54 @@
+      body {
+        font-family: Monospace;
+        background-color: #000000;
+        margin: 0px;
+        overflow: hidden;
+      }
+
+      #info {
+        color: #fff;
+        position: absolute;
+        top: 10px;
+        width: 100%;
+        text-align: center;
+        z-index: 100;
+        display:block;
+
+      }
+
+      a { color: skyblue }
+      .button { background:#999; color:#eee; padding:0.2em 0.5em; cursor:pointer }
+      .highlight { background:orange; color:#fff; }
+
+      span {
+        display: inline-block;
+        width: 60px;
+        float: left;
+        text-align: center;
+      }
+
+      
+  #sortable1, #sortable2 {
+    border: 1px solid #eee;
+    width: 142px;
+    min-height: 20px;
+    list-style-type: none;
+    margin: 0;
+    padding: 5px 0 0 0;
+    float: left;
+    margin-right: 10px;
+  }
+  #sortable1 li, #sortable2 li {
+    margin: 0 5px 5px 5px;
+    padding: 5px;
+    font-size: 1.2em;
+    width: 120px;
+    background: rgba(0,0,0,0.5);
+  }
+
+.listcontainer {
+  width: 157px;
+  height: 300px;
+  overflow-y: scroll;
+  overflow-x: hidden;
+}
\ No newline at end of file
--- a/stlviewer.html	Mon Apr 03 20:04:15 2017 +0200
+++ b/stlviewer.html	Tue Apr 04 00:47:22 2017 +0200
@@ -4,50 +4,43 @@
 		<title>ScubaTools Object Viewer</title>
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-		<style>
-			body {
-				font-family: Monospace;
-				background-color: #000000;
-				margin: 0px;
-				overflow: hidden;
-			}
 
-			#info {
-				color: #fff;
-				position: absolute;
-				top: 10px;
-				width: 100%;
-				text-align: center;
-				z-index: 100;
-				display:block;
-
-			}
+		<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" />
+		<link rel="stylesheet" href="stlviewer.css" />
+  		<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
+  		<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
 
-			a { color: skyblue }
-			.button { background:#999; color:#eee; padding:0.2em 0.5em; cursor:pointer }
-			.highlight { background:orange; color:#fff; }
+		<script src="https://threejs.org/build/three.js"></script>
+		<script src="https://threejs.org/examples/js/loaders/STLLoader.js"></script>
+        <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
 
-			span {
-				display: inline-block;
-				width: 60px;
-				float: left;
-				text-align: center;
-			}
-
-		</style>
     </head>
 	<body>
 		<div id="info">
+			<div class="listcontainer">
+				<h2>Available:</h2>
+				<ul id="sortable1">
+					<!-- PLACEHOLDER CYLINDERS -->
+				</ul>
+			</div>
+			<div class="listcontainer">
+				<h2>Selected:</h2>
+				<ul id="sortable2">
+					
+				</ul>
+			</div>
+
             <a href="https://neo-soft.org" target="_blank">NeoSoft</a> ScubaTools -  
 			<a href="https://threejs.org/" target="_blank">three.js</a> -
 			STL loader by <a href="https://github.com/aleeper" target="_blank">aleeper</a>.
             <br/>
             Left mouse: rotate camera, right mouse: move camera, middle mouse or wheel: zoom
+
+
 		</div>
 
-		<script src="https://threejs.org/build/three.js"></script>
-		<script src="https://threejs.org/examples/js/loaders/STLLoader.js"></script>
-        <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
+		<script src="stlviewer.js"></script>
+
 		<script>
 			var container;
 			var camera, cameraTarget, scene, renderer;
@@ -55,127 +48,6 @@
 			init();
 			animate();
 
-			function init() {
-				container = document.createElement( 'div' );
-				document.body.appendChild( container );
-
-				camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 1, 15 );
-				camera.position.set( 3, 0.35, 3 );
-
-				cameraTarget = new THREE.Vector3( 0, -0.25, 0 );
-
-				scene = new THREE.Scene();
-				scene.fog = new THREE.Fog( 0x72645b, 2, 15 );
-
-                var controls = new THREE.OrbitControls(camera);
-
-				// Ground
-
-				var plane = new THREE.Mesh(
-					new THREE.PlaneBufferGeometry( 40, 40 ),
-					new THREE.MeshPhongMaterial( { color: 0x999999, specular: 0x101010 } )
-				);
-				plane.rotation.x = -Math.PI/2;
-				plane.position.y = -0.5;
-				scene.add( plane );
-
-				plane.receiveShadow = true;
-
-				// ASCII file
-
-				var loader = new THREE.STLLoader();
-				loader.load( './test.stl', function ( geometry ) {
-
-					var material = new THREE.MeshPhongMaterial( { color: 0xff5533, specular: 0x111111, shininess: 200 } );
-					var mesh = new THREE.Mesh( geometry, material );
-
-					mesh.position.set( 0, -0.25, 0 );
-					mesh.rotation.set( 0, Math.PI / 2, 0 );
-					mesh.scale.set( 0.01, 0.01, 0.01 );
-
-					mesh.castShadow = true;
-					//mesh.receiveShadow = true;
-
-					scene.add( mesh );
-
-				} );
-
-				// Lights
-
-				scene.add( new THREE.HemisphereLight( 0x443333, 0x111122 ) );
-
-				addShadowedLight( 1, 1, 1, 0xffffff, 1.35 );
-				//addShadowedLight( 0.5, 1, -1, 0xffaa00, 1 );
-				// renderer
-
-				renderer = new THREE.WebGLRenderer( { antialias: true } );
-				renderer.setClearColor( scene.fog.color );
-				renderer.setPixelRatio( window.devicePixelRatio );
-				renderer.setSize( window.innerWidth, window.innerHeight );
-
-				renderer.gammaInput = true;
-				renderer.gammaOutput = true;
-
-				renderer.shadowMap.enabled = true;
-				renderer.shadowMap.renderReverseSided = false;
-
-				container.appendChild( renderer.domElement );
-
-				window.addEventListener( 'resize', onWindowResize, false );
-
-			}
-
-			function addShadowedLight( x, y, z, color, intensity ) {
-
-				var directionalLight = new THREE.DirectionalLight( color, intensity );
-				directionalLight.position.set( x, y, z );
-				scene.add( directionalLight );
-
-				directionalLight.castShadow = true;
-
-				var d = 1;
-				directionalLight.shadow.camera.left = -d;
-				directionalLight.shadow.camera.right = d;
-				directionalLight.shadow.camera.top = d;
-				directionalLight.shadow.camera.bottom = -d;
-
-				directionalLight.shadow.camera.near = 1;
-				directionalLight.shadow.camera.far = 4;
-
-				directionalLight.shadow.mapSize.width = 1024;
-				directionalLight.shadow.mapSize.height = 1024;
-
-				directionalLight.shadow.bias = -0.005;
-
-			}
-
-			function onWindowResize() {
-
-				camera.aspect = window.innerWidth / window.innerHeight;
-				camera.updateProjectionMatrix();
-
-				renderer.setSize( window.innerWidth, window.innerHeight );
-
-			}
-
-			function animate() {
-
-				requestAnimationFrame( animate );
-
-				//render();
-                renderer.render( scene, camera );
-				//stats.update();
-
-			}
-
-			function render() {
-				var timer = Date.now() * 0.0005;
-				camera.position.x = Math.cos( timer ) * 3;
-				camera.position.z = Math.sin( timer ) * 3;
-				camera.lookAt( cameraTarget );
-				renderer.render( scene, camera );
-			}
-
 		</script><div><canvas style="width: 1589px; height: 711px;" height="711" width="1589"></canvas><div style="position: fixed; top: 0px; left: 0px; cursor: pointer; opacity: 0.9; z-index: 10000;"><canvas style="width: 80px; height: 48px; display: block;" height="48" width="80"></canvas><canvas style="width: 80px; height: 48px; display: none;" height="48" width="80"></canvas></div></div>
 	
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stlviewer.js	Tue Apr 04 00:47:22 2017 +0200
@@ -0,0 +1,199 @@
+$( function() {
+    $( "#sortable1 li" ).draggable({
+        helper: "clone",
+        containment:"document"
+        });
+    $( "#sortable2" ).droppable({
+        accept: "#sortable1 li",
+        drop: function( event, ui ) {
+            ui.draggable.clone(false).appendTo($(this));
+            for (i =0; i<10; i++) clear_scene();
+            window.setTimeout(update_scene,500);
+        }
+    });
+    $( "#sortable2" ).sortable({
+        placeholder: "ui-state-highlight",
+        start: clear_scene,
+        stop: function() {
+            for (i =0; i<10; i++) clear_scene();
+            window.setTimeout(update_scene,500)
+        }
+    });
+    $( "#sortable2" ).disableSelection();
+} );
+
+function clear_scene() {
+    scene.children.forEach(function(v){
+        if(v.stlfile === true) {
+            v.material.dispose();
+            v.geometry.dispose();
+            scene.remove(v);
+        }
+        //scene.remove(object);
+    });
+}
+
+function update_scene() {
+    var cylinders = [];
+    $("#sortable2 li").each(function(idx, e){
+        cylinders.push($(e).attr('key'));
+    });
+    if (cylinders.length < 2) return;
+
+    // fetch new objects list
+    $.ajax({
+        url: "#",
+        method: 'post',
+        dataType: 'json',
+        data: {
+            action: 'calculate',
+            cylinders: cylinders
+        },
+        success: function(data) {
+            //console.log(data);
+            // remove all meshes
+            clear_scene();
+            // append the objects with positioning
+            for (i = 0; i<data.objects.length; i++) {
+                var obj = data.objects[i];
+                if (obj[5] == "") {
+                    // spacer
+                    filename = "stl/spacer_" + obj[4][0] + '.stl';
+                } else {
+                    // cylinder
+                    filename = "stl/cylinder_" + obj[5] + '.stl';
+                }
+                position = [data.scale3d * 0.01 * obj[0], 0, 0];
+                loadSTL(filename, null, position);
+            }
+
+        }
+    });
+}
+
+function loadSTL(filename, material, position, rotation, scale) {
+    //console.log(filename, position);
+    var loader = new THREE.STLLoader();
+    loader.load( filename, function ( geometry ) {
+        if (!material)
+            var material = new THREE.MeshPhongMaterial( {
+                color: 0xff5533, specular: 0x111111, shininess: 200 } );
+        var mesh = new THREE.Mesh( geometry, material );
+        mesh["stlfile"] = true;
+        if (!position) mesh.position.set( 0, -0.25, 0 ); else 
+            mesh.position.set( position[0], position[1], position[2] );
+        if (!rotation) mesh.rotation.set( 0, 0, 0 ); else 
+            mesh.rotation.set( rotation[0], rotation[1], rotation[2] );
+        if (!scale) mesh.scale.set( 0.01, 0.01, 0.01 ); else 
+            mesh.scale.set( scale[0], scale[1], scale[2] );
+
+        mesh.castShadow = true;
+        mesh.receiveShadow = true;
+
+        scene.add( mesh );
+
+    } );
+
+}
+
+function init() {
+    container = document.createElement( 'div' );
+    document.body.appendChild( container );
+
+    camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 20 );
+    camera.position.set( 0.5, 0.35, 2 );
+
+    cameraTarget = new THREE.Vector3( 0, -0.25, 0 );
+
+    scene = new THREE.Scene();
+    scene.fog = new THREE.Fog( 0x72645b, 2, 15 );
+
+    var controls = new THREE.OrbitControls(camera);
+
+    // Ground
+
+    var plane = new THREE.Mesh(
+        new THREE.PlaneBufferGeometry( 40, 40 ),
+        new THREE.MeshPhongMaterial( { color: 0x999999, specular: 0x101010 } )
+    );
+    plane.rotation.x = -Math.PI/2;
+    plane.position.y = -0.5;
+    scene.add( plane );
+
+    plane.receiveShadow = true;
+
+    // Lights
+
+    scene.add( new THREE.HemisphereLight( 0x443333, 0x111122 ) );
+
+    addShadowedLight( 1, 1, 1, 0xffffff, 1.35 );
+    //addShadowedLight( 0.5, 1, -1, 0xffaa00, 1 );
+    // renderer
+
+    renderer = new THREE.WebGLRenderer( { antialias: true } );
+    renderer.setClearColor( scene.fog.color );
+    renderer.setPixelRatio( window.devicePixelRatio );
+    renderer.setSize( window.innerWidth, window.innerHeight );
+
+    renderer.gammaInput = true;
+    renderer.gammaOutput = true;
+
+    renderer.shadowMap.enabled = true;
+    renderer.shadowMap.renderReverseSided = true;
+
+    container.appendChild( renderer.domElement );
+
+    window.addEventListener( 'resize', onWindowResize, false );
+
+}
+
+function addShadowedLight( x, y, z, color, intensity ) {
+
+    var directionalLight = new THREE.DirectionalLight( color, intensity );
+    directionalLight.position.set( x, y, z );
+    scene.add( directionalLight );
+
+    directionalLight.castShadow = true;
+
+    var d = 5;
+    directionalLight.shadow.camera.left = -d;
+    directionalLight.shadow.camera.right = d;
+    directionalLight.shadow.camera.top = d;
+    directionalLight.shadow.camera.bottom = -d;
+
+    directionalLight.shadow.camera.near = 1;
+    directionalLight.shadow.camera.far = 20;
+
+    directionalLight.shadow.mapSize.width = 1024;
+    directionalLight.shadow.mapSize.height = 1024;
+
+    directionalLight.shadow.bias = -0.005;
+
+}
+
+function onWindowResize() {
+
+    camera.aspect = window.innerWidth / window.innerHeight;
+    camera.updateProjectionMatrix();
+
+    renderer.setSize( window.innerWidth, window.innerHeight );
+
+}
+
+function animate() {
+
+    requestAnimationFrame( animate );
+
+    //render();
+    renderer.render( scene, camera );
+    //stats.update();
+
+}
+
+function render() {
+    var timer = Date.now() * 0.0005;
+    camera.position.x = Math.cos( timer ) * 3;
+    camera.position.z = Math.sin( timer ) * 3;
+    camera.lookAt( cameraTarget );
+    renderer.render( scene, camera );
+}
\ No newline at end of file

mercurial