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
8fdcd854
Commit
8fdcd854
authored
5 years ago
by
Neil Gershenfeld
Browse files
Options
Downloads
Patches
Plain Diff
wip
parent
1f13a1c3
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
modules/processes/mill/raster/3D
+1
-210
1 addition, 210 deletions
modules/processes/mill/raster/3D
programs/machines/ShopBot/mill 3D stl
+1
-1
1 addition, 1 deletion
programs/machines/ShopBot/mill 3D stl
with
2 additions
and
211 deletions
modules/processes/mill/raster/3D
+
1
−
210
View file @
8fdcd854
...
@@ -243,7 +243,7 @@ function calculate_path() {
...
@@ -243,7 +243,7 @@ function calculate_path() {
var x = xmin+(xmax-xmin)*ix/(w-1)
var x = xmin+(xmax-xmin)*ix/(w-1)
var y = ymin+(ymax-ymin)*iy/(h-1)
var y = ymin+(ymax-ymin)*iy/(h-1)
var z = mod.map[(h-1-iy)*w+ix]
var z = mod.map[(h-1-iy)*w+ix]
var dz = h*(zmax-z)/(ymax-ymin)
var dz =
0.1*
h*(zmax-z)/(ymax-ymin)
while (1) {
while (1) {
var ixp = ix
var ixp = ix
var iyp = iy
var iyp = iy
...
@@ -289,215 +289,6 @@ function calculate_path() {
...
@@ -289,215 +289,6 @@ function calculate_path() {
mod.label.nodeValue = 'calculate'
mod.label.nodeValue = 'calculate'
mod.labelspan.style.fontWeight = 'normal'
mod.labelspan.style.fontWeight = 'normal'
}
}
//
// clear_path
//
function clear_path() {
}
//
// accumulate_path
// todo: replace inefficient insertion sort
// todo: move sort out of main thread
//
function accumulate_path(path) {
var forward = mod.forward.checked
var conventional = mod.conventional.checked
var sort = mod.sort.checked
for (var segnew = 0; segnew < path.length; ++segnew) {
if (conventional)
path[segnew].reverse()
if (mod.path.length == 0)
mod.path.splice(0,0,path[segnew])
else if (sort) {
var xnew = path[segnew][0][0]
var ynew = path[segnew][0][1]
var dmin = Number.MAX_VALUE
var segmin = -1
for (var segold = 0; segold < mod.path.length; ++segold) {
var xold = mod.path[segold][0][0]
var yold = mod.path[segold][0][1]
var dx = xnew-xold
var dy = ynew-yold
var d = Math.sqrt(dx*dx+dy*dy)
if (d < dmin) {
dmin = d
segmin = segold
}
}
if (forward)
mod.path.splice(segmin+1,0,path[segnew])
else
mod.path.splice(segmin,0,path[segnew])
}
else {
if (forward)
mod.path.splice(mod.path.length,0,path[segnew])
else
mod.path.splice(0,0,path[segnew])
}
}
}
//
// merge_path
//
function merge_path() {
var dmerge = mod.dpi*parseFloat(mod.merge.value)*parseFloat(mod.dia_in.value)
var seg = 0
while (seg < (mod.path.length-1)) {
var xold = mod.path[seg][mod.path[seg].length-1][0]
var yold = mod.path[seg][mod.path[seg].length-1][1]
var xnew = mod.path[seg+1][0][0]
var ynew = mod.path[seg+1][0][1]
var dx = xnew-xold
var dy = ynew-yold
var d = Math.sqrt(dx*dx+dy*dy)
if (d < dmerge)
mod.path.splice(seg,2,mod.path[seg].concat(mod.path[seg+1]))
else
seg += 1
}
}
//
// add_depth
//
function add_depth() {
var cut = parseFloat(mod.cut_in.value)
var max = parseFloat(mod.max_in.value)
var newpath = []
for (var seg = 0; seg < mod.path.length; ++seg) {
var depth = cut
if (mod.path[seg][0][0] == mod.path[seg][mod.path[seg].length-1][0]) {
var newseg = []
while (depth <= max) {
var idepth = -Math.round(mod.dpi*depth)
for (var pt = 0; pt < mod.path[seg].length; ++pt) {
var point = mod.path[seg][pt].concat(idepth)
newseg.splice(newseg.length,0,point)
}
if (depth == max)
break
depth += cut
if (depth > max)
depth = max
}
newpath.splice(newpath.length,0,newseg)
}
else {
var newseg = []
while (depth <= max) {
var idepth = -Math.round(mod.dpi*depth)
for (var pt = 0; pt < mod.path[seg].length; ++pt) {
var point = mod.path[seg][pt].concat(idepth)
newseg.splice(newseg.length,0,point)
}
newpath.splice(newpath.length,0,newseg)
newseg = []
if (depth == max)
break
depth += cut
if (depth > max)
depth = max
}
}
}
mod.path = newpath
mod.depth = Math.round(parseFloat(mod.max_in.value)*mod.dpi)
}
//
// draw_path
//
function draw_path(path) {
var g = document.getElementById(mod.div.id+'g')
var h = mod.img.height
var w = mod.img.width
var xend = null
var yend = null
//
// loop over segments
//
for (var segment = 0; segment < path.length; ++segment) {
if (path[segment].length > 1) {
//
// loop over points
//
for (var point = 1; point < path[segment].length; ++point) {
var line = document.createElementNS('http://www.w3.org/2000/svg','line')
line.setAttribute('stroke','black')
line.setAttribute('stroke-width',1)
line.setAttribute('stroke-linecap','round')
var x1 = path[segment][point-1][0]
var y1 = h-path[segment][point-1][1]-1
var x2 = path[segment][point][0]
var y2 = h-path[segment][point][1]-1
xend = x2
yend = y2
line.setAttribute('x1',x1)
line.setAttribute('y1',y1)
line.setAttribute('x2',x2)
line.setAttribute('y2',y2)
var dx = x2-x1
var dy = y2-y1
var d = Math.sqrt(dx*dx+dy*dy)
if (d > 0) {
nx = 6*dx/d
ny = 6*dy/d
var tx = 3*dy/d
var ty = -3*dx/d
g.appendChild(line)
triangle = document.createElementNS('http://www.w3.org/2000/svg','polygon')
triangle.setAttribute('points',x2+','+y2+' '+(x2-nx+tx)+','+(y2-ny+ty)
+' '+(x2-nx-tx)+','+(y2-ny-ty))
triangle.setAttribute('fill','black')
g.appendChild(triangle)
}
}
}
}
}
//
// draw_connections
//
function draw_connections() {
var g = document.getElementById(mod.div.id+'g')
var h = mod.img.height
var w = mod.img.width
//
// loop over segments
//
for (var segment = 1; segment < mod.path.length; ++segment) {
//
// draw connection from previous segment
//
var line = document.createElementNS('http://www.w3.org/2000/svg','line')
line.setAttribute('stroke','red')
line.setAttribute('stroke-width',1)
line.setAttribute('stroke-linecap','round')
var x1 = mod.path[segment-1][mod.path[segment-1].length-1][0]
var y1 = h-mod.path[segment-1][mod.path[segment-1].length-1][1]-1
var x2 = mod.path[segment][0][0]
var y2 = h-mod.path[segment][0][1]-1
line.setAttribute('x1',x1)
line.setAttribute('y1',y1)
line.setAttribute('x2',x2)
line.setAttribute('y2',y2)
var dx = x2-x1
var dy = y2-y1
var d = Math.sqrt(dx*dx+dy*dy)
if (d > 0) {
nx = 6*dx/d
ny = 6*dy/d
var tx = 3*dy/d
var ty = -3*dx/d
g.appendChild(line)
triangle = document.createElementNS('http://www.w3.org/2000/svg','polygon')
triangle.setAttribute('points',x2+','+y2+' '+(x2-nx+tx)+','+(y2-ny+ty)
+' '+(x2-nx-tx)+','+(y2-ny-ty))
triangle.setAttribute('fill','red')
g.appendChild(triangle)
}
}
}
//
//
// return values
// return values
//
//
...
...
This diff is collapsed.
Click to expand it.
programs/machines/ShopBot/mill 3D stl
+
1
−
1
View file @
8fdcd854
{"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":"102.61657499836218","left":"97.22330127332333","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":"228.40801751128484","left":"523.2621169675592","inputs":{},"outputs":{}},"0.536212242526729":{"definition":"//\n// mill raster 3D\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 = '1'\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.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 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 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 cmd.depth = mod.depth\n mods.output(mod,'toolpath',cmd)\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 (pixels): '))\n //div.appendChild(document.createElement('br'))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n vectorize()\n })\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 h = mod.height\n var w = mod.width\n var xmin = mod.xmin\n var xmax = mod.xmax\n var ymin = mod.ymin\n var ymax = mod.ymax\n var zmin = mod.zmin\n var zmax = mod.zmax\n //\n // clear SVG\n //\n var svg = document.getElementById(mod.div.id+'svg')\n svg.setAttribute('viewBox',\"0 0 \"+(w-1)+\" \"+(h-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 // line loop\n //\n var ix = 0\n var iy = h-1\n var dx = 1\n var dy = 0\n var x = xmin+(xmax-xmin)*ix/(w-1)\n var y = ymin+(ymax-ymin)*iy/(h-1)\n var z = mod.map[(h-1-iy)*w+ix]\n var dz = h*(zmax-z)/(ymax-ymin)\n while (1) {\n var ixp = ix\n var iyp = iy\n var dzp = dz\n ix += dx\n iy += dy\n if (iy <= 0)\n break;\n var x = xmin+(xmax-xmin)*ix/(w-1)\n var y = ymin+(ymax-ymin)*iy/(h-1)\n var z = mod.map[iy*w+ix]\n var dz = 0.1*h*(zmax-z)/(zmax-zmin)\n var line = document.createElementNS('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+dzp)\n line.setAttribute('x2',ix)\n line.setAttribute('y2',iy+dz)\n g.appendChild(line)\n if (ix == (mod.width-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 (ix == 0) {\n if (dx == -1) {\n dx = 0\n dy = -10\n }\n else {\n dx = 1\n dy = 0\n }\n }\n }\n mod.label.nodeValue = 'calculate'\n mod.labelspan.style.fontWeight = 'normal'\n }\n\n//\n// clear_path\n//\nfunction clear_path() {\n }\n//\n// accumulate_path\n// todo: replace inefficient insertion sort\n// todo: move sort out of main thread\n//\nfunction accumulate_path(path) {\n var forward = mod.forward.checked\n var conventional = mod.conventional.checked\n var sort = mod.sort.checked\n for (var segnew = 0; segnew < path.length; ++segnew) {\n if (conventional)\n path[segnew].reverse()\n if (mod.path.length == 0)\n mod.path.splice(0,0,path[segnew])\n else if (sort) {\n var xnew = path[segnew][0][0]\n var ynew = path[segnew][0][1]\n var dmin = Number.MAX_VALUE\n var segmin = -1\n for (var segold = 0; segold < mod.path.length; ++segold) {\n var xold = mod.path[segold][0][0]\n var yold = mod.path[segold][0][1]\n var dx = xnew-xold\n var dy = ynew-yold\n var d = Math.sqrt(dx*dx+dy*dy)\n if (d < dmin) {\n dmin = d\n segmin = segold\n }\n }\n if (forward)\n mod.path.splice(segmin+1,0,path[segnew])\n else\n mod.path.splice(segmin,0,path[segnew])\n }\n else {\n if (forward)\n mod.path.splice(mod.path.length,0,path[segnew])\n else\n mod.path.splice(0,0,path[segnew])\n }\n }\n }\n//\n// merge_path\n//\nfunction merge_path() {\n var dmerge = mod.dpi*parseFloat(mod.merge.value)*parseFloat(mod.dia_in.value)\n var seg = 0\n while (seg < (mod.path.length-1)) {\n var xold = mod.path[seg][mod.path[seg].length-1][0]\n var yold = mod.path[seg][mod.path[seg].length-1][1]\n var xnew = mod.path[seg+1][0][0]\n var ynew = mod.path[seg+1][0][1]\n var dx = xnew-xold\n var dy = ynew-yold\n var d = Math.sqrt(dx*dx+dy*dy)\n if (d < dmerge)\n mod.path.splice(seg,2,mod.path[seg].concat(mod.path[seg+1]))\n else\n seg += 1\n }\n }\n//\n// add_depth\n//\nfunction add_depth() {\n var cut = parseFloat(mod.cut_in.value)\n var max = parseFloat(mod.max_in.value)\n var newpath = []\n for (var seg = 0; seg < mod.path.length; ++seg) {\n var depth = cut\n if (mod.path[seg][0][0] == mod.path[seg][mod.path[seg].length-1][0]) {\n var newseg = []\n while (depth <= max) {\n var idepth = -Math.round(mod.dpi*depth)\n for (var pt = 0; pt < mod.path[seg].length; ++pt) {\n var point = mod.path[seg][pt].concat(idepth)\n newseg.splice(newseg.length,0,point)\n }\n if (depth == max)\n break\n depth += cut\n if (depth > max)\n depth = max\n }\n newpath.splice(newpath.length,0,newseg)\n }\n else {\n var newseg = []\n while (depth <= max) {\n var idepth = -Math.round(mod.dpi*depth)\n for (var pt = 0; pt < mod.path[seg].length; ++pt) {\n var point = mod.path[seg][pt].concat(idepth)\n newseg.splice(newseg.length,0,point)\n }\n newpath.splice(newpath.length,0,newseg)\n newseg = []\n if (depth == max)\n break\n depth += cut\n if (depth > max)\n depth = max\n }\n }\n }\n mod.path = newpath\n mod.depth = Math.round(parseFloat(mod.max_in.value)*mod.dpi)\n }\n//\n// draw_path\n//\nfunction draw_path(path) {\n var g = document.getElementById(mod.div.id+'g')\n var h = mod.img.height\n var w = mod.img.width\n var xend = null\n var yend = null\n //\n // loop over segments\n //\n for (var segment = 0; segment < path.length; ++segment) {\n if (path[segment].length > 1) {\n //\n // loop over points\n //\n for (var point = 1; point < path[segment].length; ++point) {\n var line = document.createElementNS('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 var x1 = path[segment][point-1][0]\n var y1 = h-path[segment][point-1][1]-1\n var x2 = path[segment][point][0]\n var y2 = h-path[segment][point][1]-1\n xend = x2\n yend = y2\n line.setAttribute('x1',x1)\n line.setAttribute('y1',y1)\n line.setAttribute('x2',x2)\n line.setAttribute('y2',y2)\n var dx = x2-x1\n var dy = y2-y1\n var d = Math.sqrt(dx*dx+dy*dy)\n if (d > 0) {\n nx = 6*dx/d\n ny = 6*dy/d\n var tx = 3*dy/d\n var ty = -3*dx/d\n g.appendChild(line)\n triangle = document.createElementNS('http://www.w3.org/2000/svg','polygon')\n triangle.setAttribute('points',x2+','+y2+' '+(x2-nx+tx)+','+(y2-ny+ty)\n +' '+(x2-nx-tx)+','+(y2-ny-ty))\n triangle.setAttribute('fill','black')\n g.appendChild(triangle)\n }\n }\n }\n }\n }\n//\n// draw_connections\n//\nfunction draw_connections() {\n var g = document.getElementById(mod.div.id+'g')\n var h = mod.img.height\n var w = mod.img.width\n //\n // loop over segments\n //\n for (var segment = 1; segment < mod.path.length; ++segment) {\n //\n // draw connection from previous segment\n //\n var line = document.createElementNS('http://www.w3.org/2000/svg','line')\n line.setAttribute('stroke','red')\n line.setAttribute('stroke-width',1)\n line.setAttribute('stroke-linecap','round')\n var x1 = mod.path[segment-1][mod.path[segment-1].length-1][0]\n var y1 = h-mod.path[segment-1][mod.path[segment-1].length-1][1]-1\n var x2 = mod.path[segment][0][0]\n var y2 = h-mod.path[segment][0][1]-1\n line.setAttribute('x1',x1)\n line.setAttribute('y1',y1)\n line.setAttribute('x2',x2)\n line.setAttribute('y2',y2)\n var dx = x2-x1\n var dy = y2-y1\n var d = Math.sqrt(dx*dx+dy*dy)\n if (d > 0) {\n nx = 6*dx/d\n ny = 6*dy/d\n var tx = 3*dy/d\n var ty = -3*dx/d\n g.appendChild(line)\n triangle = document.createElementNS('http://www.w3.org/2000/svg','polygon')\n triangle.setAttribute('points',x2+','+y2+' '+(x2-nx+tx)+','+(y2-ny+ty)\n +' '+(x2-nx-tx)+','+(y2-ny-ty))\n triangle.setAttribute('fill','red')\n g.appendChild(triangle)\n }\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":"112.66259275401453","left":"950.4095131219412","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.536212242526729\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"map\\\"}\"}"]}
{"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":"101.09025323814005","left":"124.55170608551913","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":"226.8816957510627","left":"550.590521779755","inputs":{},"outputs":{}},"0.09986325972778665":{"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 = '1'\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.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 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 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 cmd.depth = mod.depth\n mods.output(mod,'toolpath',cmd)\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 input.addEventListener('change',function(){\n vectorize()\n })\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 h = mod.height\n var w = mod.width\n var xmin = mod.xmin\n var xmax = mod.xmax\n var ymin = mod.ymin\n var ymax = mod.ymax\n var zmin = mod.zmin\n var zmax = mod.zmax\n //\n // clear SVG\n //\n var svg = document.getElementById(mod.div.id+'svg')\n svg.setAttribute('viewBox',\"0 0 \"+(w-1)+\" \"+(h-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 // line loop\n //\n var ix = 0\n var iy = h-1\n var dx = 1\n var dy = 0\n var x = xmin+(xmax-xmin)*ix/(w-1)\n var y = ymin+(ymax-ymin)*iy/(h-1)\n var z = mod.map[(h-1-iy)*w+ix]\n var dz = 0.1*h*(zmax-z)/(ymax-ymin)\n while (1) {\n var ixp = ix\n var iyp = iy\n var dzp = dz\n ix += dx\n iy += dy\n if (iy <= 0)\n break;\n var x = xmin+(xmax-xmin)*ix/(w-1)\n var y = ymin+(ymax-ymin)*iy/(h-1)\n var z = mod.map[iy*w+ix]\n var dz = 0.1*h*(zmax-z)/(zmax-zmin)\n var line = document.createElementNS('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+dzp)\n line.setAttribute('x2',ix)\n line.setAttribute('y2',iy+dz)\n g.appendChild(line)\n if (ix == (mod.width-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 (ix == 0) {\n if (dx == -1) {\n dx = 0\n dy = -10\n }\n else {\n dx = 1\n dy = 0\n }\n }\n }\n mod.label.nodeValue = 'calculate'\n mod.labelspan.style.fontWeight = 'normal'\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":"114.0870285990817","left":"987.3074815152157","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.09986325972778665\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"map\\\"}\"}"]}
\ No newline at end of file
\ 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