diff --git a/programs/formats/gerber/plot png b/programs/formats/gerber/plot png index f7ecc07ea3b6f423327792123851914d3fd7c716..24a7b3f52e575659f8bac25be795d6202488f832 100644 --- a/programs/formats/gerber/plot png +++ b/programs/formats/gerber/plot png @@ -1 +1 @@ -{"modules":{"0.07944144280928633":{"definition":"//\n// edge detect\n// green = interior, blue = exterior, red = boundary\n// assumes input is thresholded\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2015,6\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the fab modules \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 = 'edge detect'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt){\n mod.input = evt.detail\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n ctx.putImageData(mod.input,0,0)\n edge_detect()}}}\n//\n// outputs\n//\nvar outputs = {\n image:{type:'RGBA',\n event:function(){\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n mods.output(mod,'image',img)}}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // on-screen drawing 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 // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\n //\n // view 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('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 win.document.body.appendChild(document.createTextNode('green:interior, blue:exterior, red:boundary'))\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// edge detect\n//\nfunction edge_detect() {\n var blob = new Blob(['('+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.buffer)\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.canvas.height*.5*(1-h/w)\n var wd = mod.canvas.width\n var hd = mod.canvas.width*h/w\n }\n else {\n var x0 = mod.canvas.width*.5*(1-w/h)\n var y0 = 0\n var wd = mod.canvas.height*w/h\n var hd = mod.canvas.height\n }\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n ctx.drawImage(mod.img,x0,y0,wd,hd)\n webworker.terminate()\n outputs.image.event()\n })\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n webworker.postMessage({worker:worker.toString(),\n height:mod.input.height,width:mod.input.width,\n buffer:mod.input.data.buffer},\n [mod.input.data.buffer])\n }\nfunction worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var input = new Uint8ClampedArray(evt.data.buffer)\n var output = new Uint8ClampedArray(h*w*4)\n var i00,i0m,i0p,im0,ip0,imm,imp,ipm,ipp,row,col\n //\n // find edges - interior\n //\n for (row = 1; row < (h-1); ++row) {\n for (col = 1; col < (w-1); ++col) {\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0p = (input[(h-1-row)*w*4+(col+1)*4+0] \n +input[(h-1-row)*w*4+(col+1)*4+1] \n +input[(h-1-row)*w*4+(col+1)*4+2])\n ip0 = (input[(h-2-row)*w*4+col*4+0] \n +input[(h-2-row)*w*4+col*4+1] \n +input[(h-2-row)*w*4+col*4+2])\n ipp = (input[(h-2-row)*w*4+(col+1)*4+0] \n +input[(h-2-row)*w*4+(col+1)*4+1] \n +input[(h-2-row)*w*4+(col+1)*4+2])\n i0m = (input[(h-1-row)*w*4+(col-1)*4+0] \n +input[(h-1-row)*w*4+(col-1)*4+1] \n +input[(h-1-row)*w*4+(col-1)*4+2])\n im0 = (input[(h-row)*w*4+col*4+0] \n +input[(h-row)*w*4+col*4+1] \n +input[(h-row)*w*4+col*4+2])\n imm = (input[(h-row)*w*4+(col-1)*4+0] \n +input[(h-row)*w*4+(col-1)*4+1] \n +input[(h-row)*w*4+(col-1)*4+2])\n imp = (input[(h-row)*w*4+(col+1)*4+0] \n +input[(h-row)*w*4+(col+1)*4+1] \n +input[(h-row)*w*4+(col+1)*4+2])\n ipm = (input[(h-2-row)*w*4+(col-1)*4+0] \n +input[(h-2-row)*w*4+(col-1)*4+1] \n +input[(h-2-row)*w*4+(col-1)*4+2])\n if ((i00 != i0p) || (i00 != ip0) || (i00 != ipp) \n || (i00 != i0m) || (i00 != im0) || (i00 != imm)\n || (i00 != imp) || (i00 != ipm)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n }\n }\n //\n // left and right edges\n //\n for (row = 1; row < (h-1); ++row) {\n col = w-1\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0m = (input[(h-1-row)*w*4+(col-1)*4+0] \n +input[(h-1-row)*w*4+(col-1)*4+1] \n +input[(h-1-row)*w*4+(col-1)*4+2])\n imm = (input[(h-row)*w*4+(col-1)*4+0] \n +input[(h-row)*w*4+(col-1)*4+1] \n +input[(h-row)*w*4+(col-1)*4+2])\n ipm = (input[(h-2-row)*w*4+(col-1)*4+0] \n +input[(h-2-row)*w*4+(col-1)*4+1] \n +input[(h-2-row)*w*4+(col-1)*4+2])\n im0 = (input[(h-row)*w*4+col*4+0] \n +input[(h-row)*w*4+col*4+1] \n +input[(h-row)*w*4+col*4+2])\n ip0 = (input[(h-2-row)*w*4+col*4+0] \n +input[(h-2-row)*w*4+col*4+1] \n +input[(h-2-row)*w*4+col*4+2])\n if ((i00 != i0m) || (i00 != ip0) || (i00 != ipm) \n || (i00 != im0) || (i00 != imm)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n col = 0\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0p = (input[(h-1-row)*w*4+(col+1)*4+0] \n +input[(h-1-row)*w*4+(col+1)*4+1] \n +input[(h-1-row)*w*4+(col+1)*4+2])\n imp = (input[(h-row)*w*4+(col+1)*4+0] \n +input[(h-row)*w*4+(col+1)*4+1] \n +input[(h-row)*w*4+(col+1)*4+2])\n ipp = (input[(h-2-row)*w*4+(col+1)*4+0] \n +input[(h-2-row)*w*4+(col+1)*4+1] \n +input[(h-2-row)*w*4+(col+1)*4+2])\n im0 = (input[(h-row)*w*4+col*4+0] \n +input[(h-row)*w*4+col*4+1] \n +input[(h-row)*w*4+col*4+2])\n ip0 = (input[(h-2-row)*w*4+col*4+0] \n +input[(h-2-row)*w*4+col*4+1] \n +input[(h-2-row)*w*4+col*4+2])\n if ((i00 != i0p) || (i00 != ip0) || (i00 != ipp) \n || (i00 != im0) || (i00 != imp)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n }\n //\n // top and bottom edges\n //\n for (col = 1; col < (w-1); ++col) {\n row = h-1\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0m = (input[(h-1-row)*w*4+(col-1)*4+0] \n +input[(h-1-row)*w*4+(col-1)*4+1] \n +input[(h-1-row)*w*4+(col-1)*4+2])\n i0p = (input[(h-1-row)*w*4+(col+1)*4+0] \n +input[(h-1-row)*w*4+(col+1)*4+1] \n +input[(h-1-row)*w*4+(col+1)*4+2])\n imm = (input[(h-row)*w*4+(col-1)*4+0] \n +input[(h-row)*w*4+(col-1)*4+1] \n +input[(h-row)*w*4+(col-1)*4+2])\n im0 = (input[(h-row)*w*4+col*4+0] \n +input[(h-row)*w*4+col*4+1] \n +input[(h-row)*w*4+col*4+2])\n imp = (input[(h-row)*w*4+(col+1)*4+0] \n +input[(h-row)*w*4+(col+1)*4+1] \n +input[(h-row)*w*4+(col+1)*4+2])\n if ((i00 != i0m) || (i00 != i0p) || (i00 != imm) \n || (i00 != im0) || (i00 != imp)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n row = 0\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0m = (input[(h-1-row)*w*4+(col-1)*4+0] \n +input[(h-1-row)*w*4+(col-1)*4+1] \n +input[(h-1-row)*w*4+(col-1)*4+2])\n i0p = (input[(h-1-row)*w*4+(col+1)*4+0] \n +input[(h-1-row)*w*4+(col+1)*4+1] \n +input[(h-1-row)*w*4+(col+1)*4+2])\n ipm = (input[(h-2-row)*w*4+(col-1)*4+0] \n +input[(h-2-row)*w*4+(col-1)*4+1] \n +input[(h-2-row)*w*4+(col-1)*4+2])\n ip0 = (input[(h-2-row)*w*4+col*4+0] \n +input[(h-2-row)*w*4+col*4+1] \n +input[(h-2-row)*w*4+col*4+2])\n ipp = (input[(h-2-row)*w*4+(col+1)*4+0] \n +input[(h-2-row)*w*4+(col+1)*4+1] \n +input[(h-2-row)*w*4+(col+1)*4+2])\n if ((i00 != i0m) || (i00 != i0p) || (i00 != ipm) \n || (i00 != ip0) || (i00 != ipp)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n }\n //\n // corners\n //\n row = 0\n col = 0\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0p = (input[(h-1-row)*w*4+(col+1)*4+0] \n +input[(h-1-row)*w*4+(col+1)*4+1] \n +input[(h-1-row)*w*4+(col+1)*4+2])\n ip0 = (input[(h-2-row)*w*4+col*4+0] \n +input[(h-2-row)*w*4+col*4+1] \n +input[(h-2-row)*w*4+col*4+2])\n ipp = (input[(h-2-row)*w*4+(col+1)*4+0] \n +input[(h-2-row)*w*4+(col+1)*4+1] \n +input[(h-2-row)*w*4+(col+1)*4+2])\n if ((i00 != i0p) || (i00 != ip0) || (i00 != ipp)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n row = 0\n col = w-1\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0m = (input[(h-1-row)*w*4+(col-1)*4+0] \n +input[(h-1-row)*w*4+(col-1)*4+1] \n +input[(h-1-row)*w*4+(col-1)*4+2])\n ip0 = (input[(h-2-row)*w*4+col*4+0] \n +input[(h-2-row)*w*4+col*4+1] \n +input[(h-2-row)*w*4+col*4+2])\n ipm = (input[(h-2-row)*w*4+(col-1)*4+0] \n +input[(h-2-row)*w*4+(col-1)*4+1] \n +input[(h-2-row)*w*4+(col-1)*4+2])\n if ((i00 != i0m) || (i00 != ip0) || (i00 != ipm)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n row = h-1\n col = 0\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0p = (input[(h-1-row)*w*4+(col+1)*4+0] \n +input[(h-1-row)*w*4+(col+1)*4+1] \n +input[(h-1-row)*w*4+(col+1)*4+2])\n im0 = (input[(h-row)*w*4+col*4+0] \n +input[(h-row)*w*4+col*4+1] \n +input[(h-row)*w*4+col*4+2])\n imp = (input[(h-row)*w*4+(col+1)*4+0] \n +input[(h-row)*w*4+(col+1)*4+1] \n +input[(h-row)*w*4+(col+1)*4+2])\n if ((i00 != i0p) || (i00 != im0) || (i00 != imp)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n row = h-1\n col = w-1\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0m = (input[(h-1-row)*w*4+(col-1)*4+0] \n +input[(h-1-row)*w*4+(col-1)*4+1] \n +input[(h-1-row)*w*4+(col-1)*4+2])\n im0 = (input[(h-row)*w*4+col*4+0] \n +input[(h-row)*w*4+col*4+1] \n +input[(h-row)*w*4+col*4+2])\n imm = (input[(h-row)*w*4+(col-1)*4+0] \n +input[(h-row)*w*4+(col-1)*4+1] \n +input[(h-row)*w*4+(col-1)*4+2])\n if ((i00 != i0m) || (i00 != im0) || (i00 != imm)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n self.postMessage({buffer:output.buffer},[output.buffer])\n })\n }\n//\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"188.3025579837396","left":"1686.6484625538612","filename":"undefined","inputs":{},"outputs":{}},"0.8903773266711255":{"definition":"//\n// orient edges\n// input is green:interior, blue:exterior, red:boundary\n// output is red 128:north,64:south, green 128:east,64:west, blue 128:start,64:stop\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2016\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the fab modules \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 = 'orient edges'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt){\n mod.input = evt.detail\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n ctx.putImageData(mod.input,0,0)\n var ctx = mod.display.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n orient_edges()\n }}}\n//\n// outputs\n//\nvar outputs = {\n image:{type:'RGBA',\n event:function(){\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n mods.output(mod,'image',img)}}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // on-screen drawing 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 // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\n //\n // off-screen display canvas\n //\n var canvas = document.createElement('canvas')\n mod.display = canvas\n //\n // view 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('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 win.document.body.appendChild(document.createTextNode('red:north, dark red:south'))\n win.document.body.appendChild(document.createElement('br'))\n win.document.body.appendChild(document.createTextNode('green:east, dark green:west'))\n win.document.body.appendChild(document.createElement('br'))\n win.document.body.appendChild(document.createTextNode('blue:start, dark blue:stop'))\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.display,0,0)\n })\n div.appendChild(btn)\n }\n//\n// local functions\n//\n// orient edges\n//\nfunction orient_edges() {\n var blob = new Blob(['('+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.buffer)\n var imgdata = new ImageData(buf,w,h)\n var ctx = mod.img.getContext(\"2d\")\n ctx.putImageData(imgdata,0,0)\n var disp = new Uint8ClampedArray(evt.data.display)\n var dispdata = new ImageData(disp,w,h)\n var ctx = mod.display.getContext(\"2d\")\n ctx.putImageData(dispdata,0,0)\n if (w > h) {\n var x0 = 0\n var y0 = mod.canvas.height*.5*(1-h/w)\n var wd = mod.canvas.width\n var hd = mod.canvas.width*h/w\n }\n else {\n var x0 = mod.canvas.width*.5*(1-w/h)\n var y0 = 0\n var wd = mod.canvas.height*w/h\n var hd = mod.canvas.height\n }\n var w = mod.canvas.width\n var h = mod.canvas.height\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,w,h)\n ctx.drawImage(mod.display,x0,y0,wd,hd)\n webworker.terminate()\n outputs.image.event()\n })\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n webworker.postMessage({\n height:mod.input.height,width:mod.input.width,\n buffer:mod.input.data.buffer},\n [mod.input.data.buffer])\n }\nfunction worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var input = new Uint8ClampedArray(evt.data.buffer)\n var output = new Uint8ClampedArray(h*w*4)\n var row,col\n var boundary = 0\n var interior = 1\n var exterior = 2\n var alpha = 3\n var northsouth = 0\n var north = 128\n var south = 64\n var eastwest = 1\n var east = 128\n var west = 64\n var startstop = 2\n var start = 128\n var stop = 64\n //\n // orient body states\n //\n for (row = 1; row < (h-1); ++row) {\n for (col = 1; col < (w-1); ++col) {\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n if (input[(h-1-(row))*w*4+(col)*4+boundary] != 0) {\n if ((input[(h-1-(row+1))*w*4+(col)*4+boundary] != 0)\n && ((input[(h-1-(row))*w*4+(col+1)*4+interior] != 0)\n || (input[(h-1-(row+1))*w*4+(col+1)*4+interior] != 0)))\n output[(h-1-row)*w*4+col*4+northsouth] |= north\n if ((input[(h-1-(row-1))*w*4+(col)*4+boundary] != 0)\n && ((input[(h-1-(row))*w*4+(col-1)*4+interior] != 0)\n || (input[(h-1-(row-1))*w*4+(col-1)*4+interior] != 0)))\n output[(h-1-row)*w*4+col*4+northsouth] |= south\n if ((input[(h-1-(row))*w*4+(col+1)*4+boundary] != 0)\n && ((input[(h-1-(row-1))*w*4+(col)*4+interior] != 0)\n || (input[(h-1-(row-1))*w*4+(col+1)*4+interior] != 0)))\n output[(h-1-row)*w*4+col*4+eastwest] |= east\n if ((input[(h-1-(row))*w*4+(col-1)*4+boundary] != 0)\n && ((input[(h-1-(row+1))*w*4+(col)*4+interior] != 0)\n || (input[(h-1-(row+1))*w*4+(col-1)*4+interior] != 0)))\n output[(h-1-row)*w*4+col*4+eastwest] |= west\n }\n }\n }\n //\n // orient edge states\n //\n for (col = 1; col < (w-1); ++col) {\n row = 0\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n if (input[(h-1-(row))*w*4+(col)*4+boundary] != 0) {\n if ((input[(h-1-(row+1))*w*4+(col)*4+boundary] != 0)\n && (input[(h-1-(row))*w*4+(col+1)*4+interior] != 0)) {\n output[(h-1-row)*w*4+col*4+northsouth] |= north\n output[(h-1-row)*w*4+col*4+startstop] |= start\n }\n if (input[(h-1-(row))*w*4+(col-1)*4+interior] != 0)\n output[(h-1-row)*w*4+col*4+startstop] |= stop\n }\n row = h-1\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n if (input[(h-1-(row))*w*4+(col)*4+boundary] != 0) {\n if (input[(h-1-(row))*w*4+(col+1)*4+interior] != 0)\n output[(h-1-row)*w*4+col*4+startstop] |= stop\n if ((input[(h-1-(row-1))*w*4+(col)*4+boundary] != 0)\n && (input[(h-1-(row))*w*4+(col-1)*4+interior] != 0)) {\n output[(h-1-row)*w*4+col*4+northsouth] |= south\n output[(h-1-row)*w*4+col*4+startstop] |= start\n }\n }\n }\n for (row = 1; row < (h-1); ++row) {\n col = 0\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n if (input[(h-1-(row))*w*4+(col)*4+boundary] != 0) {\n if ((input[(h-1-(row))*w*4+(col+1)*4+boundary] != 0)\n && (input[(h-1-(row-1))*w*4+(col)*4+interior] != 0)) {\n output[(h-1-row)*w*4+col*4+eastwest] |= east\n output[(h-1-row)*w*4+col*4+startstop] |= start\n }\n if (input[(h-1-(row+1))*w*4+(col)*4+interior] != 0)\n output[(h-1-row)*w*4+col*4+startstop] |= stop\n }\n col = w-1\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n if (input[(h-1-(row))*w*4+(col)*4+boundary] != 0) {\n if (input[(h-1-(row-1))*w*4+(col)*4+interior] != 0)\n output[(h-1-row)*w*4+col*4+startstop] |= stop\n if ((input[(h-1-(row))*w*4+(col-1)*4+boundary] != 0)\n && (input[(h-1-(row+1))*w*4+(col)*4+interior] != 0)) {\n output[(h-1-row)*w*4+col*4+eastwest] |= west\n output[(h-1-row)*w*4+col*4+startstop] |= start\n }\n }\n }\n //\n // orient corner states (todo)\n //\n row = 0\n col = 0\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n row = h-1\n col = 0\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n row = 0\n col = w-1\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n row = h-1\n col = w-1\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n //\n // invert background for display\n //\n var display = new Uint8ClampedArray(h*w*4)\n var r,g,b,i\n for (row = 0; row < h; ++row) {\n for (col = 0; col < w; ++col) {\n r = output[(h-1-row)*w*4+col*4+0]\n g = output[(h-1-row)*w*4+col*4+1]\n b = output[(h-1-row)*w*4+col*4+2]\n i = r+g+b\n if (i != 0) { \n display[(h-1-row)*w*4+col*4+0] = output[(h-1-row)*w*4+col*4+0]\n display[(h-1-row)*w*4+col*4+1] = output[(h-1-row)*w*4+col*4+1]\n display[(h-1-row)*w*4+col*4+2] = output[(h-1-row)*w*4+col*4+2]\n display[(h-1-row)*w*4+col*4+3] = output[(h-1-row)*w*4+col*4+3]\n }\n else {\n display[(h-1-row)*w*4+col*4+0] = 255\n display[(h-1-row)*w*4+col*4+1] = 255\n display[(h-1-row)*w*4+col*4+2] = 255\n display[(h-1-row)*w*4+col*4+3] = 255\n }\n }\n }\n //\n // return output\n //\n self.postMessage({buffer:output.buffer,display:display.buffer},[output.buffer,display.buffer])\n })\n }\n//\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"618.3025579837396","left":"1667.6484625538612","filename":"undefined","inputs":{},"outputs":{}},"0.08127540142793499":{"definition":"//\n// read png\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2015,6\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the fab modules \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 png'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\n }\n//\n// outputs\n//\nvar outputs = {\n image:{type:'RGBA',\n event:function(){\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n mods.output(mod,'image',img)}},\n imageInfo:{type:'object',\n event:function(){\n var obj = {}\n obj.name = mod.name.nodeValue\n obj.dpi = parseFloat(mod.dpitext.value)\n obj.width = mod.img.width\n obj.height = mod.img.height\n mods.output(mod,'imageInfo',obj)}}}\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 png_read_handler()\n })\n div.appendChild(file)\n mod.file = file\n //\n // on-screen drawing 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 // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\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 png 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 // view 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('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 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 div.appendChild(document.createTextNode(' '))\n //\n // invert 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('invert'))\n btn.addEventListener('click',function(){\n invert_image()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // info div\n //\n var info = document.createElement('div')\n info.setAttribute('id',div.id+'info')\n info.appendChild(document.createTextNode('dpi: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('input',function(){\n mod.dpi = parseFloat(mod.dpitext.value)\n mod.mmtext.nodeValue = (25.4*mod.img.width/mod.dpi).toFixed(3)\n +' x '+(25.4*mod.img.height/mod.dpi).toFixed(3)+' mm'\n mod.intext.nodeValue = (mod.img.width/mod.dpi).toFixed(3)\n +' x '+(mod.img.height/mod.dpi).toFixed(3)+' in'\n outputs.imageInfo.event()\n })\n info.appendChild(input)\n mod.dpitext = input\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('px: ')\n info.appendChild(text)\n mod.pxtext = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('mm: ')\n info.appendChild(text)\n mod.mmtext = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('in: ')\n info.appendChild(text)\n mod.intext = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('')\n info.appendChild(text)\n mod.name = text\n div.appendChild(info)\n }\n//\n// local functions\n//\n// read handler\n//\nfunction png_read_handler(event) {\n var file_reader = new FileReader()\n file_reader.onload = png_binary_handler\n input_file = mod.file.files[0]\n file_name = input_file.name\n mod.name.nodeValue = file_name\n file_reader.readAsArrayBuffer(input_file)\n }\n//\n// binary load handler\n//\nfunction png_binary_handler(event) {\n //\n // get DPI\n //\n // 8 header\n // 4 len, 4 type, data, 4 crc\n // pHYs 4 ppx, 4 ppy, 1 unit: 0 ?, 1 meter\n // IEND\n //\n var units = ppx = ppy = 0\n var buf = event.target.result\n var view = new DataView(buf)\n var ptr = 8\n if (!((view.getUint8(1) == 80) && (view.getUint8(2) == 78) && (view.getUint8(3) == 71))) {\n set_prompt(\"error: PNG header not found\")\n return\n }\n while (1) {\n var length = view.getUint32(ptr)\n ptr += 4\n var type = String.fromCharCode(\n view.getUint8(ptr),view.getUint8(ptr+1),\n view.getUint8(ptr+2),view.getUint8(ptr+3))\n ptr += 4\n if (type == \"pHYs\") {\n ppx = view.getUint32(ptr)\n ppy = view.getUint32(ptr + 4)\n units = view.getUint8(ptr + 8)\n }\n if (type == \"IEND\")\n break\n ptr += length + 4\n }\n if (units == 0) {\n set_prompt(\"no PNG units not found, assuming 72 DPI\")\n ppx = 72*1000/25.4\n }\n dpi = ppx*25.4/1000\n //\n // read as URL for display\n //\n var file_reader = new FileReader()\n file_reader.onload = png_URL_handler\n file_reader.readAsDataURL(input_file)\n }\n//\n// URL load handler\n//\nfunction png_URL_handler(event) {\n var img = new Image()\n img.setAttribute(\"src\",event.target.result)\n img.onload = function() {\n if (img.width > img.height) {\n var x0 = 0\n var y0 = mod.canvas.height*.5*(1-img.height/img.width)\n var w = mod.canvas.width\n var h = mod.canvas.width*img.height/img.width\n }\n else {\n var x0 = mod.canvas.width*.5*(1-img.width/img.height)\n var y0 = 0\n var w = mod.canvas.height*img.width/img.height\n var h = mod.canvas.height\n }\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n ctx.drawImage(img,x0,y0,w,h)\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = img.width\n ctx.canvas.height = img.height \n ctx.drawImage(img,0,0)\n mod.dpitext.value = dpi.toFixed(3)\n mod.pxtext.nodeValue = img.width+' x '+img.height+' px'\n mod.mmtext.nodeValue = (25.4*img.width/dpi).toFixed(3)\n +' x '+(25.4*img.height/dpi).toFixed(3)+' mm'\n mod.intext.nodeValue = (img.width/dpi).toFixed(3)\n +' x '+(img.height/dpi).toFixed(3)+' in'\n outputs.image.event()\n outputs.imageInfo.event()\n }\n }\n//\n// invert image\n//\nfunction invert_image() {\n var blob = new Blob(['('+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.buffer)\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.canvas.height*.5*(1-h/w)\n var wd = mod.canvas.width\n var hd = mod.canvas.width*h/w\n }\n else {\n var x0 = mod.canvas.width*.5*(1-w/h)\n var y0 = 0\n var wd = mod.canvas.height*w/h\n var hd = mod.canvas.height\n }\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.drawImage(mod.img,x0,y0,wd,hd)\n webworker.terminate()\n outputs.image.event()\n })\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n var h = mod.img.height\n var w = mod.img.width\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,w,h)\n webworker.postMessage({\n height:img.height,width:img.width,buffer:img.data.buffer},\n [img.data.buffer])\n }\nfunction worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var buf = new Uint8ClampedArray(evt.data.buffer)\n for (var row = 0; row < h; ++row) {\n for (var col = 0; col < w; ++col) {\n buf[(h-1-row)*w*4+col*4+0] \n = 255-buf[(h-1-row)*w*4+col*4+0] \n buf[(h-1-row)*w*4+col*4+1] \n = 255-buf[(h-1-row)*w*4+col*4+1] \n buf[(h-1-row)*w*4+col*4+2] \n = 255-buf[(h-1-row)*w*4+col*4+2] \n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n }\n self.postMessage({buffer:buf.buffer},[buf.buffer])\n })\n }\n//\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"227.3025579837396","left":"162.64846255386124","filename":"undefined","inputs":{},"outputs":{}},"0.6488303557466412":{"definition":"//\n// image threshold\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2015,6\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the fab modules \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 = 'image threshold'\n//\n// initialization\n//\nvar init = function() {\n mod.threshold.value = 0.5\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt){\n mod.input = evt.detail\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n ctx.putImageData(mod.input,0,0)\n threshold_image()}}}\n//\n// outputs\n//\nvar outputs = {\n image:{type:'RGBA',\n event:function(){\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n mods.output(mod,'image',img)}}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // on-screen drawing 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 // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\n //\n // threshold value\n //\n div.appendChild(document.createTextNode('threshold (0-1): '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n threshold_image()\n })\n div.appendChild(input)\n mod.threshold = input\n div.appendChild(document.createElement('br'))\n //\n // view 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('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 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// threshold image\n//\nfunction threshold_image() {\n var blob = new Blob(['('+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.buffer)\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.canvas.height*.5*(1-h/w)\n var wd = mod.canvas.width\n var hd = mod.canvas.width*h/w\n }\n else {\n var x0 = mod.canvas.width*.5*(1-w/h)\n var y0 = 0\n var wd = mod.canvas.height*w/h\n var hd = mod.canvas.height\n }\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n ctx.drawImage(mod.img,x0,y0,wd,hd)\n webworker.terminate()\n outputs.image.event()\n })\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n var t = parseFloat(mod.threshold.value)\n var ctx = mod.img.getContext(\"2d\")\n ctx.putImageData(mod.input,0,0)\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n webworker.postMessage({\n height:mod.input.height,width:mod.input.width,threshold:t,\n buffer:img.data.buffer},\n [img.data.buffer])\n }\nfunction worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var t = evt.data.threshold\n var buf = new Uint8ClampedArray(evt.data.buffer)\n var r,g,b,a,i\n for (var row = 0; row < h; ++row) {\n for (var col = 0; col < w; ++col) {\n r = buf[(h-1-row)*w*4+col*4+0] \n g = buf[(h-1-row)*w*4+col*4+1] \n b = buf[(h-1-row)*w*4+col*4+2] \n a = buf[(h-1-row)*w*4+col*4+3] \n i = (r+g+b)/(3*255)\n if (a == 0)\n val = 255\n else if (i > t)\n var val = 255\n else\n var val = 0\n buf[(h-1-row)*w*4+col*4+0] = val\n buf[(h-1-row)*w*4+col*4+1] = val\n buf[(h-1-row)*w*4+col*4+2] = val\n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n }\n self.postMessage({buffer:buf.buffer},[buf.buffer])\n })\n }\n//\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"99.3025579837396","left":"1205.6484625538612","filename":"undefined","inputs":{},"outputs":{}},"0.749132408760488":{"definition":"//\n// vectorize\n// input is red 128:north,64:south, green 128:east,64:west, blue 128:start,64:stop\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2016\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the fab modules \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 = 'vectorize'\n//\n// initialization\n//\nvar init = function() {\n mod.error.value = 1\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt){\n mod.input = evt.detail\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n ctx.putImageData(mod.input,0,0)\n vectorize()\n }}}\n//\n// outputs\n//\nvar outputs = {\n path:{type:'array',\n event:function(){\n mods.output(mod,'path',mod.path)\n }}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\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 // error value\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 // sort\n //\n div.appendChild(document.createTextNode('sort distance: '))\n var input = document.createElement('input')\n input.type = 'checkbox'\n input.id = mod.div.id+'sort'\n input.checked = true\n div.appendChild(input)\n mod.sort = input\n div.appendChild(document.createElement('br'))\n //\n // view 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('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 }\n//\n// local functions\n//\n// vectorize\n//\nfunction vectorize() {\n //\n // draw path\n //\n function draw_path(path) {\n window.URL.revokeObjectURL(url)\n var svg = document.getElementById(mod.div.id+'svg')\n svg.setAttribute('viewBox',\"0 0 \"+(mod.img.width-1)+\" \"+(mod.img.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 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 in path) {\n if (path[segment].length > 1) {\n if (xend != null) {\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 = xend\n var y1 = yend\n var x2 = path[segment][0][0]\n var y2 = h-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 // 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 svg.appendChild(g)\n }\n //\n // set up worker\n //\n var blob = new Blob(['('+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 webworker.terminate()\n mod.path = evt.data.path\n draw_path(mod.path)\n outputs.path.event()\n })\n //\n // call worker\n //\n webworker.postMessage({\n height:mod.input.height,width:mod.input.width,sort:mod.sort.checked,\n error:parseFloat(mod.error.value),\n buffer:mod.input.data.buffer})\n }\n//\n// vectorize worker\n//\nfunction worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var sort = evt.data.sort\n var input = new Uint8ClampedArray(evt.data.buffer)\n var northsouth = 0\n var north = 128\n var south = 64\n var eastwest = 1\n var east = 128\n var west = 64\n var startstop = 2\n var start = 128\n var stop = 64\n var path = []\n //\n // edge follower\n //\n function follow_edges(row,col) {\n if ((input[(h-1-row)*w*4+col*4+northsouth] != 0)\n || (input[(h-1-row)*w*4+col*4+eastwest] != 0)) {\n path[path.length] = [[col,row]]\n while (1) {\n if (input[(h-1-row)*w*4+col*4+northsouth] & north) {\n input[(h-1-row)*w*4+col*4+northsouth] =\n input[(h-1-row)*w*4+col*4+northsouth] & ~north\n row += 1\n path[path.length-1][path[path.length-1].length] = [col,row]\n }\n else if (input[(h-1-row)*w*4+col*4+northsouth] & south) {\n input[(h-1-row)*w*4+col*4+northsouth] =\n input[(h-1-row)*w*4+col*4+northsouth] & ~south\n row -= 1\n path[path.length-1][path[path.length-1].length] = [col,row]\n }\n else if (input[(h-1-row)*w*4+col*4+eastwest] & east) {\n input[(h-1-row)*w*4+col*4+eastwest] =\n input[(h-1-row)*w*4+col*4+eastwest] & ~east\n col += 1\n path[path.length-1][path[path.length-1].length] = [col,row]\n }\n else if (input[(h-1-row)*w*4+col*4+eastwest] & west) {\n input[(h-1-row)*w*4+col*4+eastwest] =\n input[(h-1-row)*w*4+col*4+eastwest] & ~west\n col -= 1\n path[path.length-1][path[path.length-1].length] = [col,row]\n }\n else\n break\n }\n }\n }\n //\n // follow boundary starts\n //\n for (var row = 1; row < (h-1); ++row) {\n col = 0\n follow_edges(row,col)\n col = w-1\n follow_edges(row,col)\n }\n for (var col = 1; col < (w-1); ++col) {\n row = 0\n follow_edges(row,col)\n row = h-1 \n follow_edges(row,col)\n }\n //\n // follow interior paths\n //\n for (var row = 1; row < (h-1); ++row) {\n for (var col = 1; col < (w-1); ++col) {\n follow_edges(row,col)\n }\n }\n //\n // vectorize path\n //\n var error = evt.data.error\n var vecpath = []\n for (var seg = 0; seg < path.length; ++seg) {\n var x0 = path[seg][0][0]\n var y0 = path[seg][0][1]\n vecpath[vecpath.length] = [[x0,y0]]\n var xsum = x0\n var ysum = y0\n var sum = 1\n for (var pt = 1; pt < path[seg].length; ++pt) {\n var xold = x\n var yold = y\n var x = path[seg][pt][0]\n var y = path[seg][pt][1]\n if (sum == 1) {\n xsum += x\n ysum += y\n sum += 1\n }\n else {\n var xmean = xsum/sum\n var ymean = ysum/sum\n var dx = xmean-x0\n var dy = ymean-y0\n var d = Math.sqrt(dx*dx+dy*dy)\n var nx = dy/d\n var ny = -dx/d\n var l = Math.abs(nx*(x-x0)+ny*(y-y0))\n if (l < error) {\n xsum += x\n ysum += y\n sum += 1\n }\n else {\n vecpath[vecpath.length-1][vecpath[vecpath.length-1].length] = [xold,yold]\n x0 = xold\n y0 = yold\n xsum = xold\n ysum = yold\n sum = 1\n }\n }\n if (pt == (path[seg].length-1)) {\n vecpath[vecpath.length-1][vecpath[vecpath.length-1].length] = [x,y]\n }\n }\n }\n //\n // sort path\n //\n if ((vecpath.length > 0) && (sort == true)) {\n var dmin = w*w+h*h\n segmin = null\n for (var seg = 0; seg < vecpath.length; ++seg) {\n var x = vecpath[seg][0][0]\n var y = vecpath[seg][0][0]\n var d = x*x+y*y\n if (d < dmin) {\n dmin = d\n segmin = seg\n }\n }\n if (segmin != null) {\n var sortpath = [vecpath[segmin]]\n vecpath.splice(segmin,1)\n }\n while (vecpath.length > 0) {\n var dmin = w*w+h*h\n var x0 = sortpath[sortpath.length-1][sortpath[sortpath.length-1].length-1][0]\n var y0 = sortpath[sortpath.length-1][sortpath[sortpath.length-1].length-1][1]\n segmin = null\n for (var seg = 0; seg < vecpath.length; ++seg) {\n var x = vecpath[seg][0][0]\n var y = vecpath[seg][0][1]\n var d = (x-x0)*(x-x0)+(y-y0)*(y-y0)\n if (d < dmin) {\n dmin = d\n segmin = seg\n }\n }\n if (segmin != null) {\n sortpath[sortpath.length] = vecpath[segmin]\n vecpath.splice(segmin,1)\n }\n }\n }\n else if ((vecpath.length > 0) && (sort == false))\n sortpath = vecpath\n else\n sortpath = []\n //\n // return path\n //\n self.postMessage({path:sortpath})\n })\n }\n//\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"532.3025579837396","left":"1262.6484625538612","filename":"undefined","inputs":{},"outputs":{}},"0.9085301680722191":{"definition":"//\n// path to Gerber\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2021\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 = 'path to Gerber'\n//\n// initialization\n//\nvar init = function() {\n mod.fill.checked = true\n }\n//\n// inputs\n//\nvar inputs = {\n imageInfo:{type:'',\n event:function(evt){\n mod.imageInfo = evt.detail\n }},\n path:{type:'',\n event:function(evt){\n mod.path = evt.detail\n }}}\n//\n// outputs\n//\nvar outputs = {\n Gerber:{type:'',\n event:function(evt){\n mods.output(mod,'Gerber',evt)\n }}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('plot'))\n btn.addEventListener('click',function(){\n plot()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('format:'))\n div.appendChild(document.createElement('br'))\n var formats = document.createElement('div');\n formats.style.textAlign = 'left'\n var input = document.createElement('input')\n input.type = 'radio'\n input.name = mod.div.id+'format'\n input.id = mod.div.id+'fill'\n formats.appendChild(input)\n mod.fill = input\n formats.appendChild(document.createTextNode('fill'))\n formats.appendChild(document.createElement('br'))\n var input = document.createElement('input')\n input.type = 'radio'\n input.name = mod.div.id+'format'\n input.id = mod.div.id+'outline'\n input.disabled = true\n formats.appendChild(input)\n mod.outline = input\n formats.appendChild(document.createTextNode('outline'))\n formats.appendChild(document.createElement('br'))\n var input = document.createElement('input')\n input.type = 'radio'\n input.name = mod.div.id+'format'\n input.id = mod.div.id+'outline'\n input.disabled = true\n formats.appendChild(input)\n mod.drill = input\n formats.appendChild(document.createTextNode('drill'))\n div.appendChild(formats)\n }\n//\n// local functions\n//\n// plot\n//\nfunction plot() {\n var imgwidth = mod.imageInfo.width/parseFloat(mod.imageInfo.dpi)\n var imgheight = mod.imageInfo.height/parseFloat(mod.imageInfo.dpi)\n str = ''\n str += \"%MOIN*%\\n\" // inch units\n str += \"%ASAXBY*%\\n\" // axes\n str += \"%IPPOS*%\\n\" // positive image\n str += \"%LPD*%\\n\" // dark layer\n str += \"%FSLAX33Y33*%\\n\" // format absolute 3.3\n for (var seg = 0; seg < mod.path.length; ++seg) {\n for (var pt = 0; pt < mod.path[seg].length; ++pt) {\n var x = imgwidth*mod.path[seg][pt][0]/(mod.imageInfo.width-1)\n var y = imgheight*(1-mod.path[seg][pt][1]/(mod.imageInfo.height-1))\n }\n var x = imgwidth*mod.path[seg][0][0]/(mod.imageInfo.width-1)\n var y = imgheight*(1-mod.path[seg][0][1]/(mod.imageInfo.height-1))\n console.log(parseFloat(x.toFixed(3)))\n }\n }\n/*\n%MOIN*%\n%ASAXBY*%\n%IPPOS*%\n%FSLAX33Y33*%\n%ADD11C,0.1*%\n%LPD*%\nG36*\nX1000Y1000D02*\nX2000Y2000D01*\nX2000Y1000D01*\nX1000Y1000D01*\nG37*\n%LPC*%\nG01*\nD11*\nX1000Y1000D02*\nX1000Y2000D01*\nX2000Y2000D01*\nX1500Y1000D01*\nM02*\n//\n// convert\n//\nfunction convert(path) {\n //\n // draw path\n //\n if (mod.fill.checked == true) {\n var polyline = document.createElementNS(svgNS,'polyline')\n polyline.setAttribute('stroke','none')\n polyline.setAttribute('fill','black')\n polyline.setAttribute('fill-rule','evenodd')\n polyline.setAttribute('points',points)\n g.appendChild(polyline)\n }\n else {\n var polyline = document.createElementNS(svgNS,'polyline')\n polyline.setAttribute('stroke','black')\n polyline.setAttribute('stroke-width','0.01')\n polyline.setAttribute('stroke-linecap','round')\n polyline.setAttribute('fill','none')\n polyline.setAttribute('points',points)\n g.appendChild(polyline)\n }\n }\n //\n // save file\n //\n var obj = {}\n obj.type = 'file'\n obj.name = mod.imageInfo.name+'.svg'\n var xml = new XMLSerializer().serializeToString(svg)\n obj.contents = xml\n outputs.SVG.event(obj)\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":"377","left":"692","filename":"modules/path/formats/gerber","inputs":{},"outputs":{}}},"links":["{\"source\":\"{\\\"id\\\":\\\"0.07944144280928633\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.8903773266711255\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.08127540142793499\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.6488303557466412\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.8903773266711255\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.749132408760488\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.6488303557466412\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.07944144280928633\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.08127540142793499\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"imageInfo\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.9085301680722191\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"imageInfo\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.749132408760488\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"path\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.9085301680722191\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"path\\\"}\"}"]} \ No newline at end of file +{"modules":{"0.07944144280928633":{"definition":"//\n// edge detect\n// green = interior, blue = exterior, red = boundary\n// assumes input is thresholded\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2015,6\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the fab modules \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 = 'edge detect'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt){\n mod.input = evt.detail\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n ctx.putImageData(mod.input,0,0)\n edge_detect()}}}\n//\n// outputs\n//\nvar outputs = {\n image:{type:'RGBA',\n event:function(){\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n mods.output(mod,'image',img)}}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // on-screen drawing 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 // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\n //\n // view 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('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 win.document.body.appendChild(document.createTextNode('green:interior, blue:exterior, red:boundary'))\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// edge detect\n//\nfunction edge_detect() {\n var blob = new Blob(['('+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.buffer)\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.canvas.height*.5*(1-h/w)\n var wd = mod.canvas.width\n var hd = mod.canvas.width*h/w\n }\n else {\n var x0 = mod.canvas.width*.5*(1-w/h)\n var y0 = 0\n var wd = mod.canvas.height*w/h\n var hd = mod.canvas.height\n }\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n ctx.drawImage(mod.img,x0,y0,wd,hd)\n webworker.terminate()\n outputs.image.event()\n })\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n webworker.postMessage({worker:worker.toString(),\n height:mod.input.height,width:mod.input.width,\n buffer:mod.input.data.buffer},\n [mod.input.data.buffer])\n }\nfunction worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var input = new Uint8ClampedArray(evt.data.buffer)\n var output = new Uint8ClampedArray(h*w*4)\n var i00,i0m,i0p,im0,ip0,imm,imp,ipm,ipp,row,col\n //\n // find edges - interior\n //\n for (row = 1; row < (h-1); ++row) {\n for (col = 1; col < (w-1); ++col) {\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0p = (input[(h-1-row)*w*4+(col+1)*4+0] \n +input[(h-1-row)*w*4+(col+1)*4+1] \n +input[(h-1-row)*w*4+(col+1)*4+2])\n ip0 = (input[(h-2-row)*w*4+col*4+0] \n +input[(h-2-row)*w*4+col*4+1] \n +input[(h-2-row)*w*4+col*4+2])\n ipp = (input[(h-2-row)*w*4+(col+1)*4+0] \n +input[(h-2-row)*w*4+(col+1)*4+1] \n +input[(h-2-row)*w*4+(col+1)*4+2])\n i0m = (input[(h-1-row)*w*4+(col-1)*4+0] \n +input[(h-1-row)*w*4+(col-1)*4+1] \n +input[(h-1-row)*w*4+(col-1)*4+2])\n im0 = (input[(h-row)*w*4+col*4+0] \n +input[(h-row)*w*4+col*4+1] \n +input[(h-row)*w*4+col*4+2])\n imm = (input[(h-row)*w*4+(col-1)*4+0] \n +input[(h-row)*w*4+(col-1)*4+1] \n +input[(h-row)*w*4+(col-1)*4+2])\n imp = (input[(h-row)*w*4+(col+1)*4+0] \n +input[(h-row)*w*4+(col+1)*4+1] \n +input[(h-row)*w*4+(col+1)*4+2])\n ipm = (input[(h-2-row)*w*4+(col-1)*4+0] \n +input[(h-2-row)*w*4+(col-1)*4+1] \n +input[(h-2-row)*w*4+(col-1)*4+2])\n if ((i00 != i0p) || (i00 != ip0) || (i00 != ipp) \n || (i00 != i0m) || (i00 != im0) || (i00 != imm)\n || (i00 != imp) || (i00 != ipm)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n }\n }\n //\n // left and right edges\n //\n for (row = 1; row < (h-1); ++row) {\n col = w-1\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0m = (input[(h-1-row)*w*4+(col-1)*4+0] \n +input[(h-1-row)*w*4+(col-1)*4+1] \n +input[(h-1-row)*w*4+(col-1)*4+2])\n imm = (input[(h-row)*w*4+(col-1)*4+0] \n +input[(h-row)*w*4+(col-1)*4+1] \n +input[(h-row)*w*4+(col-1)*4+2])\n ipm = (input[(h-2-row)*w*4+(col-1)*4+0] \n +input[(h-2-row)*w*4+(col-1)*4+1] \n +input[(h-2-row)*w*4+(col-1)*4+2])\n im0 = (input[(h-row)*w*4+col*4+0] \n +input[(h-row)*w*4+col*4+1] \n +input[(h-row)*w*4+col*4+2])\n ip0 = (input[(h-2-row)*w*4+col*4+0] \n +input[(h-2-row)*w*4+col*4+1] \n +input[(h-2-row)*w*4+col*4+2])\n if ((i00 != i0m) || (i00 != ip0) || (i00 != ipm) \n || (i00 != im0) || (i00 != imm)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n col = 0\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0p = (input[(h-1-row)*w*4+(col+1)*4+0] \n +input[(h-1-row)*w*4+(col+1)*4+1] \n +input[(h-1-row)*w*4+(col+1)*4+2])\n imp = (input[(h-row)*w*4+(col+1)*4+0] \n +input[(h-row)*w*4+(col+1)*4+1] \n +input[(h-row)*w*4+(col+1)*4+2])\n ipp = (input[(h-2-row)*w*4+(col+1)*4+0] \n +input[(h-2-row)*w*4+(col+1)*4+1] \n +input[(h-2-row)*w*4+(col+1)*4+2])\n im0 = (input[(h-row)*w*4+col*4+0] \n +input[(h-row)*w*4+col*4+1] \n +input[(h-row)*w*4+col*4+2])\n ip0 = (input[(h-2-row)*w*4+col*4+0] \n +input[(h-2-row)*w*4+col*4+1] \n +input[(h-2-row)*w*4+col*4+2])\n if ((i00 != i0p) || (i00 != ip0) || (i00 != ipp) \n || (i00 != im0) || (i00 != imp)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n }\n //\n // top and bottom edges\n //\n for (col = 1; col < (w-1); ++col) {\n row = h-1\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0m = (input[(h-1-row)*w*4+(col-1)*4+0] \n +input[(h-1-row)*w*4+(col-1)*4+1] \n +input[(h-1-row)*w*4+(col-1)*4+2])\n i0p = (input[(h-1-row)*w*4+(col+1)*4+0] \n +input[(h-1-row)*w*4+(col+1)*4+1] \n +input[(h-1-row)*w*4+(col+1)*4+2])\n imm = (input[(h-row)*w*4+(col-1)*4+0] \n +input[(h-row)*w*4+(col-1)*4+1] \n +input[(h-row)*w*4+(col-1)*4+2])\n im0 = (input[(h-row)*w*4+col*4+0] \n +input[(h-row)*w*4+col*4+1] \n +input[(h-row)*w*4+col*4+2])\n imp = (input[(h-row)*w*4+(col+1)*4+0] \n +input[(h-row)*w*4+(col+1)*4+1] \n +input[(h-row)*w*4+(col+1)*4+2])\n if ((i00 != i0m) || (i00 != i0p) || (i00 != imm) \n || (i00 != im0) || (i00 != imp)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n row = 0\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0m = (input[(h-1-row)*w*4+(col-1)*4+0] \n +input[(h-1-row)*w*4+(col-1)*4+1] \n +input[(h-1-row)*w*4+(col-1)*4+2])\n i0p = (input[(h-1-row)*w*4+(col+1)*4+0] \n +input[(h-1-row)*w*4+(col+1)*4+1] \n +input[(h-1-row)*w*4+(col+1)*4+2])\n ipm = (input[(h-2-row)*w*4+(col-1)*4+0] \n +input[(h-2-row)*w*4+(col-1)*4+1] \n +input[(h-2-row)*w*4+(col-1)*4+2])\n ip0 = (input[(h-2-row)*w*4+col*4+0] \n +input[(h-2-row)*w*4+col*4+1] \n +input[(h-2-row)*w*4+col*4+2])\n ipp = (input[(h-2-row)*w*4+(col+1)*4+0] \n +input[(h-2-row)*w*4+(col+1)*4+1] \n +input[(h-2-row)*w*4+(col+1)*4+2])\n if ((i00 != i0m) || (i00 != i0p) || (i00 != ipm) \n || (i00 != ip0) || (i00 != ipp)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n }\n //\n // corners\n //\n row = 0\n col = 0\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0p = (input[(h-1-row)*w*4+(col+1)*4+0] \n +input[(h-1-row)*w*4+(col+1)*4+1] \n +input[(h-1-row)*w*4+(col+1)*4+2])\n ip0 = (input[(h-2-row)*w*4+col*4+0] \n +input[(h-2-row)*w*4+col*4+1] \n +input[(h-2-row)*w*4+col*4+2])\n ipp = (input[(h-2-row)*w*4+(col+1)*4+0] \n +input[(h-2-row)*w*4+(col+1)*4+1] \n +input[(h-2-row)*w*4+(col+1)*4+2])\n if ((i00 != i0p) || (i00 != ip0) || (i00 != ipp)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n row = 0\n col = w-1\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0m = (input[(h-1-row)*w*4+(col-1)*4+0] \n +input[(h-1-row)*w*4+(col-1)*4+1] \n +input[(h-1-row)*w*4+(col-1)*4+2])\n ip0 = (input[(h-2-row)*w*4+col*4+0] \n +input[(h-2-row)*w*4+col*4+1] \n +input[(h-2-row)*w*4+col*4+2])\n ipm = (input[(h-2-row)*w*4+(col-1)*4+0] \n +input[(h-2-row)*w*4+(col-1)*4+1] \n +input[(h-2-row)*w*4+(col-1)*4+2])\n if ((i00 != i0m) || (i00 != ip0) || (i00 != ipm)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n row = h-1\n col = 0\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0p = (input[(h-1-row)*w*4+(col+1)*4+0] \n +input[(h-1-row)*w*4+(col+1)*4+1] \n +input[(h-1-row)*w*4+(col+1)*4+2])\n im0 = (input[(h-row)*w*4+col*4+0] \n +input[(h-row)*w*4+col*4+1] \n +input[(h-row)*w*4+col*4+2])\n imp = (input[(h-row)*w*4+(col+1)*4+0] \n +input[(h-row)*w*4+(col+1)*4+1] \n +input[(h-row)*w*4+(col+1)*4+2])\n if ((i00 != i0p) || (i00 != im0) || (i00 != imp)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n row = h-1\n col = w-1\n i00 = (input[(h-1-row)*w*4+col*4+0] \n +input[(h-1-row)*w*4+col*4+1] \n +input[(h-1-row)*w*4+col*4+2])\n i0m = (input[(h-1-row)*w*4+(col-1)*4+0] \n +input[(h-1-row)*w*4+(col-1)*4+1] \n +input[(h-1-row)*w*4+(col-1)*4+2])\n im0 = (input[(h-row)*w*4+col*4+0] \n +input[(h-row)*w*4+col*4+1] \n +input[(h-row)*w*4+col*4+2])\n imm = (input[(h-row)*w*4+(col-1)*4+0] \n +input[(h-row)*w*4+(col-1)*4+1] \n +input[(h-row)*w*4+(col-1)*4+2])\n if ((i00 != i0m) || (i00 != im0) || (i00 != imm)) {\n output[(h-1-row)*w*4+col*4+0] = 255\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else if (i00 == 0) {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 0\n output[(h-1-row)*w*4+col*4+2] = 255\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n output[(h-1-row)*w*4+col*4+0] = 0\n output[(h-1-row)*w*4+col*4+1] = 255\n output[(h-1-row)*w*4+col*4+2] = 0\n output[(h-1-row)*w*4+col*4+3] = 255\n }\n self.postMessage({buffer:output.buffer},[output.buffer])\n })\n }\n//\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"262.3025579837396","left":"1815.6484625538612","filename":"undefined","inputs":{},"outputs":{}},"0.8903773266711255":{"definition":"//\n// orient edges\n// input is green:interior, blue:exterior, red:boundary\n// output is red 128:north,64:south, green 128:east,64:west, blue 128:start,64:stop\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2016\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the fab modules \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 = 'orient edges'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt){\n mod.input = evt.detail\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n ctx.putImageData(mod.input,0,0)\n var ctx = mod.display.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n orient_edges()\n }}}\n//\n// outputs\n//\nvar outputs = {\n image:{type:'RGBA',\n event:function(){\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n mods.output(mod,'image',img)}}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // on-screen drawing 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 // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\n //\n // off-screen display canvas\n //\n var canvas = document.createElement('canvas')\n mod.display = canvas\n //\n // view 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('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 win.document.body.appendChild(document.createTextNode('red:north, dark red:south'))\n win.document.body.appendChild(document.createElement('br'))\n win.document.body.appendChild(document.createTextNode('green:east, dark green:west'))\n win.document.body.appendChild(document.createElement('br'))\n win.document.body.appendChild(document.createTextNode('blue:start, dark blue:stop'))\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.display,0,0)\n })\n div.appendChild(btn)\n }\n//\n// local functions\n//\n// orient edges\n//\nfunction orient_edges() {\n var blob = new Blob(['('+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.buffer)\n var imgdata = new ImageData(buf,w,h)\n var ctx = mod.img.getContext(\"2d\")\n ctx.putImageData(imgdata,0,0)\n var disp = new Uint8ClampedArray(evt.data.display)\n var dispdata = new ImageData(disp,w,h)\n var ctx = mod.display.getContext(\"2d\")\n ctx.putImageData(dispdata,0,0)\n if (w > h) {\n var x0 = 0\n var y0 = mod.canvas.height*.5*(1-h/w)\n var wd = mod.canvas.width\n var hd = mod.canvas.width*h/w\n }\n else {\n var x0 = mod.canvas.width*.5*(1-w/h)\n var y0 = 0\n var wd = mod.canvas.height*w/h\n var hd = mod.canvas.height\n }\n var w = mod.canvas.width\n var h = mod.canvas.height\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,w,h)\n ctx.drawImage(mod.display,x0,y0,wd,hd)\n webworker.terminate()\n outputs.image.event()\n })\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n webworker.postMessage({\n height:mod.input.height,width:mod.input.width,\n buffer:mod.input.data.buffer},\n [mod.input.data.buffer])\n }\nfunction worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var input = new Uint8ClampedArray(evt.data.buffer)\n var output = new Uint8ClampedArray(h*w*4)\n var row,col\n var boundary = 0\n var interior = 1\n var exterior = 2\n var alpha = 3\n var northsouth = 0\n var north = 128\n var south = 64\n var eastwest = 1\n var east = 128\n var west = 64\n var startstop = 2\n var start = 128\n var stop = 64\n //\n // orient body states\n //\n for (row = 1; row < (h-1); ++row) {\n for (col = 1; col < (w-1); ++col) {\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n if (input[(h-1-(row))*w*4+(col)*4+boundary] != 0) {\n if ((input[(h-1-(row+1))*w*4+(col)*4+boundary] != 0)\n && ((input[(h-1-(row))*w*4+(col+1)*4+interior] != 0)\n || (input[(h-1-(row+1))*w*4+(col+1)*4+interior] != 0)))\n output[(h-1-row)*w*4+col*4+northsouth] |= north\n if ((input[(h-1-(row-1))*w*4+(col)*4+boundary] != 0)\n && ((input[(h-1-(row))*w*4+(col-1)*4+interior] != 0)\n || (input[(h-1-(row-1))*w*4+(col-1)*4+interior] != 0)))\n output[(h-1-row)*w*4+col*4+northsouth] |= south\n if ((input[(h-1-(row))*w*4+(col+1)*4+boundary] != 0)\n && ((input[(h-1-(row-1))*w*4+(col)*4+interior] != 0)\n || (input[(h-1-(row-1))*w*4+(col+1)*4+interior] != 0)))\n output[(h-1-row)*w*4+col*4+eastwest] |= east\n if ((input[(h-1-(row))*w*4+(col-1)*4+boundary] != 0)\n && ((input[(h-1-(row+1))*w*4+(col)*4+interior] != 0)\n || (input[(h-1-(row+1))*w*4+(col-1)*4+interior] != 0)))\n output[(h-1-row)*w*4+col*4+eastwest] |= west\n }\n }\n }\n //\n // orient edge states\n //\n for (col = 1; col < (w-1); ++col) {\n row = 0\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n if (input[(h-1-(row))*w*4+(col)*4+boundary] != 0) {\n if ((input[(h-1-(row+1))*w*4+(col)*4+boundary] != 0)\n && (input[(h-1-(row))*w*4+(col+1)*4+interior] != 0)) {\n output[(h-1-row)*w*4+col*4+northsouth] |= north\n output[(h-1-row)*w*4+col*4+startstop] |= start\n }\n if (input[(h-1-(row))*w*4+(col-1)*4+interior] != 0)\n output[(h-1-row)*w*4+col*4+startstop] |= stop\n }\n row = h-1\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n if (input[(h-1-(row))*w*4+(col)*4+boundary] != 0) {\n if (input[(h-1-(row))*w*4+(col+1)*4+interior] != 0)\n output[(h-1-row)*w*4+col*4+startstop] |= stop\n if ((input[(h-1-(row-1))*w*4+(col)*4+boundary] != 0)\n && (input[(h-1-(row))*w*4+(col-1)*4+interior] != 0)) {\n output[(h-1-row)*w*4+col*4+northsouth] |= south\n output[(h-1-row)*w*4+col*4+startstop] |= start\n }\n }\n }\n for (row = 1; row < (h-1); ++row) {\n col = 0\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n if (input[(h-1-(row))*w*4+(col)*4+boundary] != 0) {\n if ((input[(h-1-(row))*w*4+(col+1)*4+boundary] != 0)\n && (input[(h-1-(row-1))*w*4+(col)*4+interior] != 0)) {\n output[(h-1-row)*w*4+col*4+eastwest] |= east\n output[(h-1-row)*w*4+col*4+startstop] |= start\n }\n if (input[(h-1-(row+1))*w*4+(col)*4+interior] != 0)\n output[(h-1-row)*w*4+col*4+startstop] |= stop\n }\n col = w-1\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n if (input[(h-1-(row))*w*4+(col)*4+boundary] != 0) {\n if (input[(h-1-(row-1))*w*4+(col)*4+interior] != 0)\n output[(h-1-row)*w*4+col*4+startstop] |= stop\n if ((input[(h-1-(row))*w*4+(col-1)*4+boundary] != 0)\n && (input[(h-1-(row+1))*w*4+(col)*4+interior] != 0)) {\n output[(h-1-row)*w*4+col*4+eastwest] |= west\n output[(h-1-row)*w*4+col*4+startstop] |= start\n }\n }\n }\n //\n // orient corner states (todo)\n //\n row = 0\n col = 0\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n row = h-1\n col = 0\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n row = 0\n col = w-1\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n row = h-1\n col = w-1\n output[(h-1-row)*w*4+col*4+northsouth] = 0\n output[(h-1-row)*w*4+col*4+eastwest] = 0\n output[(h-1-row)*w*4+col*4+startstop] = 0\n output[(h-1-row)*w*4+col*4+alpha] = 255\n //\n // invert background for display\n //\n var display = new Uint8ClampedArray(h*w*4)\n var r,g,b,i\n for (row = 0; row < h; ++row) {\n for (col = 0; col < w; ++col) {\n r = output[(h-1-row)*w*4+col*4+0]\n g = output[(h-1-row)*w*4+col*4+1]\n b = output[(h-1-row)*w*4+col*4+2]\n i = r+g+b\n if (i != 0) { \n display[(h-1-row)*w*4+col*4+0] = output[(h-1-row)*w*4+col*4+0]\n display[(h-1-row)*w*4+col*4+1] = output[(h-1-row)*w*4+col*4+1]\n display[(h-1-row)*w*4+col*4+2] = output[(h-1-row)*w*4+col*4+2]\n display[(h-1-row)*w*4+col*4+3] = output[(h-1-row)*w*4+col*4+3]\n }\n else {\n display[(h-1-row)*w*4+col*4+0] = 255\n display[(h-1-row)*w*4+col*4+1] = 255\n display[(h-1-row)*w*4+col*4+2] = 255\n display[(h-1-row)*w*4+col*4+3] = 255\n }\n }\n }\n //\n // return output\n //\n self.postMessage({buffer:output.buffer,display:display.buffer},[output.buffer,display.buffer])\n })\n }\n//\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"692.3025579837396","left":"1796.6484625538612","filename":"undefined","inputs":{},"outputs":{}},"0.08127540142793499":{"definition":"//\n// read png\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2015,6\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the fab modules \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 png'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\n }\n//\n// outputs\n//\nvar outputs = {\n image:{type:'RGBA',\n event:function(){\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n mods.output(mod,'image',img)}},\n imageInfo:{type:'object',\n event:function(){\n var obj = {}\n obj.name = mod.name.nodeValue\n obj.dpi = parseFloat(mod.dpitext.value)\n obj.width = mod.img.width\n obj.height = mod.img.height\n mods.output(mod,'imageInfo',obj)}}}\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 png_read_handler()\n })\n div.appendChild(file)\n mod.file = file\n //\n // on-screen drawing 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 // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\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 png 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 // view 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('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 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 div.appendChild(document.createTextNode(' '))\n //\n // invert 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('invert'))\n btn.addEventListener('click',function(){\n invert_image()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // info div\n //\n var info = document.createElement('div')\n info.setAttribute('id',div.id+'info')\n info.appendChild(document.createTextNode('dpi: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('input',function(){\n mod.dpi = parseFloat(mod.dpitext.value)\n mod.mmtext.nodeValue = (25.4*mod.img.width/mod.dpi).toFixed(3)\n +' x '+(25.4*mod.img.height/mod.dpi).toFixed(3)+' mm'\n mod.intext.nodeValue = (mod.img.width/mod.dpi).toFixed(3)\n +' x '+(mod.img.height/mod.dpi).toFixed(3)+' in'\n outputs.imageInfo.event()\n })\n info.appendChild(input)\n mod.dpitext = input\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('px: ')\n info.appendChild(text)\n mod.pxtext = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('mm: ')\n info.appendChild(text)\n mod.mmtext = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('in: ')\n info.appendChild(text)\n mod.intext = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('')\n info.appendChild(text)\n mod.name = text\n div.appendChild(info)\n }\n//\n// local functions\n//\n// read handler\n//\nfunction png_read_handler(event) {\n var file_reader = new FileReader()\n file_reader.onload = png_binary_handler\n input_file = mod.file.files[0]\n file_name = input_file.name\n mod.name.nodeValue = file_name\n file_reader.readAsArrayBuffer(input_file)\n }\n//\n// binary load handler\n//\nfunction png_binary_handler(event) {\n //\n // get DPI\n //\n // 8 header\n // 4 len, 4 type, data, 4 crc\n // pHYs 4 ppx, 4 ppy, 1 unit: 0 ?, 1 meter\n // IEND\n //\n var units = ppx = ppy = 0\n var buf = event.target.result\n var view = new DataView(buf)\n var ptr = 8\n if (!((view.getUint8(1) == 80) && (view.getUint8(2) == 78) && (view.getUint8(3) == 71))) {\n set_prompt(\"error: PNG header not found\")\n return\n }\n while (1) {\n var length = view.getUint32(ptr)\n ptr += 4\n var type = String.fromCharCode(\n view.getUint8(ptr),view.getUint8(ptr+1),\n view.getUint8(ptr+2),view.getUint8(ptr+3))\n ptr += 4\n if (type == \"pHYs\") {\n ppx = view.getUint32(ptr)\n ppy = view.getUint32(ptr + 4)\n units = view.getUint8(ptr + 8)\n }\n if (type == \"IEND\")\n break\n ptr += length + 4\n }\n if (units == 0) {\n set_prompt(\"no PNG units not found, assuming 72 DPI\")\n ppx = 72*1000/25.4\n }\n dpi = ppx*25.4/1000\n //\n // read as URL for display\n //\n var file_reader = new FileReader()\n file_reader.onload = png_URL_handler\n file_reader.readAsDataURL(input_file)\n }\n//\n// URL load handler\n//\nfunction png_URL_handler(event) {\n var img = new Image()\n img.setAttribute(\"src\",event.target.result)\n img.onload = function() {\n if (img.width > img.height) {\n var x0 = 0\n var y0 = mod.canvas.height*.5*(1-img.height/img.width)\n var w = mod.canvas.width\n var h = mod.canvas.width*img.height/img.width\n }\n else {\n var x0 = mod.canvas.width*.5*(1-img.width/img.height)\n var y0 = 0\n var w = mod.canvas.height*img.width/img.height\n var h = mod.canvas.height\n }\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n ctx.drawImage(img,x0,y0,w,h)\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = img.width\n ctx.canvas.height = img.height \n ctx.drawImage(img,0,0)\n mod.dpitext.value = dpi.toFixed(3)\n mod.pxtext.nodeValue = img.width+' x '+img.height+' px'\n mod.mmtext.nodeValue = (25.4*img.width/dpi).toFixed(3)\n +' x '+(25.4*img.height/dpi).toFixed(3)+' mm'\n mod.intext.nodeValue = (img.width/dpi).toFixed(3)\n +' x '+(img.height/dpi).toFixed(3)+' in'\n outputs.image.event()\n outputs.imageInfo.event()\n }\n }\n//\n// invert image\n//\nfunction invert_image() {\n var blob = new Blob(['('+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.buffer)\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.canvas.height*.5*(1-h/w)\n var wd = mod.canvas.width\n var hd = mod.canvas.width*h/w\n }\n else {\n var x0 = mod.canvas.width*.5*(1-w/h)\n var y0 = 0\n var wd = mod.canvas.height*w/h\n var hd = mod.canvas.height\n }\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.drawImage(mod.img,x0,y0,wd,hd)\n webworker.terminate()\n outputs.image.event()\n })\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n var h = mod.img.height\n var w = mod.img.width\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,w,h)\n webworker.postMessage({\n height:img.height,width:img.width,buffer:img.data.buffer},\n [img.data.buffer])\n }\nfunction worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var buf = new Uint8ClampedArray(evt.data.buffer)\n for (var row = 0; row < h; ++row) {\n for (var col = 0; col < w; ++col) {\n buf[(h-1-row)*w*4+col*4+0] \n = 255-buf[(h-1-row)*w*4+col*4+0] \n buf[(h-1-row)*w*4+col*4+1] \n = 255-buf[(h-1-row)*w*4+col*4+1] \n buf[(h-1-row)*w*4+col*4+2] \n = 255-buf[(h-1-row)*w*4+col*4+2] \n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n }\n self.postMessage({buffer:buf.buffer},[buf.buffer])\n })\n }\n//\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"301.3025579837396","left":"291.64846255386124","filename":"undefined","inputs":{},"outputs":{}},"0.6488303557466412":{"definition":"//\n// image threshold\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2015,6\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the fab modules \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 = 'image threshold'\n//\n// initialization\n//\nvar init = function() {\n mod.threshold.value = 0.5\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt){\n mod.input = evt.detail\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n ctx.putImageData(mod.input,0,0)\n threshold_image()}}}\n//\n// outputs\n//\nvar outputs = {\n image:{type:'RGBA',\n event:function(){\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n mods.output(mod,'image',img)}}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // on-screen drawing 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 // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\n //\n // threshold value\n //\n div.appendChild(document.createTextNode('threshold (0-1): '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n threshold_image()\n })\n div.appendChild(input)\n mod.threshold = input\n div.appendChild(document.createElement('br'))\n //\n // view 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('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 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// threshold image\n//\nfunction threshold_image() {\n var blob = new Blob(['('+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.buffer)\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.canvas.height*.5*(1-h/w)\n var wd = mod.canvas.width\n var hd = mod.canvas.width*h/w\n }\n else {\n var x0 = mod.canvas.width*.5*(1-w/h)\n var y0 = 0\n var wd = mod.canvas.height*w/h\n var hd = mod.canvas.height\n }\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n ctx.drawImage(mod.img,x0,y0,wd,hd)\n webworker.terminate()\n outputs.image.event()\n })\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n var t = parseFloat(mod.threshold.value)\n var ctx = mod.img.getContext(\"2d\")\n ctx.putImageData(mod.input,0,0)\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n webworker.postMessage({\n height:mod.input.height,width:mod.input.width,threshold:t,\n buffer:img.data.buffer},\n [img.data.buffer])\n }\nfunction worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var t = evt.data.threshold\n var buf = new Uint8ClampedArray(evt.data.buffer)\n var r,g,b,a,i\n for (var row = 0; row < h; ++row) {\n for (var col = 0; col < w; ++col) {\n r = buf[(h-1-row)*w*4+col*4+0] \n g = buf[(h-1-row)*w*4+col*4+1] \n b = buf[(h-1-row)*w*4+col*4+2] \n a = buf[(h-1-row)*w*4+col*4+3] \n i = (r+g+b)/(3*255)\n if (a == 0)\n val = 255\n else if (i > t)\n var val = 255\n else\n var val = 0\n buf[(h-1-row)*w*4+col*4+0] = val\n buf[(h-1-row)*w*4+col*4+1] = val\n buf[(h-1-row)*w*4+col*4+2] = val\n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n }\n self.postMessage({buffer:buf.buffer},[buf.buffer])\n })\n }\n//\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"173.3025579837396","left":"1334.6484625538612","filename":"undefined","inputs":{},"outputs":{}},"0.749132408760488":{"definition":"//\n// vectorize\n// input is red 128:north,64:south, green 128:east,64:west, blue 128:start,64:stop\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2016\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the fab modules \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 = 'vectorize'\n//\n// initialization\n//\nvar init = function() {\n mod.error.value = 1\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt){\n mod.input = evt.detail\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n ctx.putImageData(mod.input,0,0)\n vectorize()\n }}}\n//\n// outputs\n//\nvar outputs = {\n path:{type:'array',\n event:function(){\n mods.output(mod,'path',mod.path)\n }}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\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 // error value\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 // sort\n //\n div.appendChild(document.createTextNode('sort distance: '))\n var input = document.createElement('input')\n input.type = 'checkbox'\n input.id = mod.div.id+'sort'\n input.checked = true\n div.appendChild(input)\n mod.sort = input\n div.appendChild(document.createElement('br'))\n //\n // view 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('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 }\n//\n// local functions\n//\n// vectorize\n//\nfunction vectorize() {\n //\n // draw path\n //\n function draw_path(path) {\n window.URL.revokeObjectURL(url)\n var svg = document.getElementById(mod.div.id+'svg')\n svg.setAttribute('viewBox',\"0 0 \"+(mod.img.width-1)+\" \"+(mod.img.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 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 in path) {\n if (path[segment].length > 1) {\n if (xend != null) {\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 = xend\n var y1 = yend\n var x2 = path[segment][0][0]\n var y2 = h-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 // 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 svg.appendChild(g)\n }\n //\n // set up worker\n //\n var blob = new Blob(['('+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 webworker.terminate()\n mod.path = evt.data.path\n draw_path(mod.path)\n outputs.path.event()\n })\n //\n // call worker\n //\n webworker.postMessage({\n height:mod.input.height,width:mod.input.width,sort:mod.sort.checked,\n error:parseFloat(mod.error.value),\n buffer:mod.input.data.buffer})\n }\n//\n// vectorize worker\n//\nfunction worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var sort = evt.data.sort\n var input = new Uint8ClampedArray(evt.data.buffer)\n var northsouth = 0\n var north = 128\n var south = 64\n var eastwest = 1\n var east = 128\n var west = 64\n var startstop = 2\n var start = 128\n var stop = 64\n var path = []\n //\n // edge follower\n //\n function follow_edges(row,col) {\n if ((input[(h-1-row)*w*4+col*4+northsouth] != 0)\n || (input[(h-1-row)*w*4+col*4+eastwest] != 0)) {\n path[path.length] = [[col,row]]\n while (1) {\n if (input[(h-1-row)*w*4+col*4+northsouth] & north) {\n input[(h-1-row)*w*4+col*4+northsouth] =\n input[(h-1-row)*w*4+col*4+northsouth] & ~north\n row += 1\n path[path.length-1][path[path.length-1].length] = [col,row]\n }\n else if (input[(h-1-row)*w*4+col*4+northsouth] & south) {\n input[(h-1-row)*w*4+col*4+northsouth] =\n input[(h-1-row)*w*4+col*4+northsouth] & ~south\n row -= 1\n path[path.length-1][path[path.length-1].length] = [col,row]\n }\n else if (input[(h-1-row)*w*4+col*4+eastwest] & east) {\n input[(h-1-row)*w*4+col*4+eastwest] =\n input[(h-1-row)*w*4+col*4+eastwest] & ~east\n col += 1\n path[path.length-1][path[path.length-1].length] = [col,row]\n }\n else if (input[(h-1-row)*w*4+col*4+eastwest] & west) {\n input[(h-1-row)*w*4+col*4+eastwest] =\n input[(h-1-row)*w*4+col*4+eastwest] & ~west\n col -= 1\n path[path.length-1][path[path.length-1].length] = [col,row]\n }\n else\n break\n }\n }\n }\n //\n // follow boundary starts\n //\n for (var row = 1; row < (h-1); ++row) {\n col = 0\n follow_edges(row,col)\n col = w-1\n follow_edges(row,col)\n }\n for (var col = 1; col < (w-1); ++col) {\n row = 0\n follow_edges(row,col)\n row = h-1 \n follow_edges(row,col)\n }\n //\n // follow interior paths\n //\n for (var row = 1; row < (h-1); ++row) {\n for (var col = 1; col < (w-1); ++col) {\n follow_edges(row,col)\n }\n }\n //\n // vectorize path\n //\n var error = evt.data.error\n var vecpath = []\n for (var seg = 0; seg < path.length; ++seg) {\n var x0 = path[seg][0][0]\n var y0 = path[seg][0][1]\n vecpath[vecpath.length] = [[x0,y0]]\n var xsum = x0\n var ysum = y0\n var sum = 1\n for (var pt = 1; pt < path[seg].length; ++pt) {\n var xold = x\n var yold = y\n var x = path[seg][pt][0]\n var y = path[seg][pt][1]\n if (sum == 1) {\n xsum += x\n ysum += y\n sum += 1\n }\n else {\n var xmean = xsum/sum\n var ymean = ysum/sum\n var dx = xmean-x0\n var dy = ymean-y0\n var d = Math.sqrt(dx*dx+dy*dy)\n var nx = dy/d\n var ny = -dx/d\n var l = Math.abs(nx*(x-x0)+ny*(y-y0))\n if (l < error) {\n xsum += x\n ysum += y\n sum += 1\n }\n else {\n vecpath[vecpath.length-1][vecpath[vecpath.length-1].length] = [xold,yold]\n x0 = xold\n y0 = yold\n xsum = xold\n ysum = yold\n sum = 1\n }\n }\n if (pt == (path[seg].length-1)) {\n vecpath[vecpath.length-1][vecpath[vecpath.length-1].length] = [x,y]\n }\n }\n }\n //\n // sort path\n //\n if ((vecpath.length > 0) && (sort == true)) {\n var dmin = w*w+h*h\n segmin = null\n for (var seg = 0; seg < vecpath.length; ++seg) {\n var x = vecpath[seg][0][0]\n var y = vecpath[seg][0][0]\n var d = x*x+y*y\n if (d < dmin) {\n dmin = d\n segmin = seg\n }\n }\n if (segmin != null) {\n var sortpath = [vecpath[segmin]]\n vecpath.splice(segmin,1)\n }\n while (vecpath.length > 0) {\n var dmin = w*w+h*h\n var x0 = sortpath[sortpath.length-1][sortpath[sortpath.length-1].length-1][0]\n var y0 = sortpath[sortpath.length-1][sortpath[sortpath.length-1].length-1][1]\n segmin = null\n for (var seg = 0; seg < vecpath.length; ++seg) {\n var x = vecpath[seg][0][0]\n var y = vecpath[seg][0][1]\n var d = (x-x0)*(x-x0)+(y-y0)*(y-y0)\n if (d < dmin) {\n dmin = d\n segmin = seg\n }\n }\n if (segmin != null) {\n sortpath[sortpath.length] = vecpath[segmin]\n vecpath.splice(segmin,1)\n }\n }\n }\n else if ((vecpath.length > 0) && (sort == false))\n sortpath = vecpath\n else\n sortpath = []\n //\n // return path\n //\n self.postMessage({path:sortpath})\n })\n }\n//\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"606.3025579837396","left":"1391.6484625538612","filename":"undefined","inputs":{},"outputs":{}},"0.9308036593731321":{"definition":"//\n// save file\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2016\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is \n// provided as is; no warranty is provided, and users accept all \n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'save file'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\n file:{type:'object',\n event:function(evt){\n mod.name = evt.detail.name\n mod.contents = evt.detail.contents\n save_file()\n }}}\n//\n// outputs\n//\nvar outputs = {}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // info\n //\n var text = document.createTextNode('name:')\n div.appendChild(text)\n mod.nametext = text\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('size:')\n div.appendChild(text)\n mod.sizetext = text\n div.appendChild(document.createElement('br'))\n }\n//\n// local functions\n//\nfunction save_file() {\n var a = document.createElement('a')\n a.setAttribute('href','data:text/plain;charset=utf-8,'+ \n encodeURIComponent(mod.contents))\n a.setAttribute('download',mod.name)\n a.style.display = 'none'\n document.body.appendChild(a)\n a.click()\n document.body.removeChild(a)\n mod.nametext.nodeValue = 'name: '+mod.name\n mods.fit(mod.div)\n mod.sizetext.nodeValue = 'size: '+mod.contents.length\n mods.fit(mod.div)\n }\n//\n// return values\n//\nreturn ({\n mod:mod,\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"708.2066115702479","left":"847.0661157024794","filename":"modules/file/save","inputs":{},"outputs":{}},"0.3039514232113123":{"definition":"//\n// path to Gerber\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2021\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 = 'path to Gerber'\n//\n// initialization\n//\nvar init = function() {\n mod.fill.checked = false\n }\n//\n// inputs\n//\nvar inputs = {\n imageInfo:{type:'',\n event:function(evt){\n mod.imageInfo = evt.detail\n }},\n path:{type:'',\n event:function(evt){\n mod.path = evt.detail\n }}}\n//\n// outputs\n//\nvar outputs = {\n Gerber:{type:'',\n event:function(evt){\n mods.output(mod,'Gerber',evt)\n }}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('plot'))\n btn.addEventListener('click',function(){\n plot()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode('format:'))\n div.appendChild(document.createElement('br'))\n var formats = document.createElement('div');\n formats.style.textAlign = 'left'\n var input = document.createElement('input')\n input.type = 'radio'\n input.name = mod.div.id+'format'\n input.id = mod.div.id+'fill'\n formats.appendChild(input)\n mod.fill = input\n formats.appendChild(document.createTextNode('fill'))\n formats.appendChild(document.createElement('br'))\n var input = document.createElement('input')\n input.type = 'radio'\n input.name = mod.div.id+'format'\n input.id = mod.div.id+'outline'\n formats.appendChild(input)\n mod.outline = input\n formats.appendChild(document.createTextNode('outline'))\n formats.appendChild(document.createElement('br'))\n var input = document.createElement('input')\n input.type = 'radio'\n input.name = mod.div.id+'format'\n input.id = mod.div.id+'outline'\n input.disabled = true\n formats.appendChild(input)\n mod.drill = input\n formats.appendChild(document.createTextNode('drill'))\n div.appendChild(formats)\n }\n//\n// local functions\n//\nfunction format(x) {\n var s = x.toFixed(6)\n s = s.substr(0,s.length-7)+s.substr(-6,6)\n return s\n }\n//\nfunction plot() {\n var imgwidth = mod.imageInfo.width/parseFloat(mod.imageInfo.dpi)\n var imgheight = mod.imageInfo.height/parseFloat(mod.imageInfo.dpi)\n var x,y\n //\n str = ''\n str += \"%MOIN*%\\n\" // inch units\n str += \"%LPD*%\\n\" // layer dark\n str += \"%FSLAX66Y66*%\\n\" // format absolute 6.6\n str += \"G01*\\n\" // linear interpolation\n //\n if (mod.fill.checked == true) {\n for (var seg = 0; seg < mod.path.length; ++seg) {\n str += \"G36*\\n\"\n x = imgwidth*mod.path[seg][0][0]/(mod.imageInfo.width-1)\n y = imgheight*mod.path[seg][0][1]/(mod.imageInfo.height-1)\n str += 'X'+format(x)+'Y'+format(y)+'D02*\\n'\n for (var pt = 1; pt < mod.path[seg].length; ++pt) {\n var x = imgwidth*mod.path[seg][pt][0]/(mod.imageInfo.width-1)\n var y = imgheight*mod.path[seg][pt][1]/(mod.imageInfo.height-1)\n str += 'X'+format(x)+'Y'+format(y)+'D01*\\n'\n }\n x = imgwidth*mod.path[seg][0][0]/(mod.imageInfo.width-1)\n y = imgheight*mod.path[seg][0][1]/(mod.imageInfo.height-1)\n str += 'X'+format(x)+'Y'+format(y)+'D01*\\n'\n str += \"G37*\\n\"\n }\n str += \"M02*\\n\"\n var obj = {}\n obj.type = 'file'\n obj.name = mod.imageInfo.name+'.gtl'\n obj.contents = str\n outputs.Gerber.event(obj)\n }\n else if (mod.outline.checked == true) {\n str += \"%ADD10C,0.001*%\\n\"\n str += \"D10*\\n\"\n for (var seg = 0; seg < mod.path.length; ++seg) {\n x = imgwidth*mod.path[seg][0][0]/(mod.imageInfo.width-1)\n y = imgheight*mod.path[seg][0][1]/(mod.imageInfo.height-1)\n str += 'X'+format(x)+'Y'+format(y)+'D02*\\n'\n for (var pt = 1; pt < mod.path[seg].length; ++pt) {\n var x = imgwidth*mod.path[seg][pt][0]/(mod.imageInfo.width-1)\n var y = imgheight*mod.path[seg][pt][1]/(mod.imageInfo.height-1)\n str += 'X'+format(x)+'Y'+format(y)+'D01*\\n'\n }\n x = imgwidth*mod.path[seg][0][0]/(mod.imageInfo.width-1)\n y = imgheight*mod.path[seg][0][1]/(mod.imageInfo.height-1)\n str += 'X'+format(x)+'Y'+format(y)+'D01*\\n'\n }\n str += \"M02*\\n\"\n var obj = {}\n obj.type = 'file'\n obj.name = mod.imageInfo.name+'.gko'\n obj.contents = str\n outputs.Gerber.event(obj)\n }\n }\n/*\nD11*\nX1000Y1000D02*\nX1000Y2000D01*\nX2000Y2000D01*\nX1500Y1000D01*\nM02*\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":"429.0133288253729","left":"811.9563594751694","filename":"modules/path/formats/gerber","inputs":{},"outputs":{}}},"links":["{\"source\":\"{\\\"id\\\":\\\"0.07944144280928633\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.8903773266711255\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.08127540142793499\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.6488303557466412\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.8903773266711255\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.749132408760488\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.6488303557466412\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.07944144280928633\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.08127540142793499\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"imageInfo\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.3039514232113123\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"imageInfo\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.749132408760488\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"path\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.3039514232113123\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"path\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.3039514232113123\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"Gerber\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.9308036593731321\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"file\\\"}\"}"]} \ No newline at end of file