From 8a368c069046f5eecc6de6219976e6b608c0c8eb Mon Sep 17 00:00:00 2001 From: Neil Gershenfeld <gersh@cba.mit.edu> Date: Sun, 31 Oct 2021 11:52:21 -0400 Subject: [PATCH] wip --- programs/machines/Roland/mill/SRM-20/mill 3D stl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/machines/Roland/mill/SRM-20/mill 3D stl b/programs/machines/Roland/mill/SRM-20/mill 3D stl index 3fa106b..d559f1c 100644 --- a/programs/machines/Roland/mill/SRM-20/mill 3D stl +++ b/programs/machines/Roland/mill/SRM-20/mill 3D stl @@ -1 +1 @@ -{"modules":{"0.0622871075904039":{"definition":"//\n// read stl\n//\n// Neil Gershenfeld\n// (c) Massachusetts Institute of Technology 2018\n//\n// This work may be reproduced, modified, distributed, performed, and\n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is\n// provided as is; no warranty is provided, and users accept all\n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'read STL'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\n }\n//\n// outputs\n//\nvar outputs = {\n mesh:{type:'STL',\n event:function(buffer){\n mods.output(mod,'mesh',buffer)}}\n }\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // file input control\n //\n var file = document.createElement('input')\n file.setAttribute('type','file')\n file.setAttribute('id',div.id+'file_input')\n file.style.position = 'absolute'\n file.style.left = 0\n file.style.top = 0\n file.style.width = 0\n file.style.height = 0\n file.style.opacity = 0\n file.addEventListener('change',function() {\n stl_read_handler()\n })\n div.appendChild(file)\n mod.file = file\n //\n // canvas\n //\n var canvas = document.createElement('canvas')\n canvas.width = mods.ui.canvas\n canvas.height = mods.ui.canvas\n canvas.style.backgroundColor = 'rgb(255,255,255)'\n div.appendChild(canvas)\n mod.canvas = canvas\n div.appendChild(document.createElement('br'))\n //\n // file select button\n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('select stl file'))\n btn.addEventListener('click',function(){\n var file = document.getElementById(div.id+'file_input')\n file.value = null\n file.click()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // info\n //\n var info = document.createElement('div')\n info.setAttribute('id',div.id+'info')\n var text = document.createTextNode('name: ')\n info.appendChild(text)\n mod.namen = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('size: ')\n info.appendChild(text)\n mod.sizen = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('triangles: ')\n info.appendChild(text)\n mod.trianglesn = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('dx: ')\n info.appendChild(text)\n mod.dxn = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('dy: ')\n info.appendChild(text)\n mod.dyn = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('dz: ')\n info.appendChild(text)\n mod.dzn = text\n div.appendChild(info)\n }\n//\n// local functions\n//\n// read handler\n//\nfunction stl_read_handler(event) {\n var file_reader = new FileReader()\n file_reader.onload = stl_load_handler\n input_file = mod.file.files[0]\n file_name = input_file.name\n mod.namen.nodeValue = 'name: '+file_name\n file_reader.readAsArrayBuffer(input_file)\n }\n//\n// load handler\n//\nfunction stl_load_handler(event) {\n //\n // check for binary STL\n //\n var endian = true\n var view = new DataView(event.target.result)\n var triangles = view.getUint32(80,endian)\n var size = 80+4+triangles*(4*12+2)\n if (size != view.byteLength) {\n mod.sizen.nodeValue = 'error: not binary STL'\n mod.trianglesn.nodeValue = ''\n mod.dxn.nodeValue = ''\n mod.dyn.nodeValue = ''\n mod.dzn.nodeValue = ''\n return\n }\n mod.sizen.nodeValue = 'size: '+size\n mod.trianglesn.nodeValue = 'triangles: '+triangles\n //\n // find limits and draw\n //\n var blob = new Blob(['('+draw_limits_worker.toString()+'())'])\n var url = window.URL.createObjectURL(blob)\n var webworker = new Worker(url)\n webworker.addEventListener('message',function(evt) {\n //\n // worker response\n //\n window.URL.revokeObjectURL(url)\n //\n // size\n //\n mod.dxn.nodeValue = 'dx: '+evt.data.dx.toFixed(3)\n mod.dyn.nodeValue = 'dy: '+evt.data.dy.toFixed(3)\n mod.dzn.nodeValue = 'dz: '+evt.data.dz.toFixed(3)\n //\n // image\n //\n var image = evt.data.image\n var height = mod.canvas.height\n var width = mod.canvas.width\n var buffer = new Uint8ClampedArray(evt.data.image)\n var imgdata = new ImageData(buffer,width,height)\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.putImageData(imgdata,0,0)\n //\n // output\n //\n outputs.mesh.event(evt.data.mesh)\n })\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n var img = ctx.getImageData(0,0,mod.canvas.width,mod.canvas.height)\n //\n // call worker\n //\n webworker.postMessage({\n height:mod.canvas.height,width:mod.canvas.width,\n image:img.data.buffer,mesh:event.target.result},\n [img.data.buffer,event.target.result])\n }\nfunction draw_limits_worker() {\n self.addEventListener('message',function(evt) {\n //\n // function to draw line\n //\n function line(x0,y0,x1,y1) {\n var ix0 = Math.floor(xo+xw*(x0-xmin)/dx)\n var iy0 = Math.floor(yo+yh*(ymax-y0)/dy)\n var ix1 = Math.floor(xo+xw*(x1-xmin)/dx)\n var iy1 = Math.floor(yo+yh*(ymax-y1)/dy)\n var row,col\n var idx = ix1-ix0\n var idy = iy1-iy0\n if (Math.abs(idy) > Math.abs(idx)) {\n (idy > 0) ?\n (row0=iy0,col0=ix0,row1=iy1,col1=ix1):\n (row0=iy1,col0=ix1,row1=iy0,col1=ix0)\n for (row = row0; row <= row1; ++row) {\n col = Math.floor(col0+(col1-col0)*(row-row0)/(row1-row0))\n image[row*width*4+col*4+0] = 0\n image[row*width*4+col*4+1] = 0\n image[row*width*4+col*4+2] = 0\n image[row*width*4+col*4+3] = 255\n }\n }\n else if ((Math.abs(idx) >= Math.abs(idy)) && (idx != 0)) {\n (idx > 0) ?\n (row0=iy0,col0=ix0,row1=iy1,col1=ix1):\n (row0=iy1,col0=ix1,row1=iy0,col1=ix0)\n for (col = col0; col <= col1; ++col) {\n row = Math.floor(row0+(row1-row0)*(col-col0)/(col1-col0))\n image[row*width*4+col*4+0] = 0\n image[row*width*4+col*4+1] = 0\n image[row*width*4+col*4+2] = 0\n image[row*width*4+col*4+3] = 255\n }\n }\n else {\n row = iy0\n col = ix0\n image[row*width*4+col*4+0] = 0\n image[row*width*4+col*4+1] = 0\n image[row*width*4+col*4+2] = 0\n image[row*width*4+col*4+3] = 255\n }\n }\n //\n // get variables\n //\n var height = evt.data.height\n var width = evt.data.width\n var endian = true\n var image = new Uint8ClampedArray(evt.data.image)\n var view = new DataView(evt.data.mesh)\n var triangles = view.getUint32(80,endian)\n //\n // find limits\n //\n var offset = 80+4\n var x0,x1,x2,y0,y1,y2,z0,z1,z2\n var xmin = Number.MAX_VALUE\n var xmax = -Number.MAX_VALUE\n var ymin = Number.MAX_VALUE\n var ymax = -Number.MAX_VALUE\n var zmin = Number.MAX_VALUE\n var zmax = -Number.MAX_VALUE\n for (var t = 0; t < triangles; ++t) {\n offset += 3*4\n x0 = view.getFloat32(offset,endian)\n offset += 4\n if (x0 > xmax) xmax = x0\n if (x0 < xmin) xmin = x0\n y0 = view.getFloat32(offset,endian)\n offset += 4\n if (y0 > ymax) ymax = y0\n if (y0 < ymin) ymin = y0\n z0 = view.getFloat32(offset,endian)\n offset += 4\n if (z0 > zmax) zmax = z0\n if (z0 < zmin) zmin = z0\n x1 = view.getFloat32(offset,endian)\n offset += 4\n if (x1 > xmax) xmax = x1\n if (x1 < xmin) xmin = x1\n y1 = view.getFloat32(offset,endian)\n offset += 4\n if (y1 > ymax) ymax = y1\n if (y1 < ymin) ymin = y1\n z1 = view.getFloat32(offset,endian)\n offset += 4\n if (z1 > zmax) zmax = z1\n if (z1 < zmin) zmin = z1\n x2 = view.getFloat32(offset,endian)\n offset += 4\n if (x2 > xmax) xmax = x2\n if (x2 < xmin) xmin = x2\n y2 = view.getFloat32(offset,endian)\n offset += 4\n if (y2 > ymax) ymax = y2\n if (y2 < ymin) ymin = y2\n z2 = view.getFloat32(offset,endian)\n offset += 4\n if (z2 > zmax) zmax = z2\n if (z2 < zmin) zmin = z2\n offset += 2\n }\n var dx = xmax-xmin\n var dy = ymax-ymin\n var dz = zmax-zmin\n //\n // draw mesh\n //\n if (dx > dy) {\n var xo = 0\n var yo = height*.5*(1-dy/dx)\n var xw = width-1\n var yh = (width-1)*dy/dx\n }\n else {\n var xo = width*.5*(1-dx/dy)\n var yo = 0\n var xw = (height-1)*dx/dy\n var yh = height-1\n }\n offset = 80+4\n for (var t = 0; t < triangles; ++t) {\n offset += 3*4\n x0 = view.getFloat32(offset,endian)\n offset += 4\n y0 = view.getFloat32(offset,endian)\n offset += 4\n z0 = view.getFloat32(offset,endian)\n offset += 4\n x1 = view.getFloat32(offset,endian)\n offset += 4\n y1 = view.getFloat32(offset,endian)\n offset += 4\n z1 = view.getFloat32(offset,endian)\n offset += 4\n x2 = view.getFloat32(offset,endian)\n offset += 4\n y2 = view.getFloat32(offset,endian)\n offset += 4\n z2 = view.getFloat32(offset,endian)\n offset += 4\n offset += 2\n line(x0,y0,x1,y1)\n line(x1,y1,x2,y2)\n line(x2,y2,x0,y0)\n }\n //\n // return results and close\n //\n self.postMessage({\n dx:dx,dy:dy,dz:dz,\n image:evt.data.image,mesh:evt.data.mesh},[evt.data.image,evt.data.mesh])\n self.close()\n })\n }\n//\n// return values\n//\nreturn ({\n mod:mod,\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"121.4689005070139","left":"231.1238074852728","filename":"undefined","inputs":{},"outputs":{}},"0.908940842104825":{"definition":"//\n// mesh rotate\n// \n// Neil Gershenfeld\n// (c) Massachusetts Institute of Technology 2018\n//\n// This work may be reproduced, modified, distributed, performed, and\n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is\n// provided as is; no warranty is provided, and users accept all\n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'mesh rotate'\n//\n// initialization\n//\nvar init = function() {\n mod.rx.value = '0'\n mod.ry.value = '0'\n mod.rz.value = '0'\n }\n//\n// inputs\n//\nvar inputs = {\n mesh:{type:'STL',\n event:function(evt){\n mod.mesh = evt.detail\n rotate_mesh()}}}\n//\n// outputs\n//\nvar outputs = {\n mesh:{type:'STL',\n event:function(buffer){\n mods.output(mod,'mesh',buffer)}}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // canvas\n //\n var canvas = document.createElement('canvas')\n canvas.width = mods.ui.canvas\n canvas.height = mods.ui.canvas\n canvas.style.backgroundColor = 'rgb(255,255,255)'\n div.appendChild(canvas)\n mod.canvas = canvas\n div.appendChild(document.createElement('br'))\n //\n // rotation\n //\n div.appendChild(document.createTextNode('rotation (degrees):'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode(' x: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n rotate_mesh()\n })\n div.appendChild(input)\n mod.rx = input\n div.appendChild(document.createTextNode(' y: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n rotate_mesh()\n })\n div.appendChild(input)\n mod.ry = input\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode(' z: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n rotate_mesh()\n })\n div.appendChild(input)\n mod.rz = input\n div.appendChild(document.createTextNode(' (enter)'))\n div.appendChild(document.createElement('br'))\n //\n // info\n //\n var text = document.createTextNode('dx:')\n div.appendChild(text)\n mod.dxn = text\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('dy:')\n div.appendChild(text)\n mod.dyn = text\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('dz:')\n div.appendChild(text)\n mod.dzn = text\n div.appendChild(document.createElement('br'))\n }\n//\n// local functions\n//\n// rotate mesh\n//\nfunction rotate_mesh() {\n //\n // check for binary STL\n //\n var endian = true\n var view = new DataView(mod.mesh)\n var triangles = view.getUint32(80,endian)\n var size = 80+4+triangles*(4*12+2)\n //\n // find limits, rotate, and draw\n //\n var blob = new Blob(['('+rotate_mesh_worker.toString()+'())'])\n var url = window.URL.createObjectURL(blob)\n var webworker = new Worker(url)\n webworker.addEventListener('message',function(evt) {\n //\n // worker response\n //\n window.URL.revokeObjectURL(url)\n //\n // size\n //\n mod.dxn.nodeValue = 'dx: '+evt.data.dx.toFixed(3)\n mod.dyn.nodeValue = 'dy: '+evt.data.dy.toFixed(3)\n mod.dzn.nodeValue = 'dz: '+evt.data.dz.toFixed(3)\n //\n // image\n //\n var image = evt.data.image\n var height = mod.canvas.height\n var width = mod.canvas.width\n var buffer = new Uint8ClampedArray(evt.data.image)\n var imgdata = new ImageData(buffer,width,height)\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.putImageData(imgdata,0,0)\n //\n // mesh\n //\n mod.mesh = evt.data.mesh\n //\n // output\n //\n outputs.mesh.event(evt.data.rotate)\n })\n //\n // call worker\n //\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n var img = ctx.getImageData(0,0,mod.canvas.width,mod.canvas.height)\n var rx = parseFloat(mod.rx.value)*Math.PI/180\n var ry = parseFloat(mod.ry.value)*Math.PI/180\n var rz = parseFloat(mod.rz.value)*Math.PI/180\n webworker.postMessage({\n height:mod.canvas.height,width:mod.canvas.width,\n rx:rx,ry:ry,rz:rz,\n image:img.data.buffer,mesh:mod.mesh},\n [img.data.buffer,mod.mesh])\n }\nfunction rotate_mesh_worker() {\n self.addEventListener('message',function(evt) {\n //\n // function to draw line\n //\n function line(x0,y0,x1,y1) {\n var ix0 = Math.floor(xo+xw*(x0-xmin)/dx)\n var iy0 = Math.floor(yo+yh*(ymax-y0)/dy)\n var ix1 = Math.floor(xo+xw*(x1-xmin)/dx)\n var iy1 = Math.floor(yo+yh*(ymax-y1)/dy)\n var row,col\n var idx = ix1-ix0\n var idy = iy1-iy0\n if (Math.abs(idy) > Math.abs(idx)) {\n (idy > 0) ?\n (row0=iy0,col0=ix0,row1=iy1,col1=ix1):\n (row0=iy1,col0=ix1,row1=iy0,col1=ix0)\n for (row = row0; row <= row1; ++row) {\n col = Math.floor(col0+(col1-col0)*(row-row0)/(row1-row0))\n image[row*width*4+col*4+0] = 0\n image[row*width*4+col*4+1] = 0\n image[row*width*4+col*4+2] = 0\n image[row*width*4+col*4+3] = 255\n }\n }\n else if ((Math.abs(idx) >= Math.abs(idy)) && (idx != 0)) {\n (idx > 0) ?\n (row0=iy0,col0=ix0,row1=iy1,col1=ix1):\n (row0=iy1,col0=ix1,row1=iy0,col1=ix0)\n for (col = col0; col <= col1; ++col) {\n row = Math.floor(row0+(row1-row0)*(col-col0)/(col1-col0))\n image[row*width*4+col*4+0] = 0\n image[row*width*4+col*4+1] = 0\n image[row*width*4+col*4+2] = 0\n image[row*width*4+col*4+3] = 255\n }\n }\n else {\n row = iy0\n col = ix0\n image[row*width*4+col*4+0] = 0\n image[row*width*4+col*4+1] = 0\n image[row*width*4+col*4+2] = 0\n image[row*width*4+col*4+3] = 255\n }\n }\n //\n // function to rotate point\n //\n function rotate(x,y,z) {\n var x1 = x\n var y1 = Math.cos(rx)*y-Math.sin(rx)*z\n var z1 = Math.sin(rx)*y+Math.cos(rx)*z\n var x2 = Math.cos(ry)*x1-Math.sin(ry)*z1\n var y2 = y1\n var z2 = Math.sin(ry)*x1+Math.cos(ry)*z1\n var x3 = Math.cos(rz)*x2-Math.sin(rz)*y2\n var y3 = Math.sin(rz)*x2+Math.cos(rz)*y2\n var z3 = z2\n //return([x3,y3,z3])\n return({x:x3,y:y3,z:z3})\n }\n //\n // get variables\n //\n var height = evt.data.height\n var width = evt.data.width\n var rx = evt.data.rx\n var ry = evt.data.ry\n var rz = evt.data.rz\n var endian = true\n var image = new Uint8ClampedArray(evt.data.image)\n var view = new DataView(evt.data.mesh)\n var triangles = view.getUint32(80,endian)\n //\n // find limits\n //\n var offset = 80+4\n var x0,x1,x2,y0,y1,y2,z0,z1,z2\n var xmin = Number.MAX_VALUE\n var xmax = -Number.MAX_VALUE\n var ymin = Number.MAX_VALUE\n var ymax = -Number.MAX_VALUE\n var zmin = Number.MAX_VALUE\n var zmax = -Number.MAX_VALUE\n for (var t = 0; t < triangles; ++t) {\n offset += 3*4\n x0 = view.getFloat32(offset,endian)\n offset += 4\n y0 = view.getFloat32(offset,endian)\n offset += 4\n z0 = view.getFloat32(offset,endian)\n offset += 4\n x1 = view.getFloat32(offset,endian)\n offset += 4\n y1 = view.getFloat32(offset,endian)\n offset += 4\n z1 = view.getFloat32(offset,endian)\n offset += 4\n x2 = view.getFloat32(offset,endian)\n offset += 4\n y2 = view.getFloat32(offset,endian)\n offset += 4\n z2 = view.getFloat32(offset,endian)\n offset += 4\n offset += 2\n var p0 = rotate(x0,y0,z0)\n if (p0.x > xmax) xmax = p0.x\n if (p0.x < xmin) xmin = p0.x\n if (p0.y > ymax) ymax = p0.y\n if (p0.y < ymin) ymin = p0.y\n if (p0.z > zmax) zmax = p0.z\n if (p0.z < zmin) zmin = p0.z\n var p1 = rotate(x1,y1,z1)\n if (p1.x > xmax) xmax = p1.x\n if (p1.x < xmin) xmin = p1.x\n if (p1.y > ymax) ymax = p1.y\n if (p1.y < ymin) ymin = p1.y\n if (p1.z > zmax) zmax = p1.z\n if (p1.z < zmin) zmin = p1.z\n var p2 = rotate(x2,y2,z2)\n if (p2.x > xmax) xmax = p2.x\n if (p2.x < xmin) xmin = p2.x\n if (p2.y > ymax) ymax = p2.y\n if (p2.y < ymin) ymin = p2.y\n if (p2.z > zmax) zmax = p2.z\n if (p2.z < zmin) zmin = p2.z\n }\n var dx = xmax-xmin\n var dy = ymax-ymin\n var dz = zmax-zmin\n //\n // copy mesh\n //\n var newbuf = evt.data.mesh.slice(0)\n var newview = new DataView(newbuf)\n //\n // copy and draw mesh\n //\n if (dx > dy) {\n var xo = 0\n var yo = height*.5*(1-dy/dx)\n var xw = (width-1)\n var yh = (width-1)*dy/dx\n }\n else {\n var xo = width*.5*(1-dx/dy)\n var yo = 0\n var xw = (height-1)*dx/dy\n var yh = (height-1)\n }\n offset = 80+4\n var newoffset = 80+4\n for (var t = 0; t < triangles; ++t) {\n offset += 3*4\n x0 = view.getFloat32(offset,endian)\n offset += 4\n y0 = view.getFloat32(offset,endian)\n offset += 4\n z0 = view.getFloat32(offset,endian)\n offset += 4\n x1 = view.getFloat32(offset,endian)\n offset += 4\n y1 = view.getFloat32(offset,endian)\n offset += 4\n z1 = view.getFloat32(offset,endian)\n offset += 4\n x2 = view.getFloat32(offset,endian)\n offset += 4\n y2 = view.getFloat32(offset,endian)\n offset += 4\n z2 = view.getFloat32(offset,endian)\n offset += 4\n offset += 2\n var p0 = rotate(x0,y0,z0)\n var p1 = rotate(x1,y1,z1)\n var p2 = rotate(x2,y2,z2)\n line(p0.x,p0.y,p1.x,p1.y)\n line(p1.x,p1.y,p2.x,p2.y)\n line(p2.x,p2.y,p0.x,p0.y)\n newoffset += 3*4\n newview.setFloat32(newoffset,p0.x,endian)\n newoffset += 4\n newview.setFloat32(newoffset,p0.y,endian)\n newoffset += 4\n newview.setFloat32(newoffset,p0.z,endian)\n newoffset += 4\n newview.setFloat32(newoffset,p1.x,endian)\n newoffset += 4\n newview.setFloat32(newoffset,p1.y,endian)\n newoffset += 4\n newview.setFloat32(newoffset,p1.z,endian)\n newoffset += 4\n newview.setFloat32(newoffset,p2.x,endian)\n newoffset += 4\n newview.setFloat32(newoffset,p2.y,endian)\n newoffset += 4\n newview.setFloat32(newoffset,p2.z,endian)\n newoffset += 4\n newoffset += 2\n }\n //\n // return results and close\n //\n self.postMessage({\n dx:dx,dy:dy,dz:dz,\n image:evt.data.image,mesh:evt.data.mesh,rotate:newbuf},\n [evt.data.image,evt.data.mesh,newbuf])\n self.close()\n })\n }\nfunction old_rotate_mesh() {\n //\n // function to rotate point\n //\n function rotate(x,y,z) {\n var x1 = x\n var y1 = Math.cos(rx)*y-Math.sin(rx)*z\n var z1 = Math.sin(rx)*y+Math.cos(rx)*z\n var x2 = Math.cos(ry)*x1-Math.sin(ry)*z1\n var y2 = y1\n var z2 = Math.sin(ry)*x1+Math.cos(ry)*z1\n var x3 = Math.cos(rz)*x2-Math.sin(rz)*y2\n var y3 = Math.sin(rz)*x2+Math.cos(rz)*y2\n var z3 = z2\n return([x3,y3,z3])\n }\n //\n // get vars\n //\n var view = mod.mesh\n var endian = true\n var triangles = view.getUint32(80,endian)\n mod.triangles = triangles\n var size = 80+4+triangles*(4*12+2)\n var rx = parseFloat(mod.rx.value)*Math.PI/180\n var ry = parseFloat(mod.ry.value)*Math.PI/180\n var rz = parseFloat(mod.rz.value)*Math.PI/180\n //\n // find limits\n //\n var offset = 80+4\n var x0,x1,x2,y0,y1,y2,z0,z1,z2\n var xmin = Number.MAX_VALUE\n var xmax = -Number.MAX_VALUE\n var ymin = Number.MAX_VALUE\n var ymax = -Number.MAX_VALUE\n var zmin = Number.MAX_VALUE\n var zmax = -Number.MAX_VALUE\n for (var t = 0; t < triangles; ++t) {\n offset += 3*4\n x0 = view.getFloat32(offset,endian)\n offset += 4\n y0 = view.getFloat32(offset,endian)\n offset += 4\n z0 = view.getFloat32(offset,endian)\n offset += 4\n x1 = view.getFloat32(offset,endian)\n offset += 4\n y1 = view.getFloat32(offset,endian)\n offset += 4\n z1 = view.getFloat32(offset,endian)\n offset += 4\n x2 = view.getFloat32(offset,endian)\n offset += 4\n y2 = view.getFloat32(offset,endian)\n offset += 4\n z2 = view.getFloat32(offset,endian)\n offset += 4\n offset += 2\n var p0 = rotate(x0,y0,z0)\n if (p0[0] > xmax) xmax = p0[0]\n if (p0[0] < xmin) xmin = p0[0]\n if (p0[1] > ymax) ymax = p0[1]\n if (p0[1] < ymin) ymin = p0[1]\n if (p0[2] > zmax) zmax = p0[2]\n if (p0[2] < zmin) zmin = p0[2]\n var p1 = rotate(x1,y1,z1)\n if (p1[0] > xmax) xmax = p1[0]\n if (p1[0] < xmin) xmin = p1[0]\n if (p1[1] > ymax) ymax = p1[1]\n if (p1[1] < ymin) ymin = p1[1]\n if (p1[2] > zmax) zmax = p1[2]\n if (p1[2] < zmin) zmin = p1[2]\n var p2 = rotate(x2,y2,z2)\n if (p2[0] > xmax) xmax = p2[0]\n if (p2[0] < xmin) xmin = p2[0]\n if (p2[1] > ymax) ymax = p2[1]\n if (p2[1] < ymin) ymin = p2[1]\n if (p2[2] > zmax) zmax = p2[2]\n if (p2[2] < zmin) zmin = p2[2]\n }\n mod.dx = xmax-xmin\n mod.dy = ymax-ymin\n mod.dz = zmax-zmin\n mod.dxn.nodeValue = 'dx: '+mod.dx.toFixed(3)\n mod.dyn.nodeValue = 'dy: '+mod.dy.toFixed(3)\n mod.dzn.nodeValue = 'dz: '+mod.dz.toFixed(3)\n mod.xmin = xmin\n mod.ymin = ymin\n mod.zmin = zmin\n mod.xmax = xmax\n mod.ymax = ymax\n mod.zmax = zmax\n //\n // copy mesh\n //\n var buf = mod.mesh.buffer.slice(0)\n var newview = new DataView(buf)\n //\n // draw projection and save rotation\n //\n var ctx = mod.meshcanvas.getContext('2d')\n var w = mod.meshcanvas.width\n var h = mod.meshcanvas.height\n ctx.clearRect(0,0,w,h)\n var dx = mod.dx\n var dy = mod.dy\n if (dx > dy) {\n var xo = 0\n var yo = h*.5*(1-dy/dx)\n var xw = w\n var yh = w*dy/dx\n }\n else {\n var xo = w*.5*(1-dx/dy)\n var yo = 0\n var xw = h*dx/dy\n var yh = h\n }\n ctx.beginPath()\n offset = 80+4\n var newoffset = 80+4\n for (var t = 0; t < triangles; ++t) {\n offset += 3*4\n x0 = view.getFloat32(offset,endian)\n offset += 4\n y0 = view.getFloat32(offset,endian)\n offset += 4\n z0 = view.getFloat32(offset,endian)\n offset += 4\n x1 = view.getFloat32(offset,endian)\n offset += 4\n y1 = view.getFloat32(offset,endian)\n offset += 4\n z1 = view.getFloat32(offset,endian)\n offset += 4\n x2 = view.getFloat32(offset,endian)\n offset += 4\n y2 = view.getFloat32(offset,endian)\n offset += 4\n z2 = view.getFloat32(offset,endian)\n offset += 4\n offset += 2\n var p0 = rotate(x0,y0,z0)\n var p1 = rotate(x1,y1,z1)\n var p2 = rotate(x2,y2,z2)\n x0 = xo+xw*(p0[0]-xmin)/dx\n y0 = yo+yh*(ymax-p0[1])/dy\n x1 = xo+xw*(p1[0]-xmin)/dx\n y1 = yo+yh*(ymax-p1[1])/dy\n x2 = xo+xw*(p2[0]-xmin)/dx\n y2 = yo+yh*(ymax-p2[1])/dy\n ctx.moveTo(x0,y0)\n ctx.lineTo(x1,y1)\n ctx.lineTo(x2,y2)\n ctx.lineTo(x0,y0)\n newoffset += 3*4\n newview.setFloat32(newoffset,p0[0],endian)\n newoffset += 4\n newview.setFloat32(newoffset,p0[1],endian)\n newoffset += 4\n newview.setFloat32(newoffset,p0[2],endian)\n newoffset += 4\n newview.setFloat32(newoffset,p1[0],endian)\n newoffset += 4\n newview.setFloat32(newoffset,p1[1],endian)\n newoffset += 4\n newview.setFloat32(newoffset,p1[2],endian)\n newoffset += 4\n newview.setFloat32(newoffset,p2[0],endian)\n newoffset += 4\n newview.setFloat32(newoffset,p2[1],endian)\n newoffset += 4\n newview.setFloat32(newoffset,p2[2],endian)\n newoffset += 4\n newoffset += 2\n }\n ctx.stroke()\n //\n // generate output\n //\n outputs.mesh.event(buf)\n }\n//\n// return values\n//\nreturn ({\n mod:mod,\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"252.46890050701393","left":"694.1238074852727","filename":"undefined","inputs":{},"outputs":{}},"0.373975449262817":{"definition":"//\n// mesh height map\n// \n// Neil Gershenfeld 1/16/20\n//\n// This work may be reproduced, modified, distributed, performed, and\n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is\n// provided as is; no warranty is provided, and users accept all\n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'mesh height map'\n//\n// initialization\n//\nvar init = function() {\n mod.mmunits.value = '25.4'\n mod.inunits.value = '1'\n mod.width.value = '1000'\n mod.border.value = '0'\n }\n//\n// inputs\n//\nvar inputs = {\n mesh:{type:'STL',\n event:function(evt){\n mod.mesh = new DataView(evt.detail)\n find_limits_map()}}}\n//\n// outputs\n//\nvar outputs = {\n map:{type:'',label:'height map',\n event:function(heightmap){\n var obj = {}\n obj.map = heightmap\n obj.xmin = mod.xmin\n obj.xmax = mod.xmax\n obj.ymin = mod.ymin\n obj.ymax = mod.ymax\n obj.zmin = mod.zmin\n obj.zmax = mod.zmax\n obj.width = mod.img.width\n obj.height = mod.img.height\n obj.mmunits = mod.mmunits.value\n mods.output(mod,'map',obj)\n }}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // on-screen height map canvas\n //\n div.appendChild(document.createTextNode(' '))\n var canvas = document.createElement('canvas')\n canvas.width = mods.ui.canvas\n canvas.height = mods.ui.canvas\n canvas.style.backgroundColor = 'rgb(255,255,255)'\n div.appendChild(canvas)\n mod.mapcanvas = canvas\n div.appendChild(document.createElement('br'))\n //\n // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\n //\n // mesh units\n //\n div.appendChild(document.createTextNode('mesh units: (enter)'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('mm: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n mod.inunits.value = parseFloat(mod.mmunits.value)/25.4\n find_limits_map()\n })\n div.appendChild(input)\n mod.mmunits = input\n div.appendChild(document.createTextNode(' in: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n mod.mmunits.value = parseFloat(mod.inunits.value)*25.4\n find_limits_map()\n })\n div.appendChild(input)\n mod.inunits = input\n //\n // mesh size\n //\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('mesh size:'))\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('XxYxZ (units)')\n div.appendChild(text)\n mod.meshsize = text\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('XxYxZ (mm)')\n div.appendChild(text)\n mod.mmsize = text\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('XxYxZ (in)')\n div.appendChild(text)\n mod.insize = text\n //\n // height map border \n //\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('border: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n find_limits_map()\n })\n div.appendChild(input)\n mod.border = input\n div.appendChild(document.createTextNode(' (units)'))\n //\n // height map width\n //\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('width: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n find_limits_map()\n })\n div.appendChild(input)\n mod.width = input\n div.appendChild(document.createTextNode(' (pixels)'))\n //\n // view height map\n //\n div.appendChild(document.createElement('br'))\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('view height map'))\n btn.addEventListener('click',function(){\n var win = window.open('')\n var btn = document.createElement('button')\n btn.appendChild(document.createTextNode('close'))\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.addEventListener('click',function(){\n win.close()\n })\n win.document.body.appendChild(btn)\n win.document.body.appendChild(document.createElement('br'))\n var canvas = document.createElement('canvas')\n canvas.width = mod.img.width\n canvas.height = mod.img.height\n win.document.body.appendChild(canvas)\n var ctx = canvas.getContext(\"2d\")\n ctx.drawImage(mod.img,0,0)\n })\n div.appendChild(btn)\n }\n//\n// local functions\n//\n// find limits then map \n//\nfunction find_limits_map() {\n var blob = new Blob(['('+limits_worker.toString()+'())'])\n var url = window.URL.createObjectURL(blob)\n var webworker = new Worker(url)\n webworker.addEventListener('message',function(evt) {\n window.URL.revokeObjectURL(url)\n mod.triangles = evt.data.triangles\n mod.xmin = evt.data.xmin\n mod.xmax = evt.data.xmax\n mod.ymin = evt.data.ymin\n mod.ymax = evt.data.ymax\n mod.zmin = evt.data.zmin\n mod.zmax = evt.data.zmax\n mod.dx = mod.xmax-mod.xmin\n mod.dy = mod.ymax-mod.ymin\n mod.dz = mod.zmax-mod.zmin\n mod.meshsize.nodeValue = \n mod.dx.toFixed(3)+' x '+\n mod.dy.toFixed(3)+' x '+\n mod.dz.toFixed(3)+' (units)'\n var mm = parseFloat(mod.mmunits.value)\n mod.mmsize.nodeValue = \n (mod.dx*mm).toFixed(3)+' x '+\n (mod.dy*mm).toFixed(3)+' x '+\n (mod.dz*mm).toFixed(3)+' (mm)'\n var inches = parseFloat(mod.inunits.value)\n mod.insize.nodeValue = \n (mod.dx*inches).toFixed(3)+' x '+\n (mod.dy*inches).toFixed(3)+' x '+\n (mod.dz*inches).toFixed(3)+' (in)'\n mods.fit(mod.div)\n map_mesh()\n })\n var border = parseFloat(mod.border.value)\n webworker.postMessage({\n mesh:mod.mesh,\n border:border})\n }\nfunction limits_worker() {\n self.addEventListener('message',function(evt) {\n var view = evt.data.mesh\n var border = evt.data.border\n //\n // get vars\n //\n var endian = true\n var triangles = view.getUint32(80,endian)\n var size = 80+4+triangles*(4*12+2)\n //\n // find limits\n //\n var offset = 80+4\n var x0,x1,x2,y0,y1,y2,z0,z1,z2\n var xmin = Number.MAX_VALUE\n var xmax = -Number.MAX_VALUE\n var ymin = Number.MAX_VALUE\n var ymax = -Number.MAX_VALUE\n var zmin = Number.MAX_VALUE\n var zmax = -Number.MAX_VALUE\n for (var t = 0; t < triangles; ++t) {\n offset += 3*4\n x0 = view.getFloat32(offset,endian)\n offset += 4\n y0 = view.getFloat32(offset,endian)\n offset += 4\n z0 = view.getFloat32(offset,endian)\n offset += 4\n x1 = view.getFloat32(offset,endian)\n offset += 4\n y1 = view.getFloat32(offset,endian)\n offset += 4\n z1 = view.getFloat32(offset,endian)\n offset += 4\n x2 = view.getFloat32(offset,endian)\n offset += 4\n y2 = view.getFloat32(offset,endian)\n offset += 4\n z2 = view.getFloat32(offset,endian)\n offset += 4\n offset += 2\n if (x0 > xmax) xmax = x0\n if (x0 < xmin) xmin = x0\n if (y0 > ymax) ymax = y0\n if (y0 < ymin) ymin = y0\n if (z0 > zmax) zmax = z0\n if (z0 < zmin) zmin = z0\n if (x1 > xmax) xmax = x1\n if (x1 < xmin) xmin = x1\n if (y1 > ymax) ymax = y1\n if (y1 < ymin) ymin = y1\n if (z1 > zmax) zmax = z1\n if (z1 < zmin) zmin = z1\n if (x2 > xmax) xmax = x2\n if (x2 < xmin) xmin = x2\n if (y2 > ymax) ymax = y2\n if (y2 < ymin) ymin = y2\n if (z2 > zmax) zmax = z2\n if (z2 < zmin) zmin = z2\n }\n xmin -= border\n xmax += border\n ymin -= border\n ymax += border\n //\n // return\n //\n self.postMessage({triangles:triangles,\n xmin:xmin,xmax:xmax,ymin:ymin,ymax:ymax,\n zmin:zmin,zmax:zmax})\n self.close()\n })\n }\n//\n// map mesh\n// \nfunction map_mesh() {\n var blob = new Blob(['('+map_worker.toString()+'())'])\n var url = window.URL.createObjectURL(blob)\n var webworker = new Worker(url)\n webworker.addEventListener('message',function(evt) {\n window.URL.revokeObjectURL(url)\n var h = mod.img.height\n var w = mod.img.width\n var buf = new Uint8ClampedArray(evt.data.imgbuffer)\n var map = new Float32Array(evt.data.mapbuffer)\n var imgdata = new ImageData(buf,w,h)\n var ctx = mod.img.getContext(\"2d\")\n ctx.putImageData(imgdata,0,0)\n if (w > h) {\n var x0 = 0\n var y0 = mod.mapcanvas.height*.5*(1-h/w)\n var wd = mod.mapcanvas.width\n var hd = mod.mapcanvas.width*h/w\n }\n else {\n var x0 = mod.mapcanvas.width*.5*(1-w/h)\n var y0 = 0\n var wd = mod.mapcanvas.height*w/h\n var hd = mod.mapcanvas.height\n }\n var ctx = mod.mapcanvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.mapcanvas.width,mod.mapcanvas.height)\n ctx.drawImage(mod.img,x0,y0,wd,hd)\n outputs.map.event(map)\n })\n var ctx = mod.mapcanvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.mapcanvas.width,mod.mapcanvas.height)\n mod.img.width = parseInt(mod.width.value)\n mod.img.height = Math.round(mod.img.width*mod.dy/mod.dx)\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n var map = new Float32Array(mod.img.width*mod.img.height)\n webworker.postMessage({\n height:mod.img.height,width:mod.img.width,\n imgbuffer:img.data.buffer,\n mapbuffer:map.buffer,\n mesh:mod.mesh,\n xmin:mod.xmin,xmax:mod.xmax,\n ymin:mod.ymin,ymax:mod.ymax,\n zmin:mod.zmin,zmax:mod.zmax},\n [img.data.buffer,map.buffer])\n }\nfunction map_worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var view = evt.data.mesh\n var xmin = evt.data.xmin\n var xmax = evt.data.xmax\n var ymin = evt.data.ymin\n var ymax = evt.data.ymax\n var zmin = evt.data.zmin\n var zmax = evt.data.zmax\n var buf = new Uint8ClampedArray(evt.data.imgbuffer)\n var map = new Float32Array(evt.data.mapbuffer)\n //\n // get vars from buffer\n //\n var endian = true\n var triangles = view.getUint32(80,endian)\n var size = 80+4+triangles*(4*12+2)\n //\n // initialize map and image\n //\n for (var row = 0; row < h; ++row) {\n for (var col = 0; col < w; ++col) {\n map[(h-1-row)*w+col] = zmin\n buf[(h-1-row)*w*4+col*4+0] = 0\n buf[(h-1-row)*w*4+col*4+1] = 0\n buf[(h-1-row)*w*4+col*4+2] = 0\n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n }\n //\n // loop over triangles\n //\n var segs = []\n offset = 80+4\n for (var t = 0; t < triangles; ++t) {\n offset += 3*4\n x0 = view.getFloat32(offset,endian)\n offset += 4\n y0 = view.getFloat32(offset,endian)\n offset += 4\n z0 = view.getFloat32(offset,endian)\n offset += 4\n x1 = view.getFloat32(offset,endian)\n offset += 4\n y1 = view.getFloat32(offset,endian)\n offset += 4\n z1 = view.getFloat32(offset,endian)\n offset += 4\n x2 = view.getFloat32(offset,endian)\n offset += 4\n y2 = view.getFloat32(offset,endian)\n offset += 4\n z2 = view.getFloat32(offset,endian)\n offset += 4\n offset += 2\n //\n // check normal if needs to be drawn\n //\n if (((x1-x0)*(y1-y2)-(x1-x2)*(y1-y0)) >= 0)\n continue\n //\n // quantize image coordinates\n //\n x0 = Math.floor((w-1)*(x0-xmin)/(xmax-xmin))\n x1 = Math.floor((w-1)*(x1-xmin)/(xmax-xmin))\n x2 = Math.floor((w-1)*(x2-xmin)/(xmax-xmin))\n y0 = Math.floor((h-1)*(y0-ymin)/(ymax-ymin))\n y1 = Math.floor((h-1)*(y1-ymin)/(ymax-ymin))\n y2 = Math.floor((h-1)*(y2-ymin)/(ymax-ymin))\n //\n // sort projection order\n //\n if (y1 > y2) {\n var temp = x1;\n x1 = x2;\n x2 = temp\n var temp = y1;\n y1 = y2;\n y2 = temp\n var temp = z1;\n z1 = z2;\n z2 = temp\n }\n if (y0 > y1) {\n var temp = x0;\n x0 = x1;\n x1 = temp\n var temp = y0;\n y0 = y1;\n y1 = temp\n var temp = z0;\n z0 = z1;\n z1 = temp\n }\n if (y1 > y2) {\n var temp = x1;\n x1 = x2;\n x2 = temp\n var temp = y1;\n y1 = y2;\n y2 = temp\n var temp = z1;\n z1 = z2;\n z2 = temp\n }\n //\n // check orientation after sort\n //\n if (x1 < (x0+((x2-x0)*(y1-y0))/(y2-y0)))\n var dir = 1;\n else\n var dir = -1;\n //\n // set z values\n //\n if (y2 != y1) {\n for (var y = y1; y <= y2; ++y) {\n x12 = Math.floor(0.5+x1+(y-y1)*(x2-x1)/(y2-y1))\n z12 = z1+(y-y1)*(z2-z1)/(y2-y1)\n x02 = Math.floor(0.5+x0+(y-y0)*(x2-x0)/(y2-y0))\n z02 = z0+(y-y0)*(z2-z0)/(y2-y0)\n if (x12 != x02)\n var slope = (z02-z12)/(x02-x12)\n else\n var slope = 0\n var x = x12 - dir\n while (x != x02) {\n x += dir\n var z = z12+slope*(x-x12)\n if (z > map[(h-1-y)*w+x]) {\n map[(h-1-y)*w+x] = z\n var iz = Math.floor(255*(z-zmin)/(zmax-zmin))\n buf[(h-1-y)*w*4+x*4+0] = iz\n buf[(h-1-y)*w*4+x*4+1] = iz\n buf[(h-1-y)*w*4+x*4+2] = iz\n }\n }\n }\n }\n if (y1 != y0) {\n for (var y = y0; y <= y1; ++y) {\n x01 = Math.floor(0.5+x0+(y-y0)*(x1-x0)/(y1-y0))\n z01 = z0+(y-y0)*(z1-z0)/(y1-y0)\n x02 = Math.floor(0.5+x0+(y-y0)*(x2-x0)/(y2-y0))\n z02 = z0+(y-y0)*(z2-z0)/(y2-y0)\n if (x01 != x02)\n var slope = (z02-z01)/(x02-x01)\n else\n var slope = 0\n var x = x01 - dir\n while (x != x02) {\n x += dir\n var z = z01+slope*(x-x01)\n if (z > map[(h-1-y)*w+x]) {\n map[(h-1-y)*w+x] = z\n var iz = Math.floor(255*(z-zmin)/(zmax-zmin))\n buf[(h-1-y)*w*4+x*4+0] = iz\n buf[(h-1-y)*w*4+x*4+1] = iz\n buf[(h-1-y)*w*4+x*4+2] = iz\n }\n }\n }\n }\n }\n //\n // output the map\n //\n self.postMessage({imgbuffer:buf.buffer,mapbuffer:map.buffer},[buf.buffer,map.buffer])\n self.close()\n })\n }\n//\n// return values\n//\nreturn ({\n mod:mod,\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"124.64802090317082","left":"1209.2725971321183","filename":"undefined","inputs":{},"outputs":{}},"0.21976500984768532":{"definition":"//\n// view path\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2019\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is \n// provided as is; no warranty is provided, and users accept all \n// liability.\n//\n// todo:\n// erase and update new path\n// show depth info\n// show size\n// calculate camera far\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'view path'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\n path:{type:'',\n event:function(evt){\n mod.path = evt.detail.path\n mod.name = evt.detail.name\n mod.dpi = evt.detail.dpi\n mod.width = evt.detail.width\n mod.height = evt.detail.height\n mod.depth = evt.detail.depth\n show_path_info()\n show_path()\n mods.fit(mod.div)\n outputs.path.event()\n }}}\n//\n// outputs\n//\nvar outputs = {\n path:{type:'',\n event:function(){\n cmd = {}\n cmd.path = mod.path\n cmd.name = mod.name\n cmd.dpi = mod.dpi\n cmd.width = mod.width\n cmd.height = mod.height\n mods.output(mod,'path',cmd)\n }}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // info\n //\n var text = document.createTextNode('name: ')\n div.appendChild(text)\n mod.nametext = text\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('(mm)')\n div.appendChild(text)\n mod.mmtext = text\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('(in)')\n div.appendChild(text)\n mod.intext = text\n //\n // view\n // \n div.appendChild(document.createElement('br')) \n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('view')\n span.appendChild(text)\n btn.appendChild(span)\n btn.addEventListener('click',function(){\n open_view_window()\n })\n div.appendChild(btn)\n }\n//\n// local functions\n//\n// show_path_info\n//\nfunction show_path_info() {\n mod.nametext.nodeValue = 'name: '+mod.name\n var width = (25.4*mod.width/mod.dpi).toFixed(3)\n var height = (25.4*mod.height/mod.dpi).toFixed(3)\n var depth = (25.4*mod.depth/mod.dpi).toFixed(3)\n if (mod.depth == undefined)\n mod.mmtext.nodeValue = width+' x '+height+' (mm)'\n else\n mod.mmtext.nodeValue = width+' x '+height+' x '+depth+' (mm)'\n var width = (mod.width/mod.dpi).toFixed(3)\n var height = (mod.height/mod.dpi).toFixed(3)\n var depth = (mod.depth/mod.dpi).toFixed(3)\n if (mod.depth == undefined)\n mod.intext.nodeValue = width+' x '+height+' (in)'\n else\n mod.intext.nodeValue = width+' x '+height+' x '+depth+' (in)'\n mods.fit(mod.div)\n }\n//\n// show_path\n//\nfunction show_path() {\n var scene = mod.scene\n var camera = mod.camera\n var renderer = mod.renderer\n //\n // check if view window open\n //\n if (mod.win == undefined) {\n open_view_window()\n return\n }\n //\n // check for path\n //\n if (mod.path == undefined)\n return\n //\n // clear scene, leave camera\n //\n var length = scene.children.length\n for (var c = (length-1); c > 1; --c) {\n scene.remove(scene.children[c])\n }\n //\n // fit camera\n //\n mod.thetaxy = 0\n mod.thetaz = 0\n mod.r = mod.height/2\n mod.x0 = mod.width/2\n mod.y0 = mod.height/2\n camera.position.set(mod.x0,mod.y0,mod.r)\n camera.up = new THREE.Vector3(0,1,0)\n camera.lookAt(new THREE.Vector3(mod.x0,mod.y0,0))\n camera.updateProjectionMatrix()\n //\n // draw segments\n //\n var arrow_size = 1+mod.width/200\n var path = mod.path\n for (var segment = 0; segment < path.length; ++segment) {\n if (segment > 0)\n add_arrow(path[segment-1][path[segment-1].length-1],path[segment][0],0xff0000,arrow_size) \n for (var point = 1; point < path[segment].length; ++point) {\n add_arrow(path[segment][point-1],path[segment][point],0x0000ff,arrow_size)\n }\n }\n //\n // add axes\n //\n var length = mod.height/10\n add_arrow([0,0,0],[length,0,0],0xff0000,arrow_size)\n add_arrow([0,0,0],[0,length,0],0x00ff00,arrow_size)\n add_arrow([0,0,0],[0,0,length],0x0000ff,arrow_size)\n //\n // render\n //\n update()\n //\n // add_arrow\n //\n function add_arrow(start,stop,color,size) {\n var origin = new THREE.Vector3().fromArray(start)\n if (mod.depth == undefined)\n origin.z = 0\n var end = new THREE.Vector3().fromArray(stop)\n if (mod.depth == undefined)\n end.z = 0\n var length = new THREE.Vector3().subVectors(end,origin).length()\n if (length <= size) {\n add_line(origin,end,color)\n //length = 1.1*size\n return\n }\n var direction = new THREE.Vector3().subVectors(end,origin).normalize()\n var arrow = new THREE.ArrowHelper(direction,origin,length,color,size,size)\n scene.add(arrow)\n }\n //\n // add_line\n //\n function add_line(start,stop,colorhex) {\n var geometry = new THREE.Geometry()\n geometry.vertices.push(start,stop)\n var material = new THREE.LineBasicMaterial({color:colorhex})\n var line = new THREE.Line(geometry,material)\n scene.add(line)\n }\n //\n // update\n //\n function update() {\n renderer.render(scene,camera)\n }\n }\n//\n// open_view_window\n//\nfunction open_view_window() {\n //\n // open window\n //\n win = window.open('')\n mod.win = win\n //\n // load three.js\n //\n var script = document.createElement('script')\n script.type = 'text/javascript'\n script.onload = init_window\n script.src = 'js/three.js/three.min.js'\n mod.div.appendChild(script)\n }\n//\n// init_window\n//\nfunction init_window() {\n //document.write('<script type=\"text/javascript\">'+arg+'</script>')\n //document.close()\n //\n // close button\n //\n var btn = document.createElement('button')\n btn.appendChild(document.createTextNode('close'))\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.addEventListener('click',function(){\n mod.win.close()\n mod.win = undefined\n })\n mod.win.document.body.appendChild(btn)\n //\n // label text\n //\n var text = win.document.createTextNode(' left: pan, right: rotate, scroll: zoom')\n mod.win.document.body.appendChild(text)\n //\n // GL container\n //\n mod.win.document.body.appendChild(document.createElement('br')) \n container = mod.win.document.createElement('div')\n container.style.overflow = 'hidden'\n mod.win.document.body.appendChild(container)\n //\n // event handlers\n //\n container.addEventListener('contextmenu',context_menu)\n container.addEventListener('mousedown',mouse_down)\n container.addEventListener('mouseup',mouse_up)\n container.addEventListener('mousemove',mouse_move)\n container.addEventListener('wheel',mouse_wheel)\n //\n // add scene\n //\n scene = new THREE.Scene()\n mod.scene = scene\n var width = mod.win.innerWidth\n var height = mod.win.innerHeight\n var aspect = width/height\n var near = 0.1\n var far = 1000000\n camera = new THREE.PerspectiveCamera(90,aspect,near,far)\n mod.camera = camera\n scene.add(camera)\n //\n // add renderer\n //\n renderer = new THREE.WebGLRenderer({antialias:true})\n mod.renderer = renderer\n renderer.setClearColor(0xffffff)\n renderer.setSize(width,height)\n container.appendChild(renderer.domElement)\n //\n // show the path if available\n //\n show_path()\n //\n // context_menu\n //\n function context_menu(evt) {\n evt.preventDefault()\n evt.stopPropagation()\n return (false)\n }\n //\n // mouse_down\n //\n function mouse_down(evt) {\n evt.preventDefault()\n evt.stopPropagation()\n mod.button = evt.button\n mod.x = evt.clientX\n mod.y = evt.clientY\n }\n //\n // mouse_up\n //\n function mouse_up(evt) {\n mod.button = undefined\n mod.x = evt.clientX\n mod.y = evt.clientY\n }\n //\n // mouse_move\n //\n function mouse_move(evt) {\n evt.preventDefault()\n evt.stopPropagation()\n var dx = evt.clientX-mod.x\n var dy = evt.clientY-mod.y\n mod.x = evt.clientX\n mod.y = evt.clientY\n if (mod.button == 0) {\n mod.x0 += \n Math.sin(mod.thetaz)*mod.height*dy/mod.win.innerHeight\n -Math.cos(mod.thetaz)*mod.width*dx/mod.win.innerWidth\n mod.y0 += \n Math.cos(mod.thetaz)*mod.height*dy/mod.win.innerHeight\n +Math.sin(mod.thetaz)*mod.width*dx/mod.win.innerWidth\n camera.position.x = mod.x0+Math.sin(mod.thetaz)*mod.r*Math.sin(mod.thetaxy)\n camera.position.y = mod.y0+Math.cos(mod.thetaz)*mod.r*Math.sin(mod.thetaxy)\n camera.position.z = mod.r*Math.cos(mod.thetaxy)\n camera.position.z = mod.r*Math.cos(mod.thetaxy)\n camera.up = new THREE.Vector3(Math.sin(mod.thetaz),Math.cos(mod.thetaz),0)\n camera.lookAt(new THREE.Vector3(mod.x0,mod.y0,0))\n camera.updateProjectionMatrix()\n renderer.render(scene,camera)\n }\n else if (mod.button == 2) {\n mod.thetaxy += dy/mod.win.innerHeight\n mod.thetaz += dx/mod.win.innerWidth\n camera.position.x = mod.x0+Math.sin(mod.thetaz)*mod.r*Math.sin(mod.thetaxy)\n camera.position.y = mod.y0+Math.cos(mod.thetaz)*mod.r*Math.sin(mod.thetaxy)\n camera.position.z = mod.r*Math.cos(mod.thetaxy)\n if (Math.cos(mod.thetaxy) > 0)\n camera.up = new THREE.Vector3(Math.sin(mod.thetaz),Math.cos(mod.thetaz),0)\n else\n camera.up = new THREE.Vector3(-Math.sin(mod.thetaz),-Math.cos(mod.thetaz),0)\n camera.lookAt(new THREE.Vector3(mod.x0,mod.y0,0))\n camera.updateProjectionMatrix()\n renderer.render(scene,camera)\n }\n }\n //\n // mouse_wheel\n //\n function mouse_wheel(evt) {\n evt.preventDefault()\n evt.stopPropagation()\n var dy = evt.deltaY/mod.win.innerHeight\n mod.r += mod.height*dy\n camera.position.x = mod.x0+Math.sin(mod.thetaz)*mod.r*Math.sin(mod.thetaxy)\n camera.position.y = mod.y0+Math.cos(mod.thetaz)*mod.r*Math.sin(mod.thetaxy)\n camera.position.z = mod.r*Math.cos(mod.thetaxy)\n camera.lookAt(new THREE.Vector3(mod.x0,mod.y0,0))\n camera.updateProjectionMatrix()\n renderer.render(scene,camera)\n }\n }\n//\n// return values\n//\nreturn ({\n mod:mod,\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"1051.330989940735","left":"1230.9648592659537","filename":"undefined","inputs":{},"outputs":{}},"0.5958662931535647":{"definition":"//\n// save file\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2016\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is \n// provided as is; no warranty is provided, and users accept all \n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'save file'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\n file:{type:'object',\n event:function(evt){\n mod.name = evt.detail.name\n mod.contents = evt.detail.contents\n save_file()\n }}}\n//\n// outputs\n//\nvar outputs = {}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // info\n //\n var text = document.createTextNode('name:')\n div.appendChild(text)\n mod.nametext = text\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('size:')\n div.appendChild(text)\n mod.sizetext = text\n div.appendChild(document.createElement('br'))\n }\n//\n// local functions\n//\nfunction save_file() {\n var a = document.createElement('a')\n a.setAttribute('href','data:text/plain;charset=utf-8,'+ \n encodeURIComponent(mod.contents))\n a.setAttribute('download',mod.name)\n a.style.display = 'none'\n document.body.appendChild(a)\n a.click()\n document.body.removeChild(a)\n mod.nametext.nodeValue = 'name: '+mod.name\n mods.fit(mod.div)\n mod.sizetext.nodeValue = 'size: '+mod.contents.length\n mods.fit(mod.div)\n }\n//\n// return values\n//\nreturn ({\n mod:mod,\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"830.7331133840215","left":"1251.9910798307683","filename":"undefined","inputs":{},"outputs":{}},"0.3062798763523076":{"definition":"//\n// Roland SRM-20 milling machine\n//\n// Neil Gershenfeld\n// (c) Massachusetts Institute of Technology 2016\n//\n// This work may be reproduced, modified, distributed, performed, and\n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is\n// provided as is; no warranty is provided, and users accept all\n// liability.\n//\n// closure\n//\n/*\nG-codes:\nG00X10.0\nG90 (absolute positioning)\nG21 (mm units)\n#.0 numbers\nG00 (positioning rapid move)\nG01 (linear motion)\nM03 (start spindle)\nM05 (stop spindle)\nF (feed rate mm/min, 6-1800)\n203.2 (X) x 152.4 (Y) x 60.5 (Z) mm \n*/\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'Roland SRM-20 milling machine'\n//\n// initialization\n//\nvar init = function() {\n mod.units = 100.0\n mod.speed.value = 4\n mod.ox.value = 10\n mod.oy.value = 10\n mod.oz.value = 10\n mod.jz.value = 2\n mod.hx.value = 0\n mod.hy.value = 152.4\n mod.hz.value = 60.5\n }\n//\n// inputs\n//\nvar inputs = {\n path:{type:'',\n event:function(evt){\n mod.name = evt.detail.name\n mod.path = evt.detail.path\n mod.dpi = evt.detail.dpi\n mod.width = evt.detail.width\n mod.height = evt.detail.height\n make_path()\n }}}\n//\n// outputs\n//\nvar outputs = {\n file:{type:'',\n event:function(obj){\n mods.output(mod,'file',obj)\n }}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // speed\n //\n div.appendChild(document.createTextNode('speed: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.speed = input\n div.appendChild(document.createTextNode(' (mm/s)'))\n div.appendChild(document.createElement('br'))\n //\n // origin\n //\n div.appendChild(document.createTextNode('origin:'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('x: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.ox = input\n div.appendChild(document.createTextNode(' (mm)'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode(' y: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.oy = input\n div.appendChild(document.createTextNode(' (mm)'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('z: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.oz = input\n div.appendChild(document.createTextNode(' (mm)'))\n div.appendChild(document.createElement('br'))\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('move to origin')\n span.appendChild(text)\n btn.appendChild(span)\n btn.addEventListener('click',function(){\n var x0 = mod.units*parseFloat(mod.ox.value);\n var y0 = mod.units*parseFloat(mod.oy.value);\n var z0 = mod.units*parseFloat(mod.oz.value);\n var zjog = z0+mod.units*parseFloat(mod.jz.value);\n //\n // G-code version\n //\n /*\n str = '%\\n' // data start\n str += 'G90\\n' // absolute units\n str += 'G21\\n' // mm units\n str += 'G00Z30.0\\n' // move z\n str += 'M02\\n' // end of program\n */\n //\n // RML version\n //\n var str = \"PA;PA;VS10;!VZ10;!PZ0,\"+zjog+\";PU\"+x0+\",\"+y0+\";Z\"+x0+\",\"+y0+\",\"+z0+\";!MC0;\"+\"\\u0004\"\n //\n // send command\n //\n var obj = {}\n obj.type = 'command'\n obj.name = mod.name+'.rml'\n obj.contents = str\n outputs.file.event(obj)\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // jog\n //\n div.appendChild(document.createTextNode('jog height:'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('z: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.jz = input\n div.appendChild(document.createTextNode(' (mm)'))\n div.appendChild(document.createElement('br'))\n //\n // home\n //\n div.appendChild(document.createTextNode('home:'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('x: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.hx = input\n div.appendChild(document.createTextNode(' (mm)'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode(' y: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.hy = input\n div.appendChild(document.createTextNode(' (mm)'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('z: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.hz = input\n div.appendChild(document.createTextNode(' (mm)'))\n div.appendChild(document.createElement('br'))\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('move to home')\n span.appendChild(text)\n btn.appendChild(span)\n btn.addEventListener('click',function(){\n var xhome = mod.units*parseFloat(mod.hx.value);\n var yhome = mod.units*parseFloat(mod.hy.value);\n var zhome = mod.units*parseFloat(mod.hz.value);\n //\n // G-code version\n //\n /*\n str = '%\\n' // data start\n str += 'G90\\n' // absolute units\n str += 'G21\\n' // mm units\n str += 'G00Z50.0\\n' // move z\n str += 'M02\\n' // end of program\n */\n //\n // RML version\n //\n var str = \"PA;PA;!PZ0,\"+zhome+\";PU\"+xhome+\",\"+yhome+\";!MC0;\"+\"\\u0004\"\n //\n // send command\n //\n var obj = {}\n obj.type = 'command'\n obj.name = mod.name+'.rml'\n obj.contents = str\n outputs.file.event(obj)\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n }\n//\n// local functions\n//\nfunction make_path() {\n var dx = 25.4*mod.width/mod.dpi\n var nx = mod.width\n var speed = parseFloat(mod.speed.value)\n var jog = parseFloat(mod.oz.value)+parseFloat(mod.jz.value)\n var ijog = Math.floor(mod.units*jog)\n var scale = mod.units*dx/(nx-1)\n var x0 = parseFloat(mod.ox.value)\n var y0 = parseFloat(mod.oy.value)\n var z0 = parseFloat(mod.oz.value)\n var xoffset = mod.units*x0\n var yoffset = mod.units*y0\n var zoffset = mod.units*z0\n var str = \"PA;PA;\" // plot absolute\n str += \"VS\"+speed+\";!VZ\"+speed+\";\"\n str += \"!PZ\"+0+\",\"+ijog+\";\" // set jog\n str += \"!MC1;\\n\" // turn motor on\n //\n // follow segments\n //\n for (var seg = 0; seg < mod.path.length; ++seg) {\n //\n // move up to starting point\n //\n x = xoffset+scale*mod.path[seg][0][0]\n y = yoffset+scale*mod.path[seg][0][1]\n str += \"PU\"+x.toFixed(0)+\",\"+y.toFixed(0)+\";\\n\"\n //\n // move down\n //\n z = zoffset+scale*mod.path[seg][0][2]\n str += \"Z\"+x.toFixed(0)+\",\"+y.toFixed(0)+\",\"+z.toFixed(0)+\";\\n\"\n for (var pt = 1; pt < mod.path[seg].length; ++pt) {\n //\n // move to next point\n //\n x = xoffset+scale*mod.path[seg][pt][0]\n y = yoffset+scale*mod.path[seg][pt][1]\n z = zoffset+scale*mod.path[seg][pt][2]\n str += \"Z\"+x.toFixed(0)+\",\"+y.toFixed(0)+\",\"+z.toFixed(0)+\";\\n\"\n }\n //\n // move up\n //\n str += \"PU\"+x.toFixed(0)+\",\"+y.toFixed(0)+\";\\n\"\n }\n //\n // turn off motor and move back\n //\n var xhome = mod.units*parseFloat(mod.hx.value)\n var yhome = mod.units*parseFloat(mod.hy.value)\n var zhome = mod.units*parseFloat(mod.hz.value)\n str += \"PA;PA;!PZ0,\"+zhome+\";PU\"+xhome+\",\"+yhome+\";!MC0;\"\n //\n // output string\n //\n var obj = {}\n obj.type = 'file'\n obj.name = mod.name+'.rml'\n obj.contents = str\n outputs.file.event(obj)\n }\n//\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"981.3223429160827","left":"677.9279893313669","filename":"modules/path/machines/Roland/milling/SRM-20","inputs":{},"outputs":{}},"0.1219393240810458":{"definition":"//\n// mill raster 3D\n//\n// Neil Gershenfeld 10/22/21\n//\n// This work may be reproduced, modified, distributed, performed, and\n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is\n// provided as is; no warranty is provided, and users accept all\n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'mill raster 3D'\n//\n// initialization\n//\nvar init = function() {\n mod.dia_in.value = '0.125'\n mod.dia_mm.value = '3.175'\n mod.stepover.value = '0.5'\n mod.error.value = '0.001'\n }\n//\n// inputs\n//\nvar inputs = {\n map:{type:'',label:'height map',\n event:function(evt){\n mod.map = evt.detail.map\n mod.xmin = evt.detail.xmin\n mod.xmax = evt.detail.xmax\n mod.ymin = evt.detail.ymin\n mod.ymax = evt.detail.ymax\n mod.zmin = evt.detail.zmin\n mod.zmax = evt.detail.zmax\n mod.width = evt.detail.width\n mod.height = evt.detail.height\n mod.depth = Math.floor((mod.zmax-mod.zmin)*mod.width/(mod.xmax-mod.xmin))\n mod.mmunits = evt.detail.mmunits\n mod.dpi = mod.width/(mod.mmunits*(mod.xmax-mod.xmin)/25.4)\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = mod.width\n ctx.canvas.height = mod.height\n }}}\n//\n// outputs\n//\nvar outputs = {\n toolpath:{type:'',\n event:function(){\n obj = {}\n obj.path = mod.path\n obj.name = \"mill raster 3D\"\n obj.dpi = mod.dpi\n obj.width = mod.width\n obj.height = mod.height\n obj.depth = mod.depth\n mods.output(mod,'toolpath',obj)\n }}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // tool diameter\n //\n div.appendChild(document.createTextNode('tool diameter'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('mm: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('input',function(){\n mod.dia_in.value = parseFloat(mod.dia_mm.value)/25.4\n })\n div.appendChild(input)\n mod.dia_mm = input\n div.appendChild(document.createTextNode(' in: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('input',function(){\n mod.dia_mm.value = parseFloat(mod.dia_in.value)*25.4\n })\n div.appendChild(input)\n mod.dia_in = input\n div.appendChild(document.createElement('br'))\n //\n // stepover\n //\n div.appendChild(document.createTextNode('stepover (0-1): '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.stepover = input\n div.appendChild(document.createElement('br'))\n //\n // tool shape\n //\n div.appendChild(document.createTextNode('tool shape: '))\n var input = document.createElement('input')\n input.type = 'radio'\n input.name = mod.div.id+'shape'\n input.id = mod.div.id+'flatend'\n input.checked = true\n div.appendChild(input)\n mod.flatend= input\n div.appendChild(document.createTextNode('flat end'))\n div.appendChild(document.createElement('br'))\n //\n // direction \n //\n div.appendChild(document.createTextNode('direction: '))\n var input = document.createElement('input')\n input.type = 'checkbox'\n input.id = mod.div.id+'xz'\n input.checked = true\n div.appendChild(input)\n mod.dirxz = input\n div.appendChild(document.createTextNode('xz'))\n var input = document.createElement('input')\n input.type = 'checkbox'\n input.id = mod.div.id+'yz'\n input.checked = true\n div.appendChild(input)\n mod.diryz = input\n div.appendChild(document.createTextNode('yz'))\n div.appendChild(document.createElement('br'))\n //\n // fit error \n //\n div.appendChild(document.createTextNode('vector fit: '))\n //div.appendChild(document.createElement('br'))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.error = input\n div.appendChild(document.createElement('br'))\n //\n // calculate\n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('calculate')\n mod.label = text\n span.appendChild(text)\n mod.labelspan = span\n btn.appendChild(span)\n btn.addEventListener('click',function(){\n mod.label.nodeValue = 'calculating'\n mod.labelspan.style.fontWeight = 'bold'\n calculate_path()\n })\n div.appendChild(btn)\n div.appendChild(document.createTextNode(' '))\n //\n // view\n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('view'))\n btn.addEventListener('click',function(){\n var win = window.open('')\n var btn = document.createElement('button')\n btn.appendChild(document.createTextNode('close'))\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.addEventListener('click',function(){\n win.close()\n })\n win.document.body.appendChild(btn)\n win.document.body.appendChild(document.createElement('br'))\n var svg = document.getElementById(mod.div.id+'svg')\n var clone = svg.cloneNode(true)\n clone.setAttribute('width',mod.img.width)\n clone.setAttribute('height',mod.img.height)\n win.document.body.appendChild(clone)\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // on-screen SVG\n //\n var svgNS = \"http://www.w3.org/2000/svg\"\n var svg = document.createElementNS(svgNS,\"svg\")\n svg.setAttribute('id',mod.div.id+'svg')\n svg.setAttributeNS(\"http://www.w3.org/2000/xmlns/\",\n \"xmlns:xlink\",\"http://www.w3.org/1999/xlink\")\n svg.setAttribute('width',mods.ui.canvas)\n svg.setAttribute('height',mods.ui.canvas)\n svg.style.backgroundColor = 'rgb(255,255,255)'\n var g = document.createElementNS(svgNS,'g')\n g.setAttribute('id',mod.div.id+'g')\n svg.appendChild(g)\n div.appendChild(svg)\n div.appendChild(document.createElement('br'))\n //\n // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\n }\n//\n// local functions\n//\n// calculate path\n//\nfunction calculate_path() {\n var blob = new Blob(['('+calculate_path_worker.toString()+'())'])\n var url = window.URL.createObjectURL(blob)\n var webworker = new Worker(url)\n webworker.addEventListener('message',function(evt) {\n if (evt.data.type == \"progress\") {\n mod.label.nodeValue = evt.data.value\n return\n }\n //\n // webworker handler\n //\n mod.path = evt.data.path\n mod.label.nodeValue = 'calculate'\n mod.labelspan.style.fontWeight = 'normal'\n //\n // clear SVG\n //\n var svg = document.getElementById(mod.div.id+'svg')\n svg.setAttribute('viewBox',\"0 0 \"+(mod.width-1)+\" \"+(mod.height-1))\n var g = document.getElementById(mod.div.id+'g')\n svg.removeChild(g)\n var g = document.createElementNS('http://www.w3.org/2000/svg','g')\n g.setAttribute('id',mod.div.id+'g')\n svg.appendChild(g)\n //\n // plot path\n //\n for (var i = 1; i < mod.path[0].length; ++i) {\n var ixp = mod.path[0][i-1][0]\n var iyp = mod.height-1-mod.path[0][i-1][1]\n var izp = 0.1*mod.path[0][i-1][2]\n var ix = mod.path[0][i][0]\n var iy = mod.height-1-mod.path[0][i][1]\n var iz = 0.1*mod.path[0][i][2]\n var line = document.createElementNS(\n 'http://www.w3.org/2000/svg','line')\n line.setAttribute('stroke','black')\n line.setAttribute('stroke-width',1)\n line.setAttribute('stroke-linecap','round')\n line.setAttribute('x1',ixp)\n line.setAttribute('y1',iyp-izp)\n line.setAttribute('x2',ix)\n line.setAttribute('y2',iy-iz)\n g.appendChild(line)\n }\n //\n // output path\n //\n outputs.toolpath.event()\n })\n //\n // call webworker\n //\n webworker.postMessage({\n height:mod.height,width:mod.width,\n error:mod.error.value,\n xmin:mod.xmin,xmax:mod.xmax,\n ymin:mod.ymin,ymax:mod.ymax,\n zmin:mod.zmin,zmax:mod.zmax,\n diameter:mod.dia_mm.value,\n stepover:mod.stepover.value,\n mmunits: mod.mmunits,\n xz:mod.dirxz.checked,\n yz:mod.diryz.checked,\n map:mod.map})\n }\n//\n// calculate path worker\n//\nfunction calculate_path_worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var error = evt.data.error\n var xmin = evt.data.xmin\n var xmax = evt.data.xmax\n var ymin = evt.data.ymin\n var ymax = evt.data.ymax\n var zmin = evt.data.zmin\n var zmax = evt.data.zmax\n var map = evt.data.map\n var diameter = evt.data.diameter\n var stepover = evt.data.stepover\n var mmunits = evt.data.mmunits\n var step = Math.floor(stepover*diameter*w/(mmunits*(xmax-xmin)))\n var path = []\n //\n // construct tool offset\n //\n var toolsize = Math.floor(diameter*w/(mmunits*(xmax-xmin)))\n var tooloffset = new Float32Array(toolsize*toolsize)\n var toolmiddle = Math.floor(toolsize/2)\n for (var x = 0; x < toolsize; ++x)\n for (var y = 0; y < toolsize; ++y) {\n var r = Math.sqrt((x-toolmiddle)*(x-toolmiddle)+(y-toolmiddle)*(y-toolmiddle))\n if (r <= toolmiddle)\n tooloffset[y*toolsize+x] = 0\n else\n tooloffset[y*toolsize+x] = Number.MAX_VALUE\n }\n //\n // xz\n //\n if (evt.data.xz) {\n path.push([])\n var xstart = 0\n var ystart = h-1\n var zstart = Math.floor((map[ystart*w+xstart]-zmax)*w/(xmax-xmin))\n path[path.length-1].push([xstart,h-1-ystart,zstart])\n var xcur = 1\n var ycur = h-1\n var zcur = Math.floor((map[ycur*w+xcur]-zmax)*w/(xmax-xmin))\n var dx = 1\n var dy = 0\n while (1) {\n //\n // move to next point\n //\n xnext = xcur+dx\n ynext = ycur+dy\n if (ynext <= 0)\n //\n // done\n //\n break;\n //\n // find offset at next point\n //\n var znext = -Number.MAX_VALUE\n for (var xoffset = 0; xoffset < toolsize; ++xoffset)\n for (var yoffset = 0; yoffset < toolsize; ++yoffset) {\n var x = xnext+(xoffset-toolmiddle)\n var y = ynext+(yoffset-toolmiddle)\n var offset = tooloffset[yoffset*toolsize+xoffset]\n var z = Math.floor((map[y*w+x]-zmax)*w/(xmax-xmin))-offset\n if (z > znext)\n znext = z\n }\n //\n // vectorize\n //\n dxcur = xcur-xstart\n dycur = ycur-ystart\n dzcur = zcur-zstart\n dcur = Math.sqrt(dxcur*dxcur+dycur*dycur+dzcur*dzcur)\n nxcur = dxcur/dcur\n nycur = dycur/dcur\n nzcur = dzcur/dcur\n dxnext = xnext-xcur\n dynext = ynext-ycur\n dznext = znext-zcur\n dnext = Math.sqrt(dxnext*dxnext+dynext*dynext+dznext*dznext)\n nxnext = dxnext/dnext\n nynext = dynext/dnext\n nznext = dznext/dnext\n dot = nxcur*nxnext+nycur*nynext+nzcur*nznext\n if (dot <= (1-error)) {\n path[path.length-1].push([xcur,h-1-ycur,zcur])\n xstart = xcur\n ystart = ycur\n zstart = zcur\n }\n xcur = xnext\n ycur = ynext\n zcur = znext\n if (xcur == (w-1)) {\n if (dx == 1) {\n dx = 0\n dy = -step\n }\n else {\n dx = -1\n dy = 0\n }\n }\n else if (xcur == 0) {\n if (dx == -1) {\n dx = 0\n dy = -step\n }\n else {\n dx = 1\n dy = 0\n }\n }\n //\n // update progress\n //\n self.postMessage({type:'progress',value:ycur})\n }\n }\n //\n // yz\n //\n if (evt.data.yz) {\n path.push([])\n var xstart = w-1\n var ystart = 0\n var zstart = Math.floor((map[ystart*w+xstart]-zmax)*w/(xmax-xmin))\n path[path.length-1].push([xstart,h-1-ystart,zstart])\n var xcur = w-1\n var ycur = 1\n var zcur = Math.floor((map[ycur*w+xcur]-zmax)*w/(xmax-xmin))\n var dx = 0\n var dy = 1\n while (1) {\n //\n // move to next point\n //\n xnext = xcur+dx\n ynext = ycur+dy\n if (xnext <= 0)\n //\n // done\n //\n break;\n //\n // find offset at next point\n //\n var znext = -Number.MAX_VALUE\n for (var xoffset = 0; xoffset < toolsize; ++xoffset)\n for (var yoffset = 0; yoffset < toolsize; ++yoffset) {\n var x = xnext+(xoffset-toolmiddle)\n var y = ynext+(yoffset-toolmiddle)\n var offset = tooloffset[yoffset*toolsize+xoffset]\n var z = Math.floor((map[y*w+x]-zmax)*w/(xmax-xmin))-offset\n if (z > znext)\n znext = z\n }\n //\n // vectorize\n //\n dxcur = xcur-xstart\n dycur = ycur-ystart\n dzcur = zcur-zstart\n dcur = Math.sqrt(dxcur*dxcur+dycur*dycur+dzcur*dzcur)\n nxcur = dxcur/dcur\n nycur = dycur/dcur\n nzcur = dzcur/dcur\n dxnext = xnext-xcur\n dynext = ynext-ycur\n dznext = znext-zcur\n dnext = Math.sqrt(dxnext*dxnext+dynext*dynext+dznext*dznext)\n nxnext = dxnext/dnext\n nynext = dynext/dnext\n nznext = dznext/dnext\n dot = nxcur*nxnext+nycur*nynext+nzcur*nznext\n if (dot <= (1-error)) {\n path[path.length-1].push([xcur,h-1-ycur,zcur])\n xstart = xcur\n ystart = ycur\n zstart = zcur\n }\n xcur = xnext\n ycur = ynext\n zcur = znext\n if (ycur == (h-1)) {\n if (dy == 1) {\n dy = 0\n dx = -step\n }\n else {\n dy = -1\n dx = 0\n }\n }\n else if (ycur == 0) {\n if (dy == -1) {\n dy = 0\n dx = -step\n }\n else {\n dy = 1\n dx = 0\n }\n }\n //\n // update progress\n //\n self.postMessage({type:'progress',value:xcur})\n }\n }\n //\n // return\n //\n self.postMessage({type:'path',path:path})\n self.close()\n })\n }\n//\n// return values\n//\nreturn ({\n mod:mod,\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n\n","top":"793.2645072647551","left":"258.7730903783895","filename":"modules/processes/mill/raster/3D","inputs":{},"outputs":{}}},"links":["{\"source\":\"{\\\"id\\\":\\\"0.0622871075904039\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"mesh\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.908940842104825\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"mesh\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.908940842104825\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"mesh\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.373975449262817\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"mesh\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.3062798763523076\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"file\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.5958662931535647\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"file\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.373975449262817\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"map\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.1219393240810458\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"map\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.1219393240810458\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"toolpath\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.21976500984768532\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"path\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.1219393240810458\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"toolpath\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.3062798763523076\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"path\\\"}\"}"]} +{"modules":{"0.0622871075904039":{"definition":"//\n// read stl\n//\n// Neil Gershenfeld\n// (c) Massachusetts Institute of Technology 2018\n//\n// This work may be reproduced, modified, distributed, performed, and\n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is\n// provided as is; no warranty is provided, and users accept all\n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'read STL'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\n }\n//\n// outputs\n//\nvar outputs = {\n mesh:{type:'STL',\n event:function(buffer){\n mods.output(mod,'mesh',buffer)}}\n }\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // file input control\n //\n var file = document.createElement('input')\n file.setAttribute('type','file')\n file.setAttribute('id',div.id+'file_input')\n file.style.position = 'absolute'\n file.style.left = 0\n file.style.top = 0\n file.style.width = 0\n file.style.height = 0\n file.style.opacity = 0\n file.addEventListener('change',function() {\n stl_read_handler()\n })\n div.appendChild(file)\n mod.file = file\n //\n // canvas\n //\n var canvas = document.createElement('canvas')\n canvas.width = mods.ui.canvas\n canvas.height = mods.ui.canvas\n canvas.style.backgroundColor = 'rgb(255,255,255)'\n div.appendChild(canvas)\n mod.canvas = canvas\n div.appendChild(document.createElement('br'))\n //\n // file select button\n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('select stl file'))\n btn.addEventListener('click',function(){\n var file = document.getElementById(div.id+'file_input')\n file.value = null\n file.click()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // info\n //\n var info = document.createElement('div')\n info.setAttribute('id',div.id+'info')\n var text = document.createTextNode('name: ')\n info.appendChild(text)\n mod.namen = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('size: ')\n info.appendChild(text)\n mod.sizen = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('triangles: ')\n info.appendChild(text)\n mod.trianglesn = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('dx: ')\n info.appendChild(text)\n mod.dxn = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('dy: ')\n info.appendChild(text)\n mod.dyn = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('dz: ')\n info.appendChild(text)\n mod.dzn = text\n div.appendChild(info)\n }\n//\n// local functions\n//\n// read handler\n//\nfunction stl_read_handler(event) {\n var file_reader = new FileReader()\n file_reader.onload = stl_load_handler\n input_file = mod.file.files[0]\n file_name = input_file.name\n mod.namen.nodeValue = 'name: '+file_name\n file_reader.readAsArrayBuffer(input_file)\n }\n//\n// load handler\n//\nfunction stl_load_handler(event) {\n //\n // check for binary STL\n //\n var endian = true\n var view = new DataView(event.target.result)\n var triangles = view.getUint32(80,endian)\n var size = 80+4+triangles*(4*12+2)\n if (size != view.byteLength) {\n mod.sizen.nodeValue = 'error: not binary STL'\n mod.trianglesn.nodeValue = ''\n mod.dxn.nodeValue = ''\n mod.dyn.nodeValue = ''\n mod.dzn.nodeValue = ''\n return\n }\n mod.sizen.nodeValue = 'size: '+size\n mod.trianglesn.nodeValue = 'triangles: '+triangles\n //\n // find limits and draw\n //\n var blob = new Blob(['('+draw_limits_worker.toString()+'())'])\n var url = window.URL.createObjectURL(blob)\n var webworker = new Worker(url)\n webworker.addEventListener('message',function(evt) {\n //\n // worker response\n //\n window.URL.revokeObjectURL(url)\n //\n // size\n //\n mod.dxn.nodeValue = 'dx: '+evt.data.dx.toFixed(3)\n mod.dyn.nodeValue = 'dy: '+evt.data.dy.toFixed(3)\n mod.dzn.nodeValue = 'dz: '+evt.data.dz.toFixed(3)\n //\n // image\n //\n var image = evt.data.image\n var height = mod.canvas.height\n var width = mod.canvas.width\n var buffer = new Uint8ClampedArray(evt.data.image)\n var imgdata = new ImageData(buffer,width,height)\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.putImageData(imgdata,0,0)\n //\n // output\n //\n outputs.mesh.event(evt.data.mesh)\n })\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n var img = ctx.getImageData(0,0,mod.canvas.width,mod.canvas.height)\n //\n // call worker\n //\n webworker.postMessage({\n height:mod.canvas.height,width:mod.canvas.width,\n image:img.data.buffer,mesh:event.target.result},\n [img.data.buffer,event.target.result])\n }\nfunction draw_limits_worker() {\n self.addEventListener('message',function(evt) {\n //\n // function to draw line\n //\n function line(x0,y0,x1,y1) {\n var ix0 = Math.floor(xo+xw*(x0-xmin)/dx)\n var iy0 = Math.floor(yo+yh*(ymax-y0)/dy)\n var ix1 = Math.floor(xo+xw*(x1-xmin)/dx)\n var iy1 = Math.floor(yo+yh*(ymax-y1)/dy)\n var row,col\n var idx = ix1-ix0\n var idy = iy1-iy0\n if (Math.abs(idy) > Math.abs(idx)) {\n (idy > 0) ?\n (row0=iy0,col0=ix0,row1=iy1,col1=ix1):\n (row0=iy1,col0=ix1,row1=iy0,col1=ix0)\n for (row = row0; row <= row1; ++row) {\n col = Math.floor(col0+(col1-col0)*(row-row0)/(row1-row0))\n image[row*width*4+col*4+0] = 0\n image[row*width*4+col*4+1] = 0\n image[row*width*4+col*4+2] = 0\n image[row*width*4+col*4+3] = 255\n }\n }\n else if ((Math.abs(idx) >= Math.abs(idy)) && (idx != 0)) {\n (idx > 0) ?\n (row0=iy0,col0=ix0,row1=iy1,col1=ix1):\n (row0=iy1,col0=ix1,row1=iy0,col1=ix0)\n for (col = col0; col <= col1; ++col) {\n row = Math.floor(row0+(row1-row0)*(col-col0)/(col1-col0))\n image[row*width*4+col*4+0] = 0\n image[row*width*4+col*4+1] = 0\n image[row*width*4+col*4+2] = 0\n image[row*width*4+col*4+3] = 255\n }\n }\n else {\n row = iy0\n col = ix0\n image[row*width*4+col*4+0] = 0\n image[row*width*4+col*4+1] = 0\n image[row*width*4+col*4+2] = 0\n image[row*width*4+col*4+3] = 255\n }\n }\n //\n // get variables\n //\n var height = evt.data.height\n var width = evt.data.width\n var endian = true\n var image = new Uint8ClampedArray(evt.data.image)\n var view = new DataView(evt.data.mesh)\n var triangles = view.getUint32(80,endian)\n //\n // find limits\n //\n var offset = 80+4\n var x0,x1,x2,y0,y1,y2,z0,z1,z2\n var xmin = Number.MAX_VALUE\n var xmax = -Number.MAX_VALUE\n var ymin = Number.MAX_VALUE\n var ymax = -Number.MAX_VALUE\n var zmin = Number.MAX_VALUE\n var zmax = -Number.MAX_VALUE\n for (var t = 0; t < triangles; ++t) {\n offset += 3*4\n x0 = view.getFloat32(offset,endian)\n offset += 4\n if (x0 > xmax) xmax = x0\n if (x0 < xmin) xmin = x0\n y0 = view.getFloat32(offset,endian)\n offset += 4\n if (y0 > ymax) ymax = y0\n if (y0 < ymin) ymin = y0\n z0 = view.getFloat32(offset,endian)\n offset += 4\n if (z0 > zmax) zmax = z0\n if (z0 < zmin) zmin = z0\n x1 = view.getFloat32(offset,endian)\n offset += 4\n if (x1 > xmax) xmax = x1\n if (x1 < xmin) xmin = x1\n y1 = view.getFloat32(offset,endian)\n offset += 4\n if (y1 > ymax) ymax = y1\n if (y1 < ymin) ymin = y1\n z1 = view.getFloat32(offset,endian)\n offset += 4\n if (z1 > zmax) zmax = z1\n if (z1 < zmin) zmin = z1\n x2 = view.getFloat32(offset,endian)\n offset += 4\n if (x2 > xmax) xmax = x2\n if (x2 < xmin) xmin = x2\n y2 = view.getFloat32(offset,endian)\n offset += 4\n if (y2 > ymax) ymax = y2\n if (y2 < ymin) ymin = y2\n z2 = view.getFloat32(offset,endian)\n offset += 4\n if (z2 > zmax) zmax = z2\n if (z2 < zmin) zmin = z2\n offset += 2\n }\n var dx = xmax-xmin\n var dy = ymax-ymin\n var dz = zmax-zmin\n //\n // draw mesh\n //\n if (dx > dy) {\n var xo = 0\n var yo = height*.5*(1-dy/dx)\n var xw = width-1\n var yh = (width-1)*dy/dx\n }\n else {\n var xo = width*.5*(1-dx/dy)\n var yo = 0\n var xw = (height-1)*dx/dy\n var yh = height-1\n }\n offset = 80+4\n for (var t = 0; t < triangles; ++t) {\n offset += 3*4\n x0 = view.getFloat32(offset,endian)\n offset += 4\n y0 = view.getFloat32(offset,endian)\n offset += 4\n z0 = view.getFloat32(offset,endian)\n offset += 4\n x1 = view.getFloat32(offset,endian)\n offset += 4\n y1 = view.getFloat32(offset,endian)\n offset += 4\n z1 = view.getFloat32(offset,endian)\n offset += 4\n x2 = view.getFloat32(offset,endian)\n offset += 4\n y2 = view.getFloat32(offset,endian)\n offset += 4\n z2 = view.getFloat32(offset,endian)\n offset += 4\n offset += 2\n line(x0,y0,x1,y1)\n line(x1,y1,x2,y2)\n line(x2,y2,x0,y0)\n }\n //\n // return results and close\n //\n self.postMessage({\n dx:dx,dy:dy,dz:dz,\n image:evt.data.image,mesh:evt.data.mesh},[evt.data.image,evt.data.mesh])\n self.close()\n })\n }\n//\n// return values\n//\nreturn ({\n mod:mod,\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"136.56257551578346","left":"158.8956250694314","filename":"undefined","inputs":{},"outputs":{}},"0.908940842104825":{"definition":"//\n// mesh rotate\n// \n// Neil Gershenfeld\n// (c) Massachusetts Institute of Technology 2018\n//\n// This work may be reproduced, modified, distributed, performed, and\n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is\n// provided as is; no warranty is provided, and users accept all\n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'mesh rotate'\n//\n// initialization\n//\nvar init = function() {\n mod.rx.value = '0'\n mod.ry.value = '0'\n mod.rz.value = '0'\n }\n//\n// inputs\n//\nvar inputs = {\n mesh:{type:'STL',\n event:function(evt){\n mod.mesh = evt.detail\n rotate_mesh()}}}\n//\n// outputs\n//\nvar outputs = {\n mesh:{type:'STL',\n event:function(buffer){\n mods.output(mod,'mesh',buffer)}}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // canvas\n //\n var canvas = document.createElement('canvas')\n canvas.width = mods.ui.canvas\n canvas.height = mods.ui.canvas\n canvas.style.backgroundColor = 'rgb(255,255,255)'\n div.appendChild(canvas)\n mod.canvas = canvas\n div.appendChild(document.createElement('br'))\n //\n // rotation\n //\n div.appendChild(document.createTextNode('rotation (degrees):'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode(' x: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n rotate_mesh()\n })\n div.appendChild(input)\n mod.rx = input\n div.appendChild(document.createTextNode(' y: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n rotate_mesh()\n })\n div.appendChild(input)\n mod.ry = input\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode(' z: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n rotate_mesh()\n })\n div.appendChild(input)\n mod.rz = input\n div.appendChild(document.createTextNode(' (enter)'))\n div.appendChild(document.createElement('br'))\n //\n // info\n //\n var text = document.createTextNode('dx:')\n div.appendChild(text)\n mod.dxn = text\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('dy:')\n div.appendChild(text)\n mod.dyn = text\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('dz:')\n div.appendChild(text)\n mod.dzn = text\n div.appendChild(document.createElement('br'))\n }\n//\n// local functions\n//\n// rotate mesh\n//\nfunction rotate_mesh() {\n //\n // check for binary STL\n //\n var endian = true\n var view = new DataView(mod.mesh)\n var triangles = view.getUint32(80,endian)\n var size = 80+4+triangles*(4*12+2)\n //\n // find limits, rotate, and draw\n //\n var blob = new Blob(['('+rotate_mesh_worker.toString()+'())'])\n var url = window.URL.createObjectURL(blob)\n var webworker = new Worker(url)\n webworker.addEventListener('message',function(evt) {\n //\n // worker response\n //\n window.URL.revokeObjectURL(url)\n //\n // size\n //\n mod.dxn.nodeValue = 'dx: '+evt.data.dx.toFixed(3)\n mod.dyn.nodeValue = 'dy: '+evt.data.dy.toFixed(3)\n mod.dzn.nodeValue = 'dz: '+evt.data.dz.toFixed(3)\n //\n // image\n //\n var image = evt.data.image\n var height = mod.canvas.height\n var width = mod.canvas.width\n var buffer = new Uint8ClampedArray(evt.data.image)\n var imgdata = new ImageData(buffer,width,height)\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.putImageData(imgdata,0,0)\n //\n // mesh\n //\n mod.mesh = evt.data.mesh\n //\n // output\n //\n outputs.mesh.event(evt.data.rotate)\n })\n //\n // call worker\n //\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n var img = ctx.getImageData(0,0,mod.canvas.width,mod.canvas.height)\n var rx = parseFloat(mod.rx.value)*Math.PI/180\n var ry = parseFloat(mod.ry.value)*Math.PI/180\n var rz = parseFloat(mod.rz.value)*Math.PI/180\n webworker.postMessage({\n height:mod.canvas.height,width:mod.canvas.width,\n rx:rx,ry:ry,rz:rz,\n image:img.data.buffer,mesh:mod.mesh},\n [img.data.buffer,mod.mesh])\n }\nfunction rotate_mesh_worker() {\n self.addEventListener('message',function(evt) {\n //\n // function to draw line\n //\n function line(x0,y0,x1,y1) {\n var ix0 = Math.floor(xo+xw*(x0-xmin)/dx)\n var iy0 = Math.floor(yo+yh*(ymax-y0)/dy)\n var ix1 = Math.floor(xo+xw*(x1-xmin)/dx)\n var iy1 = Math.floor(yo+yh*(ymax-y1)/dy)\n var row,col\n var idx = ix1-ix0\n var idy = iy1-iy0\n if (Math.abs(idy) > Math.abs(idx)) {\n (idy > 0) ?\n (row0=iy0,col0=ix0,row1=iy1,col1=ix1):\n (row0=iy1,col0=ix1,row1=iy0,col1=ix0)\n for (row = row0; row <= row1; ++row) {\n col = Math.floor(col0+(col1-col0)*(row-row0)/(row1-row0))\n image[row*width*4+col*4+0] = 0\n image[row*width*4+col*4+1] = 0\n image[row*width*4+col*4+2] = 0\n image[row*width*4+col*4+3] = 255\n }\n }\n else if ((Math.abs(idx) >= Math.abs(idy)) && (idx != 0)) {\n (idx > 0) ?\n (row0=iy0,col0=ix0,row1=iy1,col1=ix1):\n (row0=iy1,col0=ix1,row1=iy0,col1=ix0)\n for (col = col0; col <= col1; ++col) {\n row = Math.floor(row0+(row1-row0)*(col-col0)/(col1-col0))\n image[row*width*4+col*4+0] = 0\n image[row*width*4+col*4+1] = 0\n image[row*width*4+col*4+2] = 0\n image[row*width*4+col*4+3] = 255\n }\n }\n else {\n row = iy0\n col = ix0\n image[row*width*4+col*4+0] = 0\n image[row*width*4+col*4+1] = 0\n image[row*width*4+col*4+2] = 0\n image[row*width*4+col*4+3] = 255\n }\n }\n //\n // function to rotate point\n //\n function rotate(x,y,z) {\n var x1 = x\n var y1 = Math.cos(rx)*y-Math.sin(rx)*z\n var z1 = Math.sin(rx)*y+Math.cos(rx)*z\n var x2 = Math.cos(ry)*x1-Math.sin(ry)*z1\n var y2 = y1\n var z2 = Math.sin(ry)*x1+Math.cos(ry)*z1\n var x3 = Math.cos(rz)*x2-Math.sin(rz)*y2\n var y3 = Math.sin(rz)*x2+Math.cos(rz)*y2\n var z3 = z2\n //return([x3,y3,z3])\n return({x:x3,y:y3,z:z3})\n }\n //\n // get variables\n //\n var height = evt.data.height\n var width = evt.data.width\n var rx = evt.data.rx\n var ry = evt.data.ry\n var rz = evt.data.rz\n var endian = true\n var image = new Uint8ClampedArray(evt.data.image)\n var view = new DataView(evt.data.mesh)\n var triangles = view.getUint32(80,endian)\n //\n // find limits\n //\n var offset = 80+4\n var x0,x1,x2,y0,y1,y2,z0,z1,z2\n var xmin = Number.MAX_VALUE\n var xmax = -Number.MAX_VALUE\n var ymin = Number.MAX_VALUE\n var ymax = -Number.MAX_VALUE\n var zmin = Number.MAX_VALUE\n var zmax = -Number.MAX_VALUE\n for (var t = 0; t < triangles; ++t) {\n offset += 3*4\n x0 = view.getFloat32(offset,endian)\n offset += 4\n y0 = view.getFloat32(offset,endian)\n offset += 4\n z0 = view.getFloat32(offset,endian)\n offset += 4\n x1 = view.getFloat32(offset,endian)\n offset += 4\n y1 = view.getFloat32(offset,endian)\n offset += 4\n z1 = view.getFloat32(offset,endian)\n offset += 4\n x2 = view.getFloat32(offset,endian)\n offset += 4\n y2 = view.getFloat32(offset,endian)\n offset += 4\n z2 = view.getFloat32(offset,endian)\n offset += 4\n offset += 2\n var p0 = rotate(x0,y0,z0)\n if (p0.x > xmax) xmax = p0.x\n if (p0.x < xmin) xmin = p0.x\n if (p0.y > ymax) ymax = p0.y\n if (p0.y < ymin) ymin = p0.y\n if (p0.z > zmax) zmax = p0.z\n if (p0.z < zmin) zmin = p0.z\n var p1 = rotate(x1,y1,z1)\n if (p1.x > xmax) xmax = p1.x\n if (p1.x < xmin) xmin = p1.x\n if (p1.y > ymax) ymax = p1.y\n if (p1.y < ymin) ymin = p1.y\n if (p1.z > zmax) zmax = p1.z\n if (p1.z < zmin) zmin = p1.z\n var p2 = rotate(x2,y2,z2)\n if (p2.x > xmax) xmax = p2.x\n if (p2.x < xmin) xmin = p2.x\n if (p2.y > ymax) ymax = p2.y\n if (p2.y < ymin) ymin = p2.y\n if (p2.z > zmax) zmax = p2.z\n if (p2.z < zmin) zmin = p2.z\n }\n var dx = xmax-xmin\n var dy = ymax-ymin\n var dz = zmax-zmin\n //\n // copy mesh\n //\n var newbuf = evt.data.mesh.slice(0)\n var newview = new DataView(newbuf)\n //\n // copy and draw mesh\n //\n if (dx > dy) {\n var xo = 0\n var yo = height*.5*(1-dy/dx)\n var xw = (width-1)\n var yh = (width-1)*dy/dx\n }\n else {\n var xo = width*.5*(1-dx/dy)\n var yo = 0\n var xw = (height-1)*dx/dy\n var yh = (height-1)\n }\n offset = 80+4\n var newoffset = 80+4\n for (var t = 0; t < triangles; ++t) {\n offset += 3*4\n x0 = view.getFloat32(offset,endian)\n offset += 4\n y0 = view.getFloat32(offset,endian)\n offset += 4\n z0 = view.getFloat32(offset,endian)\n offset += 4\n x1 = view.getFloat32(offset,endian)\n offset += 4\n y1 = view.getFloat32(offset,endian)\n offset += 4\n z1 = view.getFloat32(offset,endian)\n offset += 4\n x2 = view.getFloat32(offset,endian)\n offset += 4\n y2 = view.getFloat32(offset,endian)\n offset += 4\n z2 = view.getFloat32(offset,endian)\n offset += 4\n offset += 2\n var p0 = rotate(x0,y0,z0)\n var p1 = rotate(x1,y1,z1)\n var p2 = rotate(x2,y2,z2)\n line(p0.x,p0.y,p1.x,p1.y)\n line(p1.x,p1.y,p2.x,p2.y)\n line(p2.x,p2.y,p0.x,p0.y)\n newoffset += 3*4\n newview.setFloat32(newoffset,p0.x,endian)\n newoffset += 4\n newview.setFloat32(newoffset,p0.y,endian)\n newoffset += 4\n newview.setFloat32(newoffset,p0.z,endian)\n newoffset += 4\n newview.setFloat32(newoffset,p1.x,endian)\n newoffset += 4\n newview.setFloat32(newoffset,p1.y,endian)\n newoffset += 4\n newview.setFloat32(newoffset,p1.z,endian)\n newoffset += 4\n newview.setFloat32(newoffset,p2.x,endian)\n newoffset += 4\n newview.setFloat32(newoffset,p2.y,endian)\n newoffset += 4\n newview.setFloat32(newoffset,p2.z,endian)\n newoffset += 4\n newoffset += 2\n }\n //\n // return results and close\n //\n self.postMessage({\n dx:dx,dy:dy,dz:dz,\n image:evt.data.image,mesh:evt.data.mesh,rotate:newbuf},\n [evt.data.image,evt.data.mesh,newbuf])\n self.close()\n })\n }\nfunction old_rotate_mesh() {\n //\n // function to rotate point\n //\n function rotate(x,y,z) {\n var x1 = x\n var y1 = Math.cos(rx)*y-Math.sin(rx)*z\n var z1 = Math.sin(rx)*y+Math.cos(rx)*z\n var x2 = Math.cos(ry)*x1-Math.sin(ry)*z1\n var y2 = y1\n var z2 = Math.sin(ry)*x1+Math.cos(ry)*z1\n var x3 = Math.cos(rz)*x2-Math.sin(rz)*y2\n var y3 = Math.sin(rz)*x2+Math.cos(rz)*y2\n var z3 = z2\n return([x3,y3,z3])\n }\n //\n // get vars\n //\n var view = mod.mesh\n var endian = true\n var triangles = view.getUint32(80,endian)\n mod.triangles = triangles\n var size = 80+4+triangles*(4*12+2)\n var rx = parseFloat(mod.rx.value)*Math.PI/180\n var ry = parseFloat(mod.ry.value)*Math.PI/180\n var rz = parseFloat(mod.rz.value)*Math.PI/180\n //\n // find limits\n //\n var offset = 80+4\n var x0,x1,x2,y0,y1,y2,z0,z1,z2\n var xmin = Number.MAX_VALUE\n var xmax = -Number.MAX_VALUE\n var ymin = Number.MAX_VALUE\n var ymax = -Number.MAX_VALUE\n var zmin = Number.MAX_VALUE\n var zmax = -Number.MAX_VALUE\n for (var t = 0; t < triangles; ++t) {\n offset += 3*4\n x0 = view.getFloat32(offset,endian)\n offset += 4\n y0 = view.getFloat32(offset,endian)\n offset += 4\n z0 = view.getFloat32(offset,endian)\n offset += 4\n x1 = view.getFloat32(offset,endian)\n offset += 4\n y1 = view.getFloat32(offset,endian)\n offset += 4\n z1 = view.getFloat32(offset,endian)\n offset += 4\n x2 = view.getFloat32(offset,endian)\n offset += 4\n y2 = view.getFloat32(offset,endian)\n offset += 4\n z2 = view.getFloat32(offset,endian)\n offset += 4\n offset += 2\n var p0 = rotate(x0,y0,z0)\n if (p0[0] > xmax) xmax = p0[0]\n if (p0[0] < xmin) xmin = p0[0]\n if (p0[1] > ymax) ymax = p0[1]\n if (p0[1] < ymin) ymin = p0[1]\n if (p0[2] > zmax) zmax = p0[2]\n if (p0[2] < zmin) zmin = p0[2]\n var p1 = rotate(x1,y1,z1)\n if (p1[0] > xmax) xmax = p1[0]\n if (p1[0] < xmin) xmin = p1[0]\n if (p1[1] > ymax) ymax = p1[1]\n if (p1[1] < ymin) ymin = p1[1]\n if (p1[2] > zmax) zmax = p1[2]\n if (p1[2] < zmin) zmin = p1[2]\n var p2 = rotate(x2,y2,z2)\n if (p2[0] > xmax) xmax = p2[0]\n if (p2[0] < xmin) xmin = p2[0]\n if (p2[1] > ymax) ymax = p2[1]\n if (p2[1] < ymin) ymin = p2[1]\n if (p2[2] > zmax) zmax = p2[2]\n if (p2[2] < zmin) zmin = p2[2]\n }\n mod.dx = xmax-xmin\n mod.dy = ymax-ymin\n mod.dz = zmax-zmin\n mod.dxn.nodeValue = 'dx: '+mod.dx.toFixed(3)\n mod.dyn.nodeValue = 'dy: '+mod.dy.toFixed(3)\n mod.dzn.nodeValue = 'dz: '+mod.dz.toFixed(3)\n mod.xmin = xmin\n mod.ymin = ymin\n mod.zmin = zmin\n mod.xmax = xmax\n mod.ymax = ymax\n mod.zmax = zmax\n //\n // copy mesh\n //\n var buf = mod.mesh.buffer.slice(0)\n var newview = new DataView(buf)\n //\n // draw projection and save rotation\n //\n var ctx = mod.meshcanvas.getContext('2d')\n var w = mod.meshcanvas.width\n var h = mod.meshcanvas.height\n ctx.clearRect(0,0,w,h)\n var dx = mod.dx\n var dy = mod.dy\n if (dx > dy) {\n var xo = 0\n var yo = h*.5*(1-dy/dx)\n var xw = w\n var yh = w*dy/dx\n }\n else {\n var xo = w*.5*(1-dx/dy)\n var yo = 0\n var xw = h*dx/dy\n var yh = h\n }\n ctx.beginPath()\n offset = 80+4\n var newoffset = 80+4\n for (var t = 0; t < triangles; ++t) {\n offset += 3*4\n x0 = view.getFloat32(offset,endian)\n offset += 4\n y0 = view.getFloat32(offset,endian)\n offset += 4\n z0 = view.getFloat32(offset,endian)\n offset += 4\n x1 = view.getFloat32(offset,endian)\n offset += 4\n y1 = view.getFloat32(offset,endian)\n offset += 4\n z1 = view.getFloat32(offset,endian)\n offset += 4\n x2 = view.getFloat32(offset,endian)\n offset += 4\n y2 = view.getFloat32(offset,endian)\n offset += 4\n z2 = view.getFloat32(offset,endian)\n offset += 4\n offset += 2\n var p0 = rotate(x0,y0,z0)\n var p1 = rotate(x1,y1,z1)\n var p2 = rotate(x2,y2,z2)\n x0 = xo+xw*(p0[0]-xmin)/dx\n y0 = yo+yh*(ymax-p0[1])/dy\n x1 = xo+xw*(p1[0]-xmin)/dx\n y1 = yo+yh*(ymax-p1[1])/dy\n x2 = xo+xw*(p2[0]-xmin)/dx\n y2 = yo+yh*(ymax-p2[1])/dy\n ctx.moveTo(x0,y0)\n ctx.lineTo(x1,y1)\n ctx.lineTo(x2,y2)\n ctx.lineTo(x0,y0)\n newoffset += 3*4\n newview.setFloat32(newoffset,p0[0],endian)\n newoffset += 4\n newview.setFloat32(newoffset,p0[1],endian)\n newoffset += 4\n newview.setFloat32(newoffset,p0[2],endian)\n newoffset += 4\n newview.setFloat32(newoffset,p1[0],endian)\n newoffset += 4\n newview.setFloat32(newoffset,p1[1],endian)\n newoffset += 4\n newview.setFloat32(newoffset,p1[2],endian)\n newoffset += 4\n newview.setFloat32(newoffset,p2[0],endian)\n newoffset += 4\n newview.setFloat32(newoffset,p2[1],endian)\n newoffset += 4\n newview.setFloat32(newoffset,p2[2],endian)\n newoffset += 4\n newoffset += 2\n }\n ctx.stroke()\n //\n // generate output\n //\n outputs.mesh.event(buf)\n }\n//\n// return values\n//\nreturn ({\n mod:mod,\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"267.56257551578346","left":"621.8956250694313","filename":"undefined","inputs":{},"outputs":{}},"0.373975449262817":{"definition":"//\n// mesh height map\n// \n// Neil Gershenfeld 1/16/20\n//\n// This work may be reproduced, modified, distributed, performed, and\n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is\n// provided as is; no warranty is provided, and users accept all\n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'mesh height map'\n//\n// initialization\n//\nvar init = function() {\n mod.mmunits.value = '25.4'\n mod.inunits.value = '1'\n mod.width.value = '1000'\n mod.border.value = '0'\n }\n//\n// inputs\n//\nvar inputs = {\n mesh:{type:'STL',\n event:function(evt){\n mod.mesh = new DataView(evt.detail)\n find_limits_map()}}}\n//\n// outputs\n//\nvar outputs = {\n map:{type:'',label:'height map',\n event:function(heightmap){\n var obj = {}\n obj.map = heightmap\n obj.xmin = mod.xmin\n obj.xmax = mod.xmax\n obj.ymin = mod.ymin\n obj.ymax = mod.ymax\n obj.zmin = mod.zmin\n obj.zmax = mod.zmax\n obj.width = mod.img.width\n obj.height = mod.img.height\n obj.mmunits = mod.mmunits.value\n mods.output(mod,'map',obj)\n }}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // on-screen height map canvas\n //\n div.appendChild(document.createTextNode(' '))\n var canvas = document.createElement('canvas')\n canvas.width = mods.ui.canvas\n canvas.height = mods.ui.canvas\n canvas.style.backgroundColor = 'rgb(255,255,255)'\n div.appendChild(canvas)\n mod.mapcanvas = canvas\n div.appendChild(document.createElement('br'))\n //\n // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\n //\n // mesh units\n //\n div.appendChild(document.createTextNode('mesh units: (enter)'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('mm: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n mod.inunits.value = parseFloat(mod.mmunits.value)/25.4\n find_limits_map()\n })\n div.appendChild(input)\n mod.mmunits = input\n div.appendChild(document.createTextNode(' in: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n mod.mmunits.value = parseFloat(mod.inunits.value)*25.4\n find_limits_map()\n })\n div.appendChild(input)\n mod.inunits = input\n //\n // mesh size\n //\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('mesh size:'))\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('XxYxZ (units)')\n div.appendChild(text)\n mod.meshsize = text\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('XxYxZ (mm)')\n div.appendChild(text)\n mod.mmsize = text\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('XxYxZ (in)')\n div.appendChild(text)\n mod.insize = text\n //\n // height map border \n //\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('border: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n find_limits_map()\n })\n div.appendChild(input)\n mod.border = input\n div.appendChild(document.createTextNode(' (units)'))\n //\n // height map width\n //\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('width: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n find_limits_map()\n })\n div.appendChild(input)\n mod.width = input\n div.appendChild(document.createTextNode(' (pixels)'))\n //\n // view height map\n //\n div.appendChild(document.createElement('br'))\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('view height map'))\n btn.addEventListener('click',function(){\n var win = window.open('')\n var btn = document.createElement('button')\n btn.appendChild(document.createTextNode('close'))\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.addEventListener('click',function(){\n win.close()\n })\n win.document.body.appendChild(btn)\n win.document.body.appendChild(document.createElement('br'))\n var canvas = document.createElement('canvas')\n canvas.width = mod.img.width\n canvas.height = mod.img.height\n win.document.body.appendChild(canvas)\n var ctx = canvas.getContext(\"2d\")\n ctx.drawImage(mod.img,0,0)\n })\n div.appendChild(btn)\n }\n//\n// local functions\n//\n// find limits then map \n//\nfunction find_limits_map() {\n var blob = new Blob(['('+limits_worker.toString()+'())'])\n var url = window.URL.createObjectURL(blob)\n var webworker = new Worker(url)\n webworker.addEventListener('message',function(evt) {\n window.URL.revokeObjectURL(url)\n mod.triangles = evt.data.triangles\n mod.xmin = evt.data.xmin\n mod.xmax = evt.data.xmax\n mod.ymin = evt.data.ymin\n mod.ymax = evt.data.ymax\n mod.zmin = evt.data.zmin\n mod.zmax = evt.data.zmax\n mod.dx = mod.xmax-mod.xmin\n mod.dy = mod.ymax-mod.ymin\n mod.dz = mod.zmax-mod.zmin\n mod.meshsize.nodeValue = \n mod.dx.toFixed(3)+' x '+\n mod.dy.toFixed(3)+' x '+\n mod.dz.toFixed(3)+' (units)'\n var mm = parseFloat(mod.mmunits.value)\n mod.mmsize.nodeValue = \n (mod.dx*mm).toFixed(3)+' x '+\n (mod.dy*mm).toFixed(3)+' x '+\n (mod.dz*mm).toFixed(3)+' (mm)'\n var inches = parseFloat(mod.inunits.value)\n mod.insize.nodeValue = \n (mod.dx*inches).toFixed(3)+' x '+\n (mod.dy*inches).toFixed(3)+' x '+\n (mod.dz*inches).toFixed(3)+' (in)'\n mods.fit(mod.div)\n map_mesh()\n })\n var border = parseFloat(mod.border.value)\n webworker.postMessage({\n mesh:mod.mesh,\n border:border})\n }\nfunction limits_worker() {\n self.addEventListener('message',function(evt) {\n var view = evt.data.mesh\n var border = evt.data.border\n //\n // get vars\n //\n var endian = true\n var triangles = view.getUint32(80,endian)\n var size = 80+4+triangles*(4*12+2)\n //\n // find limits\n //\n var offset = 80+4\n var x0,x1,x2,y0,y1,y2,z0,z1,z2\n var xmin = Number.MAX_VALUE\n var xmax = -Number.MAX_VALUE\n var ymin = Number.MAX_VALUE\n var ymax = -Number.MAX_VALUE\n var zmin = Number.MAX_VALUE\n var zmax = -Number.MAX_VALUE\n for (var t = 0; t < triangles; ++t) {\n offset += 3*4\n x0 = view.getFloat32(offset,endian)\n offset += 4\n y0 = view.getFloat32(offset,endian)\n offset += 4\n z0 = view.getFloat32(offset,endian)\n offset += 4\n x1 = view.getFloat32(offset,endian)\n offset += 4\n y1 = view.getFloat32(offset,endian)\n offset += 4\n z1 = view.getFloat32(offset,endian)\n offset += 4\n x2 = view.getFloat32(offset,endian)\n offset += 4\n y2 = view.getFloat32(offset,endian)\n offset += 4\n z2 = view.getFloat32(offset,endian)\n offset += 4\n offset += 2\n if (x0 > xmax) xmax = x0\n if (x0 < xmin) xmin = x0\n if (y0 > ymax) ymax = y0\n if (y0 < ymin) ymin = y0\n if (z0 > zmax) zmax = z0\n if (z0 < zmin) zmin = z0\n if (x1 > xmax) xmax = x1\n if (x1 < xmin) xmin = x1\n if (y1 > ymax) ymax = y1\n if (y1 < ymin) ymin = y1\n if (z1 > zmax) zmax = z1\n if (z1 < zmin) zmin = z1\n if (x2 > xmax) xmax = x2\n if (x2 < xmin) xmin = x2\n if (y2 > ymax) ymax = y2\n if (y2 < ymin) ymin = y2\n if (z2 > zmax) zmax = z2\n if (z2 < zmin) zmin = z2\n }\n xmin -= border\n xmax += border\n ymin -= border\n ymax += border\n //\n // return\n //\n self.postMessage({triangles:triangles,\n xmin:xmin,xmax:xmax,ymin:ymin,ymax:ymax,\n zmin:zmin,zmax:zmax})\n self.close()\n })\n }\n//\n// map mesh\n// \nfunction map_mesh() {\n var blob = new Blob(['('+map_worker.toString()+'())'])\n var url = window.URL.createObjectURL(blob)\n var webworker = new Worker(url)\n webworker.addEventListener('message',function(evt) {\n window.URL.revokeObjectURL(url)\n var h = mod.img.height\n var w = mod.img.width\n var buf = new Uint8ClampedArray(evt.data.imgbuffer)\n var map = new Float32Array(evt.data.mapbuffer)\n var imgdata = new ImageData(buf,w,h)\n var ctx = mod.img.getContext(\"2d\")\n ctx.putImageData(imgdata,0,0)\n if (w > h) {\n var x0 = 0\n var y0 = mod.mapcanvas.height*.5*(1-h/w)\n var wd = mod.mapcanvas.width\n var hd = mod.mapcanvas.width*h/w\n }\n else {\n var x0 = mod.mapcanvas.width*.5*(1-w/h)\n var y0 = 0\n var wd = mod.mapcanvas.height*w/h\n var hd = mod.mapcanvas.height\n }\n var ctx = mod.mapcanvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.mapcanvas.width,mod.mapcanvas.height)\n ctx.drawImage(mod.img,x0,y0,wd,hd)\n outputs.map.event(map)\n })\n var ctx = mod.mapcanvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.mapcanvas.width,mod.mapcanvas.height)\n mod.img.width = parseInt(mod.width.value)\n mod.img.height = Math.round(mod.img.width*mod.dy/mod.dx)\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n var map = new Float32Array(mod.img.width*mod.img.height)\n webworker.postMessage({\n height:mod.img.height,width:mod.img.width,\n imgbuffer:img.data.buffer,\n mapbuffer:map.buffer,\n mesh:mod.mesh,\n xmin:mod.xmin,xmax:mod.xmax,\n ymin:mod.ymin,ymax:mod.ymax,\n zmin:mod.zmin,zmax:mod.zmax},\n [img.data.buffer,map.buffer])\n }\nfunction map_worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var view = evt.data.mesh\n var xmin = evt.data.xmin\n var xmax = evt.data.xmax\n var ymin = evt.data.ymin\n var ymax = evt.data.ymax\n var zmin = evt.data.zmin\n var zmax = evt.data.zmax\n var buf = new Uint8ClampedArray(evt.data.imgbuffer)\n var map = new Float32Array(evt.data.mapbuffer)\n //\n // get vars from buffer\n //\n var endian = true\n var triangles = view.getUint32(80,endian)\n var size = 80+4+triangles*(4*12+2)\n //\n // initialize map and image\n //\n for (var row = 0; row < h; ++row) {\n for (var col = 0; col < w; ++col) {\n map[(h-1-row)*w+col] = zmin\n buf[(h-1-row)*w*4+col*4+0] = 0\n buf[(h-1-row)*w*4+col*4+1] = 0\n buf[(h-1-row)*w*4+col*4+2] = 0\n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n }\n //\n // loop over triangles\n //\n var segs = []\n offset = 80+4\n for (var t = 0; t < triangles; ++t) {\n offset += 3*4\n x0 = view.getFloat32(offset,endian)\n offset += 4\n y0 = view.getFloat32(offset,endian)\n offset += 4\n z0 = view.getFloat32(offset,endian)\n offset += 4\n x1 = view.getFloat32(offset,endian)\n offset += 4\n y1 = view.getFloat32(offset,endian)\n offset += 4\n z1 = view.getFloat32(offset,endian)\n offset += 4\n x2 = view.getFloat32(offset,endian)\n offset += 4\n y2 = view.getFloat32(offset,endian)\n offset += 4\n z2 = view.getFloat32(offset,endian)\n offset += 4\n offset += 2\n //\n // check normal if needs to be drawn\n //\n if (((x1-x0)*(y1-y2)-(x1-x2)*(y1-y0)) >= 0)\n continue\n //\n // quantize image coordinates\n //\n x0 = Math.floor((w-1)*(x0-xmin)/(xmax-xmin))\n x1 = Math.floor((w-1)*(x1-xmin)/(xmax-xmin))\n x2 = Math.floor((w-1)*(x2-xmin)/(xmax-xmin))\n y0 = Math.floor((h-1)*(y0-ymin)/(ymax-ymin))\n y1 = Math.floor((h-1)*(y1-ymin)/(ymax-ymin))\n y2 = Math.floor((h-1)*(y2-ymin)/(ymax-ymin))\n //\n // sort projection order\n //\n if (y1 > y2) {\n var temp = x1;\n x1 = x2;\n x2 = temp\n var temp = y1;\n y1 = y2;\n y2 = temp\n var temp = z1;\n z1 = z2;\n z2 = temp\n }\n if (y0 > y1) {\n var temp = x0;\n x0 = x1;\n x1 = temp\n var temp = y0;\n y0 = y1;\n y1 = temp\n var temp = z0;\n z0 = z1;\n z1 = temp\n }\n if (y1 > y2) {\n var temp = x1;\n x1 = x2;\n x2 = temp\n var temp = y1;\n y1 = y2;\n y2 = temp\n var temp = z1;\n z1 = z2;\n z2 = temp\n }\n //\n // check orientation after sort\n //\n if (x1 < (x0+((x2-x0)*(y1-y0))/(y2-y0)))\n var dir = 1;\n else\n var dir = -1;\n //\n // set z values\n //\n if (y2 != y1) {\n for (var y = y1; y <= y2; ++y) {\n x12 = Math.floor(0.5+x1+(y-y1)*(x2-x1)/(y2-y1))\n z12 = z1+(y-y1)*(z2-z1)/(y2-y1)\n x02 = Math.floor(0.5+x0+(y-y0)*(x2-x0)/(y2-y0))\n z02 = z0+(y-y0)*(z2-z0)/(y2-y0)\n if (x12 != x02)\n var slope = (z02-z12)/(x02-x12)\n else\n var slope = 0\n var x = x12 - dir\n while (x != x02) {\n x += dir\n var z = z12+slope*(x-x12)\n if (z > map[(h-1-y)*w+x]) {\n map[(h-1-y)*w+x] = z\n var iz = Math.floor(255*(z-zmin)/(zmax-zmin))\n buf[(h-1-y)*w*4+x*4+0] = iz\n buf[(h-1-y)*w*4+x*4+1] = iz\n buf[(h-1-y)*w*4+x*4+2] = iz\n }\n }\n }\n }\n if (y1 != y0) {\n for (var y = y0; y <= y1; ++y) {\n x01 = Math.floor(0.5+x0+(y-y0)*(x1-x0)/(y1-y0))\n z01 = z0+(y-y0)*(z1-z0)/(y1-y0)\n x02 = Math.floor(0.5+x0+(y-y0)*(x2-x0)/(y2-y0))\n z02 = z0+(y-y0)*(z2-z0)/(y2-y0)\n if (x01 != x02)\n var slope = (z02-z01)/(x02-x01)\n else\n var slope = 0\n var x = x01 - dir\n while (x != x02) {\n x += dir\n var z = z01+slope*(x-x01)\n if (z > map[(h-1-y)*w+x]) {\n map[(h-1-y)*w+x] = z\n var iz = Math.floor(255*(z-zmin)/(zmax-zmin))\n buf[(h-1-y)*w*4+x*4+0] = iz\n buf[(h-1-y)*w*4+x*4+1] = iz\n buf[(h-1-y)*w*4+x*4+2] = iz\n }\n }\n }\n }\n }\n //\n // output the map\n //\n self.postMessage({imgbuffer:buf.buffer,mapbuffer:map.buffer},[buf.buffer,map.buffer])\n self.close()\n })\n }\n//\n// return values\n//\nreturn ({\n mod:mod,\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"139.74169591194038","left":"1137.044414716277","filename":"undefined","inputs":{},"outputs":{}},"0.21976500984768532":{"definition":"//\n// view path\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2019\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is \n// provided as is; no warranty is provided, and users accept all \n// liability.\n//\n// todo:\n// erase and update new path\n// show depth info\n// show size\n// calculate camera far\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'view path'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\n path:{type:'',\n event:function(evt){\n mod.path = evt.detail.path\n mod.name = evt.detail.name\n mod.dpi = evt.detail.dpi\n mod.width = evt.detail.width\n mod.height = evt.detail.height\n mod.depth = evt.detail.depth\n show_path_info()\n show_path()\n mods.fit(mod.div)\n outputs.path.event()\n }}}\n//\n// outputs\n//\nvar outputs = {\n path:{type:'',\n event:function(){\n cmd = {}\n cmd.path = mod.path\n cmd.name = mod.name\n cmd.dpi = mod.dpi\n cmd.width = mod.width\n cmd.height = mod.height\n mods.output(mod,'path',cmd)\n }}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // info\n //\n var text = document.createTextNode('name: ')\n div.appendChild(text)\n mod.nametext = text\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('(mm)')\n div.appendChild(text)\n mod.mmtext = text\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('(in)')\n div.appendChild(text)\n mod.intext = text\n //\n // view\n // \n div.appendChild(document.createElement('br')) \n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('view')\n span.appendChild(text)\n btn.appendChild(span)\n btn.addEventListener('click',function(){\n open_view_window()\n })\n div.appendChild(btn)\n }\n//\n// local functions\n//\n// show_path_info\n//\nfunction show_path_info() {\n mod.nametext.nodeValue = 'name: '+mod.name\n var width = (25.4*mod.width/mod.dpi).toFixed(3)\n var height = (25.4*mod.height/mod.dpi).toFixed(3)\n var depth = (25.4*mod.depth/mod.dpi).toFixed(3)\n if (mod.depth == undefined)\n mod.mmtext.nodeValue = width+' x '+height+' (mm)'\n else\n mod.mmtext.nodeValue = width+' x '+height+' x '+depth+' (mm)'\n var width = (mod.width/mod.dpi).toFixed(3)\n var height = (mod.height/mod.dpi).toFixed(3)\n var depth = (mod.depth/mod.dpi).toFixed(3)\n if (mod.depth == undefined)\n mod.intext.nodeValue = width+' x '+height+' (in)'\n else\n mod.intext.nodeValue = width+' x '+height+' x '+depth+' (in)'\n mods.fit(mod.div)\n }\n//\n// show_path\n//\nfunction show_path() {\n var scene = mod.scene\n var camera = mod.camera\n var renderer = mod.renderer\n //\n // check if view window open\n //\n if (mod.win == undefined) {\n open_view_window()\n return\n }\n //\n // check for path\n //\n if (mod.path == undefined)\n return\n //\n // clear scene, leave camera\n //\n var length = scene.children.length\n for (var c = (length-1); c > 1; --c) {\n scene.remove(scene.children[c])\n }\n //\n // fit camera\n //\n mod.thetaxy = 0\n mod.thetaz = 0\n mod.r = mod.height/2\n mod.x0 = mod.width/2\n mod.y0 = mod.height/2\n camera.position.set(mod.x0,mod.y0,mod.r)\n camera.up = new THREE.Vector3(0,1,0)\n camera.lookAt(new THREE.Vector3(mod.x0,mod.y0,0))\n camera.updateProjectionMatrix()\n //\n // draw segments\n //\n var arrow_size = 1+mod.width/200\n var path = mod.path\n for (var segment = 0; segment < path.length; ++segment) {\n if (segment > 0)\n add_arrow(path[segment-1][path[segment-1].length-1],path[segment][0],0xff0000,arrow_size) \n for (var point = 1; point < path[segment].length; ++point) {\n add_arrow(path[segment][point-1],path[segment][point],0x0000ff,arrow_size)\n }\n }\n //\n // add axes\n //\n var length = mod.height/10\n add_arrow([0,0,0],[length,0,0],0xff0000,arrow_size)\n add_arrow([0,0,0],[0,length,0],0x00ff00,arrow_size)\n add_arrow([0,0,0],[0,0,length],0x0000ff,arrow_size)\n //\n // render\n //\n update()\n //\n // add_arrow\n //\n function add_arrow(start,stop,color,size) {\n var origin = new THREE.Vector3().fromArray(start)\n if (mod.depth == undefined)\n origin.z = 0\n var end = new THREE.Vector3().fromArray(stop)\n if (mod.depth == undefined)\n end.z = 0\n var length = new THREE.Vector3().subVectors(end,origin).length()\n if (length <= size) {\n add_line(origin,end,color)\n //length = 1.1*size\n return\n }\n var direction = new THREE.Vector3().subVectors(end,origin).normalize()\n var arrow = new THREE.ArrowHelper(direction,origin,length,color,size,size)\n scene.add(arrow)\n }\n //\n // add_line\n //\n function add_line(start,stop,colorhex) {\n var geometry = new THREE.Geometry()\n geometry.vertices.push(start,stop)\n var material = new THREE.LineBasicMaterial({color:colorhex})\n var line = new THREE.Line(geometry,material)\n scene.add(line)\n }\n //\n // update\n //\n function update() {\n renderer.render(scene,camera)\n }\n }\n//\n// open_view_window\n//\nfunction open_view_window() {\n //\n // open window\n //\n win = window.open('')\n mod.win = win\n //\n // load three.js\n //\n var script = document.createElement('script')\n script.type = 'text/javascript'\n script.onload = init_window\n script.src = 'js/three.js/three.min.js'\n mod.div.appendChild(script)\n }\n//\n// init_window\n//\nfunction init_window() {\n //document.write('<script type=\"text/javascript\">'+arg+'</script>')\n //document.close()\n //\n // close button\n //\n var btn = document.createElement('button')\n btn.appendChild(document.createTextNode('close'))\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.addEventListener('click',function(){\n mod.win.close()\n mod.win = undefined\n })\n mod.win.document.body.appendChild(btn)\n //\n // label text\n //\n var text = win.document.createTextNode(' left: pan, right: rotate, scroll: zoom')\n mod.win.document.body.appendChild(text)\n //\n // GL container\n //\n mod.win.document.body.appendChild(document.createElement('br')) \n container = mod.win.document.createElement('div')\n container.style.overflow = 'hidden'\n mod.win.document.body.appendChild(container)\n //\n // event handlers\n //\n container.addEventListener('contextmenu',context_menu)\n container.addEventListener('mousedown',mouse_down)\n container.addEventListener('mouseup',mouse_up)\n container.addEventListener('mousemove',mouse_move)\n container.addEventListener('wheel',mouse_wheel)\n //\n // add scene\n //\n scene = new THREE.Scene()\n mod.scene = scene\n var width = mod.win.innerWidth\n var height = mod.win.innerHeight\n var aspect = width/height\n var near = 0.1\n var far = 1000000\n camera = new THREE.PerspectiveCamera(90,aspect,near,far)\n mod.camera = camera\n scene.add(camera)\n //\n // add renderer\n //\n renderer = new THREE.WebGLRenderer({antialias:true})\n mod.renderer = renderer\n renderer.setClearColor(0xffffff)\n renderer.setSize(width,height)\n container.appendChild(renderer.domElement)\n //\n // show the path if available\n //\n show_path()\n //\n // context_menu\n //\n function context_menu(evt) {\n evt.preventDefault()\n evt.stopPropagation()\n return (false)\n }\n //\n // mouse_down\n //\n function mouse_down(evt) {\n evt.preventDefault()\n evt.stopPropagation()\n mod.button = evt.button\n mod.x = evt.clientX\n mod.y = evt.clientY\n }\n //\n // mouse_up\n //\n function mouse_up(evt) {\n mod.button = undefined\n mod.x = evt.clientX\n mod.y = evt.clientY\n }\n //\n // mouse_move\n //\n function mouse_move(evt) {\n evt.preventDefault()\n evt.stopPropagation()\n var dx = evt.clientX-mod.x\n var dy = evt.clientY-mod.y\n mod.x = evt.clientX\n mod.y = evt.clientY\n if (mod.button == 0) {\n mod.x0 += \n Math.sin(mod.thetaz)*mod.height*dy/mod.win.innerHeight\n -Math.cos(mod.thetaz)*mod.width*dx/mod.win.innerWidth\n mod.y0 += \n Math.cos(mod.thetaz)*mod.height*dy/mod.win.innerHeight\n +Math.sin(mod.thetaz)*mod.width*dx/mod.win.innerWidth\n camera.position.x = mod.x0+Math.sin(mod.thetaz)*mod.r*Math.sin(mod.thetaxy)\n camera.position.y = mod.y0+Math.cos(mod.thetaz)*mod.r*Math.sin(mod.thetaxy)\n camera.position.z = mod.r*Math.cos(mod.thetaxy)\n camera.position.z = mod.r*Math.cos(mod.thetaxy)\n camera.up = new THREE.Vector3(Math.sin(mod.thetaz),Math.cos(mod.thetaz),0)\n camera.lookAt(new THREE.Vector3(mod.x0,mod.y0,0))\n camera.updateProjectionMatrix()\n renderer.render(scene,camera)\n }\n else if (mod.button == 2) {\n mod.thetaxy += dy/mod.win.innerHeight\n mod.thetaz += dx/mod.win.innerWidth\n camera.position.x = mod.x0+Math.sin(mod.thetaz)*mod.r*Math.sin(mod.thetaxy)\n camera.position.y = mod.y0+Math.cos(mod.thetaz)*mod.r*Math.sin(mod.thetaxy)\n camera.position.z = mod.r*Math.cos(mod.thetaxy)\n if (Math.cos(mod.thetaxy) > 0)\n camera.up = new THREE.Vector3(Math.sin(mod.thetaz),Math.cos(mod.thetaz),0)\n else\n camera.up = new THREE.Vector3(-Math.sin(mod.thetaz),-Math.cos(mod.thetaz),0)\n camera.lookAt(new THREE.Vector3(mod.x0,mod.y0,0))\n camera.updateProjectionMatrix()\n renderer.render(scene,camera)\n }\n }\n //\n // mouse_wheel\n //\n function mouse_wheel(evt) {\n evt.preventDefault()\n evt.stopPropagation()\n var dy = evt.deltaY/mod.win.innerHeight\n mod.r += mod.height*dy\n camera.position.x = mod.x0+Math.sin(mod.thetaz)*mod.r*Math.sin(mod.thetaxy)\n camera.position.y = mod.y0+Math.cos(mod.thetaz)*mod.r*Math.sin(mod.thetaxy)\n camera.position.z = mod.r*Math.cos(mod.thetaxy)\n camera.lookAt(new THREE.Vector3(mod.x0,mod.y0,0))\n camera.updateProjectionMatrix()\n renderer.render(scene,camera)\n }\n }\n//\n// return values\n//\nreturn ({\n mod:mod,\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"812.6523741401768","left":"1138.1605451628693","filename":"undefined","inputs":{},"outputs":{}},"0.3062798763523076":{"definition":"//\n// Roland SRM-20 milling machine\n//\n// Neil Gershenfeld\n// (c) Massachusetts Institute of Technology 2016\n//\n// This work may be reproduced, modified, distributed, performed, and\n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is\n// provided as is; no warranty is provided, and users accept all\n// liability.\n//\n// closure\n//\n/*\nG-codes:\nG00X10.0\nG90 (absolute positioning)\nG21 (mm units)\n#.0 numbers\nG00 (positioning rapid move)\nG01 (linear motion)\nM03 (start spindle)\nM05 (stop spindle)\nF (feed rate mm/min, 6-1800)\n203.2 (X) x 152.4 (Y) x 60.5 (Z) mm \n*/\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'Roland SRM-20 milling machine'\n//\n// initialization\n//\nvar init = function() {\n mod.units = 100.0\n mod.speed.value = 4\n mod.ox.value = 10\n mod.oy.value = 10\n mod.oz.value = 10\n mod.jz.value = 2\n mod.hx.value = 0\n mod.hy.value = 152.4\n mod.hz.value = 60.5\n }\n//\n// inputs\n//\nvar inputs = {\n path:{type:'',\n event:function(evt){\n mod.name = evt.detail.name\n mod.path = evt.detail.path\n mod.dpi = evt.detail.dpi\n mod.width = evt.detail.width\n mod.height = evt.detail.height\n make_path()\n }}}\n//\n// outputs\n//\nvar outputs = {\n file:{type:'',\n event:function(obj){\n mods.output(mod,'file',obj)\n }}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // speed\n //\n div.appendChild(document.createTextNode('speed: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.speed = input\n div.appendChild(document.createTextNode(' (mm/s)'))\n div.appendChild(document.createElement('br'))\n //\n // origin\n //\n div.appendChild(document.createTextNode('origin:'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('x: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.ox = input\n div.appendChild(document.createTextNode(' (mm)'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode(' y: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.oy = input\n div.appendChild(document.createTextNode(' (mm)'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('z: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.oz = input\n div.appendChild(document.createTextNode(' (mm)'))\n div.appendChild(document.createElement('br'))\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('move to origin')\n span.appendChild(text)\n btn.appendChild(span)\n btn.addEventListener('click',function(){\n var x0 = mod.units*parseFloat(mod.ox.value);\n var y0 = mod.units*parseFloat(mod.oy.value);\n var z0 = mod.units*parseFloat(mod.oz.value);\n var zjog = z0+mod.units*parseFloat(mod.jz.value);\n //\n // G-code version\n //\n /*\n str = '%\\n' // data start\n str += 'G90\\n' // absolute units\n str += 'G21\\n' // mm units\n str += 'G00Z30.0\\n' // move z\n str += 'M02\\n' // end of program\n */\n //\n // RML version\n //\n var str = \"PA;PA;VS10;!VZ10;!PZ0,\"+zjog+\";PU\"+x0+\",\"+y0+\";Z\"+x0+\",\"+y0+\",\"+z0+\";!MC0;\"+\"\\u0004\"\n //\n // send command\n //\n var obj = {}\n obj.type = 'command'\n obj.name = mod.name+'.rml'\n obj.contents = str\n outputs.file.event(obj)\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // jog\n //\n div.appendChild(document.createTextNode('jog height:'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('z: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.jz = input\n div.appendChild(document.createTextNode(' (mm)'))\n div.appendChild(document.createElement('br'))\n //\n // home\n //\n div.appendChild(document.createTextNode('home:'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('x: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.hx = input\n div.appendChild(document.createTextNode(' (mm)'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode(' y: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.hy = input\n div.appendChild(document.createTextNode(' (mm)'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('z: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.hz = input\n div.appendChild(document.createTextNode(' (mm)'))\n div.appendChild(document.createElement('br'))\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('move to home')\n span.appendChild(text)\n btn.appendChild(span)\n btn.addEventListener('click',function(){\n var xhome = mod.units*parseFloat(mod.hx.value);\n var yhome = mod.units*parseFloat(mod.hy.value);\n var zhome = mod.units*parseFloat(mod.hz.value);\n //\n // G-code version\n //\n /*\n str = '%\\n' // data start\n str += 'G90\\n' // absolute units\n str += 'G21\\n' // mm units\n str += 'G00Z50.0\\n' // move z\n str += 'M02\\n' // end of program\n */\n //\n // RML version\n //\n var str = \"PA;PA;!PZ0,\"+zhome+\";PU\"+xhome+\",\"+yhome+\";!MC0;\"+\"\\u0004\"\n //\n // send command\n //\n var obj = {}\n obj.type = 'command'\n obj.name = mod.name+'.rml'\n obj.contents = str\n outputs.file.event(obj)\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n }\n//\n// local functions\n//\nfunction make_path() {\n var dx = 25.4*mod.width/mod.dpi\n var nx = mod.width\n var speed = parseFloat(mod.speed.value)\n var jog = parseFloat(mod.oz.value)+parseFloat(mod.jz.value)\n var ijog = Math.floor(mod.units*jog)\n var scale = mod.units*dx/(nx-1)\n var x0 = parseFloat(mod.ox.value)\n var y0 = parseFloat(mod.oy.value)\n var z0 = parseFloat(mod.oz.value)\n var xoffset = mod.units*x0\n var yoffset = mod.units*y0\n var zoffset = mod.units*z0\n var str = \"PA;PA;\" // plot absolute\n str += \"VS\"+speed+\";!VZ\"+speed+\";\"\n str += \"!PZ\"+0+\",\"+ijog+\";\" // set jog\n str += \"!MC1;\\n\" // turn motor on\n //\n // follow segments\n //\n for (var seg = 0; seg < mod.path.length; ++seg) {\n //\n // move up to starting point\n //\n x = xoffset+scale*mod.path[seg][0][0]\n y = yoffset+scale*mod.path[seg][0][1]\n str += \"PU\"+x.toFixed(0)+\",\"+y.toFixed(0)+\";\\n\"\n //\n // move down\n //\n z = zoffset+scale*mod.path[seg][0][2]\n str += \"Z\"+x.toFixed(0)+\",\"+y.toFixed(0)+\",\"+z.toFixed(0)+\";\\n\"\n for (var pt = 1; pt < mod.path[seg].length; ++pt) {\n //\n // move to next point\n //\n x = xoffset+scale*mod.path[seg][pt][0]\n y = yoffset+scale*mod.path[seg][pt][1]\n z = zoffset+scale*mod.path[seg][pt][2]\n str += \"Z\"+x.toFixed(0)+\",\"+y.toFixed(0)+\",\"+z.toFixed(0)+\";\\n\"\n }\n //\n // move up\n //\n str += \"PU\"+x.toFixed(0)+\",\"+y.toFixed(0)+\";\\n\"\n }\n //\n // turn off motor and move back\n //\n var xhome = mod.units*parseFloat(mod.hx.value)\n var yhome = mod.units*parseFloat(mod.hy.value)\n var zhome = mod.units*parseFloat(mod.hz.value)\n str += \"PA;PA;!PZ0,\"+zhome+\";PU\"+xhome+\",\"+yhome+\";!MC0;\"\n //\n // output string\n //\n var obj = {}\n obj.type = 'file'\n obj.name = mod.name+'.rml'\n obj.contents = str\n outputs.file.event(obj)\n }\n//\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"996.4160179248521","left":"605.6998069155255","filename":"modules/path/machines/Roland/milling/SRM-20","inputs":{},"outputs":{}},"0.1219393240810458":{"definition":"//\n// mill raster 3D\n//\n// Neil Gershenfeld 10/22/21\n//\n// This work may be reproduced, modified, distributed, performed, and\n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is\n// provided as is; no warranty is provided, and users accept all\n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'mill raster 3D'\n//\n// initialization\n//\nvar init = function() {\n mod.dia_in.value = '0.125'\n mod.dia_mm.value = '3.175'\n mod.stepover.value = '0.5'\n mod.error.value = '0.001'\n }\n//\n// inputs\n//\nvar inputs = {\n map:{type:'',label:'height map',\n event:function(evt){\n mod.map = evt.detail.map\n mod.xmin = evt.detail.xmin\n mod.xmax = evt.detail.xmax\n mod.ymin = evt.detail.ymin\n mod.ymax = evt.detail.ymax\n mod.zmin = evt.detail.zmin\n mod.zmax = evt.detail.zmax\n mod.width = evt.detail.width\n mod.height = evt.detail.height\n mod.depth = Math.floor((mod.zmax-mod.zmin)*mod.width/(mod.xmax-mod.xmin))\n mod.mmunits = evt.detail.mmunits\n mod.dpi = mod.width/(mod.mmunits*(mod.xmax-mod.xmin)/25.4)\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = mod.width\n ctx.canvas.height = mod.height\n }}}\n//\n// outputs\n//\nvar outputs = {\n toolpath:{type:'',\n event:function(){\n obj = {}\n obj.path = mod.path\n obj.name = \"mill raster 3D\"\n obj.dpi = mod.dpi\n obj.width = mod.width\n obj.height = mod.height\n obj.depth = mod.depth\n mods.output(mod,'toolpath',obj)\n }}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // tool diameter\n //\n div.appendChild(document.createTextNode('tool diameter'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('mm: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('input',function(){\n mod.dia_in.value = parseFloat(mod.dia_mm.value)/25.4\n })\n div.appendChild(input)\n mod.dia_mm = input\n div.appendChild(document.createTextNode(' in: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('input',function(){\n mod.dia_mm.value = parseFloat(mod.dia_in.value)*25.4\n })\n div.appendChild(input)\n mod.dia_in = input\n div.appendChild(document.createElement('br'))\n //\n // stepover\n //\n div.appendChild(document.createTextNode('stepover (0-1): '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.stepover = input\n div.appendChild(document.createElement('br'))\n //\n // tool shape\n //\n div.appendChild(document.createTextNode('tool shape: '))\n var input = document.createElement('input')\n input.type = 'radio'\n input.name = mod.div.id+'shape'\n input.id = mod.div.id+'flatend'\n input.checked = true\n div.appendChild(input)\n mod.flatend= input\n div.appendChild(document.createTextNode('flat end'))\n div.appendChild(document.createElement('br'))\n //\n // direction \n //\n div.appendChild(document.createTextNode('direction: '))\n var input = document.createElement('input')\n input.type = 'checkbox'\n input.id = mod.div.id+'xz'\n input.checked = true\n div.appendChild(input)\n mod.dirxz = input\n div.appendChild(document.createTextNode('xz'))\n var input = document.createElement('input')\n input.type = 'checkbox'\n input.id = mod.div.id+'yz'\n input.checked = true\n div.appendChild(input)\n mod.diryz = input\n div.appendChild(document.createTextNode('yz'))\n div.appendChild(document.createElement('br'))\n //\n // fit error \n //\n div.appendChild(document.createTextNode('vector fit: '))\n //div.appendChild(document.createElement('br'))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n div.appendChild(input)\n mod.error = input\n div.appendChild(document.createElement('br'))\n //\n // calculate\n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('calculate')\n mod.label = text\n span.appendChild(text)\n mod.labelspan = span\n btn.appendChild(span)\n btn.addEventListener('click',function(){\n mod.label.nodeValue = 'calculating'\n mod.labelspan.style.fontWeight = 'bold'\n calculate_path()\n })\n div.appendChild(btn)\n div.appendChild(document.createTextNode(' '))\n //\n // view\n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('view'))\n btn.addEventListener('click',function(){\n var win = window.open('')\n var btn = document.createElement('button')\n btn.appendChild(document.createTextNode('close'))\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.addEventListener('click',function(){\n win.close()\n })\n win.document.body.appendChild(btn)\n win.document.body.appendChild(document.createElement('br'))\n var svg = document.getElementById(mod.div.id+'svg')\n var clone = svg.cloneNode(true)\n clone.setAttribute('width',mod.img.width)\n clone.setAttribute('height',mod.img.height)\n win.document.body.appendChild(clone)\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // on-screen SVG\n //\n var svgNS = \"http://www.w3.org/2000/svg\"\n var svg = document.createElementNS(svgNS,\"svg\")\n svg.setAttribute('id',mod.div.id+'svg')\n svg.setAttributeNS(\"http://www.w3.org/2000/xmlns/\",\n \"xmlns:xlink\",\"http://www.w3.org/1999/xlink\")\n svg.setAttribute('width',mods.ui.canvas)\n svg.setAttribute('height',mods.ui.canvas)\n svg.style.backgroundColor = 'rgb(255,255,255)'\n var g = document.createElementNS(svgNS,'g')\n g.setAttribute('id',mod.div.id+'g')\n svg.appendChild(g)\n div.appendChild(svg)\n div.appendChild(document.createElement('br'))\n //\n // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\n }\n//\n// local functions\n//\n// calculate path\n//\nfunction calculate_path() {\n var blob = new Blob(['('+calculate_path_worker.toString()+'())'])\n var url = window.URL.createObjectURL(blob)\n var webworker = new Worker(url)\n webworker.addEventListener('message',function(evt) {\n if (evt.data.type == \"progress\") {\n mod.label.nodeValue = evt.data.value\n return\n }\n //\n // webworker handler\n //\n mod.path = evt.data.path\n mod.label.nodeValue = 'calculate'\n mod.labelspan.style.fontWeight = 'normal'\n //\n // clear SVG\n //\n var svg = document.getElementById(mod.div.id+'svg')\n svg.setAttribute('viewBox',\"0 0 \"+(mod.width-1)+\" \"+(mod.height-1))\n var g = document.getElementById(mod.div.id+'g')\n svg.removeChild(g)\n var g = document.createElementNS('http://www.w3.org/2000/svg','g')\n g.setAttribute('id',mod.div.id+'g')\n svg.appendChild(g)\n //\n // plot path\n //\n for (var i = 1; i < mod.path[0].length; ++i) {\n var ixp = mod.path[0][i-1][0]\n var iyp = mod.height-1-mod.path[0][i-1][1]\n var izp = 0.1*mod.path[0][i-1][2]\n var ix = mod.path[0][i][0]\n var iy = mod.height-1-mod.path[0][i][1]\n var iz = 0.1*mod.path[0][i][2]\n var line = document.createElementNS(\n 'http://www.w3.org/2000/svg','line')\n line.setAttribute('stroke','black')\n line.setAttribute('stroke-width',1)\n line.setAttribute('stroke-linecap','round')\n line.setAttribute('x1',ixp)\n line.setAttribute('y1',iyp-izp)\n line.setAttribute('x2',ix)\n line.setAttribute('y2',iy-iz)\n g.appendChild(line)\n }\n //\n // output path\n //\n outputs.toolpath.event()\n })\n //\n // call webworker\n //\n webworker.postMessage({\n height:mod.height,width:mod.width,\n error:mod.error.value,\n xmin:mod.xmin,xmax:mod.xmax,\n ymin:mod.ymin,ymax:mod.ymax,\n zmin:mod.zmin,zmax:mod.zmax,\n diameter:mod.dia_mm.value,\n stepover:mod.stepover.value,\n mmunits: mod.mmunits,\n xz:mod.dirxz.checked,\n yz:mod.diryz.checked,\n map:mod.map})\n }\n//\n// calculate path worker\n//\nfunction calculate_path_worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var error = evt.data.error\n var xmin = evt.data.xmin\n var xmax = evt.data.xmax\n var ymin = evt.data.ymin\n var ymax = evt.data.ymax\n var zmin = evt.data.zmin\n var zmax = evt.data.zmax\n var map = evt.data.map\n var diameter = evt.data.diameter\n var stepover = evt.data.stepover\n var mmunits = evt.data.mmunits\n var step = Math.floor(stepover*diameter*w/(mmunits*(xmax-xmin)))\n var path = []\n //\n // construct tool offset\n //\n var toolsize = Math.floor(diameter*w/(mmunits*(xmax-xmin)))\n var tooloffset = new Float32Array(toolsize*toolsize)\n var toolmiddle = Math.floor(toolsize/2)\n for (var x = 0; x < toolsize; ++x)\n for (var y = 0; y < toolsize; ++y) {\n var r = Math.sqrt((x-toolmiddle)*(x-toolmiddle)+(y-toolmiddle)*(y-toolmiddle))\n if (r <= toolmiddle)\n tooloffset[y*toolsize+x] = 0\n else\n tooloffset[y*toolsize+x] = Number.MAX_VALUE\n }\n //\n // xz\n //\n if (evt.data.xz) {\n path.push([])\n var xstart = 0\n var ystart = h-1\n var zstart = Math.floor((map[ystart*w+xstart]-zmax)*w/(xmax-xmin))\n path[path.length-1].push([xstart,h-1-ystart,zstart])\n var xcur = 1\n var ycur = h-1\n var zcur = Math.floor((map[ycur*w+xcur]-zmax)*w/(xmax-xmin))\n var dx = 1\n var dy = 0\n while (1) {\n //\n // move to next point\n //\n xnext = xcur+dx\n ynext = ycur+dy\n if (ynext <= 0)\n //\n // done\n //\n break;\n //\n // find offset at next point\n //\n var znext = -Number.MAX_VALUE\n for (var xoffset = 0; xoffset < toolsize; ++xoffset)\n for (var yoffset = 0; yoffset < toolsize; ++yoffset) {\n var x = xnext+(xoffset-toolmiddle)\n var y = ynext+(yoffset-toolmiddle)\n var offset = tooloffset[yoffset*toolsize+xoffset]\n var z = Math.floor((map[y*w+x]-zmax)*w/(xmax-xmin))-offset\n if (z > znext)\n znext = z\n }\n //\n // vectorize\n //\n dxcur = xcur-xstart\n dycur = ycur-ystart\n dzcur = zcur-zstart\n dcur = Math.sqrt(dxcur*dxcur+dycur*dycur+dzcur*dzcur)\n nxcur = dxcur/dcur\n nycur = dycur/dcur\n nzcur = dzcur/dcur\n dxnext = xnext-xcur\n dynext = ynext-ycur\n dznext = znext-zcur\n dnext = Math.sqrt(dxnext*dxnext+dynext*dynext+dznext*dznext)\n nxnext = dxnext/dnext\n nynext = dynext/dnext\n nznext = dznext/dnext\n dot = nxcur*nxnext+nycur*nynext+nzcur*nznext\n if (dot <= (1-error)) {\n path[path.length-1].push([xcur,h-1-ycur,zcur])\n xstart = xcur\n ystart = ycur\n zstart = zcur\n }\n xcur = xnext\n ycur = ynext\n zcur = znext\n if (xcur == (w-1)) {\n if (dx == 1) {\n dx = 0\n dy = -step\n }\n else {\n dx = -1\n dy = 0\n }\n }\n else if (xcur == 0) {\n if (dx == -1) {\n dx = 0\n dy = -step\n }\n else {\n dx = 1\n dy = 0\n }\n }\n //\n // update progress\n //\n self.postMessage({type:'progress',value:ycur})\n }\n }\n //\n // yz\n //\n if (evt.data.yz) {\n path.push([])\n var xstart = w-1\n var ystart = 0\n var zstart = Math.floor((map[ystart*w+xstart]-zmax)*w/(xmax-xmin))\n path[path.length-1].push([xstart,h-1-ystart,zstart])\n var xcur = w-1\n var ycur = 1\n var zcur = Math.floor((map[ycur*w+xcur]-zmax)*w/(xmax-xmin))\n var dx = 0\n var dy = 1\n while (1) {\n //\n // move to next point\n //\n xnext = xcur+dx\n ynext = ycur+dy\n if (xnext <= 0)\n //\n // done\n //\n break;\n //\n // find offset at next point\n //\n var znext = -Number.MAX_VALUE\n for (var xoffset = 0; xoffset < toolsize; ++xoffset)\n for (var yoffset = 0; yoffset < toolsize; ++yoffset) {\n var x = xnext+(xoffset-toolmiddle)\n var y = ynext+(yoffset-toolmiddle)\n var offset = tooloffset[yoffset*toolsize+xoffset]\n var z = Math.floor((map[y*w+x]-zmax)*w/(xmax-xmin))-offset\n if (z > znext)\n znext = z\n }\n //\n // vectorize\n //\n dxcur = xcur-xstart\n dycur = ycur-ystart\n dzcur = zcur-zstart\n dcur = Math.sqrt(dxcur*dxcur+dycur*dycur+dzcur*dzcur)\n nxcur = dxcur/dcur\n nycur = dycur/dcur\n nzcur = dzcur/dcur\n dxnext = xnext-xcur\n dynext = ynext-ycur\n dznext = znext-zcur\n dnext = Math.sqrt(dxnext*dxnext+dynext*dynext+dznext*dznext)\n nxnext = dxnext/dnext\n nynext = dynext/dnext\n nznext = dznext/dnext\n dot = nxcur*nxnext+nycur*nynext+nzcur*nznext\n if (dot <= (1-error)) {\n path[path.length-1].push([xcur,h-1-ycur,zcur])\n xstart = xcur\n ystart = ycur\n zstart = zcur\n }\n xcur = xnext\n ycur = ynext\n zcur = znext\n if (ycur == (h-1)) {\n if (dy == 1) {\n dy = 0\n dx = -step\n }\n else {\n dy = -1\n dx = 0\n }\n }\n else if (ycur == 0) {\n if (dy == -1) {\n dy = 0\n dx = -step\n }\n else {\n dy = 1\n dx = 0\n }\n }\n //\n // update progress\n //\n self.postMessage({type:'progress',value:xcur})\n }\n }\n //\n // return\n //\n self.postMessage({type:'path',path:path})\n self.close()\n })\n }\n//\n// return values\n//\nreturn ({\n mod:mod,\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n\n","top":"808.3581822735247","left":"186.5449079625481","filename":"modules/processes/mill/raster/3D","inputs":{},"outputs":{}},"0.7511308551424929":{"definition":"//\n// devie server module\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2016\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is \n// provided as is; no warranty is provided, and users accept all \n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'WebSocket device'\n//\n// initialization\n//\nvar init = function() {\n mod.address.value = '127.0.0.1'\n mod.port.value = '1234'\n mod.device.value = 'usb/lp0'\n mod.socket = null\n socket_open()\n }\n//\n// inputs\n//\nvar inputs = {\n file:{type:'',\n event:function(evt){\n if (evt.detail.type == 'command') {\n mod.command = evt.detail\n mod.command.device = mod.device.value\n mod.command.type = 'print'\n socket_send(JSON.stringify(mod.command))\n }\n else if (evt.detail.type == 'file') {\n mod.job = evt.detail\n mod.label.nodeValue = 'send file to device'\n mod.labelspan.style.fontWeight = 'bold'\n }\n }}}\n//\n// outputs\n//\nvar outputs = {\n }\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // server\n //\n var a = document.createElement('a')\n a.href = './js/deviceserver.js'\n a.innerHTML = 'deviceserver:'\n a.target = '_blank'\n div.appendChild(a)\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('address: '))\n input = document.createElement('input')\n input.type = 'text'\n input.size = 10\n div.appendChild(input)\n mod.address = input\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('\\u00a0\\u00a0\\u00a0\\u00a0\\u00a0port: '))\n input = document.createElement('input')\n input.type = 'text'\n input.size = 10\n div.appendChild(input)\n mod.port = input\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('\\u00a0\\u00a0status: '))\n input = document.createElement('input')\n input.type = 'text'\n input.size = 10\n div.appendChild(input)\n mod.status = input\n div.appendChild(document.createElement('br'))\n //\n // open/close\n //\n var btn = document.createElement('button')\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('open'))\n btn.addEventListener('click',function() {\n socket_open()\n })\n div.appendChild(btn)\n var btn = document.createElement('button')\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('close'))\n btn.addEventListener('click',function() {\n socket_close()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // device\n //\n div.appendChild(document.createTextNode('device:'))\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('/dev/'))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 10\n div.appendChild(input)\n mod.device = input\n div.appendChild(document.createElement('br')) \n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('waiting for file')\n mod.label = text\n span.appendChild(text)\n mod.labelspan = span\n btn.appendChild(span)\n btn.addEventListener('click',function(){\n if (mod.socket == null) {\n mod.status.value = \"can't send, not open\"\n }\n else if (mod.label.nodeValue == 'send file to device') {\n mod.job.device = mod.device.value\n mod.job.type = 'print'\n socket_send(JSON.stringify(mod.job))\n mod.label.nodeValue = 'cancel'\n }\n else if (mod.label.nodeValue == 'cancel') {\n socket_send('cancel')\n }\n })\n div.appendChild(btn)\n }\n//\n// local functions\n//\nfunction socket_open() {\n var url = \"ws://\"+mod.address.value+':'+mod.port.value\n mod.socket = new WebSocket(url)\n mod.socket.onopen = function(event) {\n mod.status.value = \"socket opened\"\n }\n mod.socket.onerror = function(event) {\n mod.status.value = \"can not open socket\"\n mod.socket = null\n }\n mod.socket.onmessage = function(event) {\n mod.status.value = event.data\n if ((event.data == 'done') || (event.data == 'cancel')\n || (event.data.slice(0,5) == 'error')) {\n mod.label.nodeValue = 'waiting for file'\n mod.labelspan.style.fontWeight = 'normal'\n }\n }\n }\nfunction socket_close() {\n mod.socket.close()\n mod.status.value = \"socket closed\"\n mod.socket = null\n }\nfunction socket_send(msg) {\n if (mod.socket != null) {\n mod.status.value = \"send\"\n mod.socket.send(msg)\n }\n else {\n mod.status.value = \"can't send, not open\"\n }\n }\n//\n// return values\n//\nreturn ({\n mod:mod,\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"1069.8879136918972","left":"1111.1037791753797","filename":"modules/socket/server/device","inputs":{},"outputs":{}}},"links":["{\"source\":\"{\\\"id\\\":\\\"0.0622871075904039\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"mesh\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.908940842104825\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"mesh\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.908940842104825\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"mesh\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.373975449262817\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"mesh\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.373975449262817\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"map\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.1219393240810458\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"map\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.1219393240810458\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"toolpath\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.21976500984768532\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"path\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.1219393240810458\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"toolpath\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.3062798763523076\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"path\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.3062798763523076\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"file\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.7511308551424929\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"file\\\"}\"}"]} \ No newline at end of file -- GitLab