Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
M
mods
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
pub
mods
Commits
110ad9cb
Commit
110ad9cb
authored
5 years ago
by
Neil Gershenfeld
Browse files
Options
Downloads
Patches
Plain Diff
ready for tool shape
parent
b6716e9b
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
programs/machines/ShopBot/mill 3D stl
+1
-1
1 addition, 1 deletion
programs/machines/ShopBot/mill 3D stl
with
1 addition
and
1 deletion
programs/machines/ShopBot/mill 3D stl
+
1
−
1
View file @
110ad9cb
{"modules":{"0.9903638182304415":{"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":"90.24915179990126","left":"102.0959522649269","inputs":{},"outputs":{}},"0.7269098240824425":{"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 = '500'\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 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":"216.04059431282388","left":"528.1347679591628","inputs":{},"outputs":{}},"0.36382263595289266":{"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":"260.3760318972536","left":"1427.9604217500023","inputs":{},"outputs":{}},"0.11764362271570472":{"definition":"//\n// mill raster 3D (incomplete)\n//\n// Neil Gershenfeld 1/18/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 = 'mill raster 3D (incomplete)'\n//\n// initialization\n//\nvar init = function() {\n mod.dia_in.value = '0.0156'\n mod.dia_mm.value = '0.39624'\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.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.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.dpi = mod.width/(mod.xmax-mod.xmin)\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 = 'radio'\n input.name = mod.div.id+'direction'\n input.id = mod.div.id+'dirx'\n input.checked = true\n div.appendChild(input)\n mod.dirx = input\n div.appendChild(document.createTextNode('xz'))\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 //\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.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.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 h:mod.height,w:mod.width,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 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.h\n var w = evt.data.w\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 path = [[]]\n //\n // loop over lines\n //\n xstart = 0\n ystart = h-1\n zstart = Math.floor((map[ystart*w+xstart]-zmax)*w/(xmax-xmin))\n path[0].push([xstart,ystart,zstart])\n xcur = 1\n ycur = h-1\n zcur = Math.floor((map[ycur*w+xcur]-zmax)*w/(xmax-xmin))\n dx = 1\n dy = 0\n while (1) {\n //\n // vectorize\n //\n xnext = xcur+dx\n ynext = ycur+dy\n znext = Math.floor((map[ynext*w+xnext]-zmax)*w/(xmax-xmin))\n if (ynext <= 0)\n break;\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[0].push([xcur,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 = -10\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 = -10\n }\n else {\n dx = 1\n dy = 0\n }\n }\n }\n //\n // return\n //\n self.postMessage({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":"117.98691577370033","left":"948.4463703512538","inputs":{},"outputs":{}}},"links":["{\"source\":\"{\\\"id\\\":\\\"0.9903638182304415\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"mesh\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.7269098240824425\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"mesh\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.7269098240824425\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"map\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.11764362271570472\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"map\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.11764362271570472\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"toolpath\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.36382263595289266\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"path\\\"}\"}"]}
\ No newline at end of file
{"modules":{"0.9903638182304415":{"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":"122.24915179990126","left":"293.0959522649269","inputs":{},"outputs":{}},"0.36382263595289266":{"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":"292.3760318972536","left":"1618.9604217500023","inputs":{},"outputs":{}},"0.3399235295113725":{"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 = '1'\n mod.inunits.value = '0.03937007874015748'\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":"239","left":"740","inputs":{},"outputs":{}},"0.28008868461487135":{"definition":"//\n// mill raster 3D (incomplete)\n//\n// Neil Gershenfeld 1/18/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 = 'mill raster 3D (incomplete)'\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 = 'radio'\n input.name = mod.div.id+'direction'\n input.id = mod.div.id+'dirx'\n input.checked = true\n div.appendChild(input)\n mod.dirx = input\n div.appendChild(document.createTextNode('xz'))\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 //\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.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.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 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 ystep = Math.floor(stepover*diameter*w/(mmunits*(xmax-xmin)))\n var path = [[]]\n //\n // loop over lines\n //\n xstart = 0\n ystart = h-1\n zstart = Math.floor((map[ystart*w+xstart]-zmax)*w/(xmax-xmin))\n path[0].push([xstart,ystart,zstart])\n xcur = 1\n ycur = h-1\n zcur = Math.floor((map[ycur*w+xcur]-zmax)*w/(xmax-xmin))\n dx = 1\n dy = 0\n while (1) {\n //\n // vectorize\n //\n xnext = xcur+dx\n ynext = ycur+dy\n znext = Math.floor((map[ynext*w+xnext]-zmax)*w/(xmax-xmin))\n if (ynext <= 0)\n break;\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[0].push([xcur,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 = -ystep\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 = -ystep\n }\n else {\n dx = 1\n dy = 0\n }\n }\n }\n //\n // return\n //\n self.postMessage({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":"156","left":"1206","inputs":{},"outputs":{}}},"links":["{\"source\":\"{\\\"id\\\":\\\"0.9903638182304415\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"mesh\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.3399235295113725\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"mesh\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.3399235295113725\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"map\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.28008868461487135\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"map\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.28008868461487135\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"toolpath\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.36382263595289266\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"path\\\"}\"}"]}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment