Commit 96cde867 authored by Neil Gershenfeld's avatar Neil Gershenfeld
Browse files

start 3D

parent 34216e42
......@@ -175,6 +175,7 @@
<i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raster</i><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./modules/processes/mill/raster/2.5D'>2.5D</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./modules/processes/mill/raster/2D'>2D</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./modules/processes/mill/raster/3D'>3D</a><br>
<i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;read</i><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./modules/read/png'>png</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./modules/read/stl'>stl</a><br>
......
......@@ -144,6 +144,7 @@ module_label('   mill')
module_label('      raster')
module_menu('         2.5D','modules/processes/mill/raster/2.5D')
module_menu('         2D','modules/processes/mill/raster/2D')
module_menu('         3D','modules/processes/mill/raster/3D')
module_label('read')
module_menu('   png','modules/read/png')
module_menu('   stl','modules/read/stl')
......
//
// mill raster 3D
//
// Neil Gershenfeld 1/18/20
//
// This work may be reproduced, modified, distributed, performed, and
// displayed for any purpose, but must acknowledge the mods
// project. Copyright is retained and must be preserved. The work is
// provided as is; no warranty is provided, and users accept all
// liability.
//
// closure
//
(function(){
//
// module globals
//
var mod = {}
//
// name
//
var name = 'mill raster 3D'
//
// initialization
//
var init = function() {
mod.dia_in.value = 0.0156
mod.dia_mm.value = 25.4*parseFloat(mod.dia_in.value)
mod.stepover.value = 0.5
}
//
// inputs
//
var inputs = {
map:{type:'',label:'height map',
event:function(evt){
mod.width = evt.detail.width
mod.height = evt.detail.height
var ctx = mod.img.getContext("2d")
ctx.canvas.width = mod.width
ctx.canvas.height = mod.height
console.log(mod.width)
console.log(mod.height)
}}}
//
// outputs
//
var outputs = {
toolpath:{type:'',
event:function(){
cmd = {}
cmd.path = mod.path
cmd.name = mod.name
cmd.dpi = mod.dpi
cmd.width = mod.width
cmd.height = mod.height
cmd.depth = mod.depth
mods.output(mod,'toolpath',cmd)
}}}
//
// interface
//
var interface = function(div){
mod.div = div
//
// tool diameter
//
div.appendChild(document.createTextNode('tool diameter'))
div.appendChild(document.createElement('br'))
div.appendChild(document.createTextNode('mm: '))
var input = document.createElement('input')
input.type = 'text'
input.size = 6
input.addEventListener('input',function(){
mod.dia_in.value = parseFloat(mod.dia_mm.value)/25.4
})
div.appendChild(input)
mod.dia_mm = input
div.appendChild(document.createTextNode(' in: '))
var input = document.createElement('input')
input.type = 'text'
input.size = 6
input.addEventListener('input',function(){
mod.dia_mm.value = parseFloat(mod.dia_in.value)*25.4
})
div.appendChild(input)
mod.dia_in = input
div.appendChild(document.createElement('br'))
//
// stepover
//
div.appendChild(document.createTextNode('stepover (0-1): '))
var input = document.createElement('input')
input.type = 'text'
input.size = 6
div.appendChild(input)
mod.stepover = input
div.appendChild(document.createElement('br'))
//
// tool shape
//
div.appendChild(document.createTextNode('tool shape: '))
div.appendChild(document.createTextNode('flat end'))
var input = document.createElement('input')
input.type = 'radio'
input.name = mod.div.id+'shape'
input.id = mod.div.id+'flatend'
input.checked = true
div.appendChild(input)
mod.flatend= input
div.appendChild(document.createElement('br'))
//
// direction
//
div.appendChild(document.createTextNode('direction: '))
div.appendChild(document.createTextNode('x'))
var input = document.createElement('input')
input.type = 'radio'
input.name = mod.div.id+'direction'
input.id = mod.div.id+'dirx'
input.checked = true
div.appendChild(input)
mod.dirx = input
div.appendChild(document.createElement('br'))
//
// calculate
//
var btn = document.createElement('button')
btn.style.padding = mods.ui.padding
btn.style.margin = 1
var span = document.createElement('span')
var text = document.createTextNode('calculate')
mod.label = text
span.appendChild(text)
mod.labelspan = span
btn.appendChild(span)
btn.addEventListener('click',function(){
mod.label.nodeValue = 'calculating'
mod.labelspan.style.fontWeight = 'bold'
mod.offset = 0.5
mod.offsetCount = 0
mod.path = []
clear_path()
outputs.diameter.event()
outputs.offset.event()
})
div.appendChild(btn)
div.appendChild(document.createTextNode(' '))
//
// view
//
var btn = document.createElement('button')
btn.style.padding = mods.ui.padding
btn.style.margin = 1
btn.appendChild(document.createTextNode('view'))
btn.addEventListener('click',function(){
var win = window.open('')
var btn = document.createElement('button')
btn.appendChild(document.createTextNode('close'))
btn.style.padding = mods.ui.padding
btn.style.margin = 1
btn.addEventListener('click',function(){
win.close()
})
win.document.body.appendChild(btn)
win.document.body.appendChild(document.createElement('br'))
var svg = document.getElementById(mod.div.id+'svg')
var clone = svg.cloneNode(true)
clone.setAttribute('width',mod.img.width)
clone.setAttribute('height',mod.img.height)
win.document.body.appendChild(clone)
})
div.appendChild(btn)
div.appendChild(document.createElement('br'))
//
// on-screen SVG
//
var svgNS = "http://www.w3.org/2000/svg"
var svg = document.createElementNS(svgNS,"svg")
svg.setAttribute('id',mod.div.id+'svg')
svg.setAttributeNS("http://www.w3.org/2000/xmlns/",
"xmlns:xlink","http://www.w3.org/1999/xlink")
svg.setAttribute('width',mods.ui.canvas)
svg.setAttribute('height',mods.ui.canvas)
svg.style.backgroundColor = 'rgb(255,255,255)'
var g = document.createElementNS(svgNS,'g')
g.setAttribute('id',mod.div.id+'g')
svg.appendChild(g)
div.appendChild(svg)
div.appendChild(document.createElement('br'))
//
// off-screen image canvas
//
var canvas = document.createElement('canvas')
mod.img = canvas
}
//
// local functions
//
// set_values
//
function set_values(settings) {
for (var s in settings) {
switch(s) {
case 'tool diameter (in)':
mod.dia_in.value = settings[s]
mod.dia_mm.value = parseFloat(mod.dia_in.value)*25.4
break
case 'cut depth (in)':
mod.cut_in.value = settings[s]
mod.cut_mm.value = parseFloat(mod.cut_in.value)*25.4
break
case 'max depth (in)':
mod.max_in.value = settings[s]
mod.max_mm.value = parseFloat(mod.max_in.value)*25.4
break
case 'offset number':
mod.number.value = settings[s]
break
}
}
}
//
// clear_path
//
function clear_path() {
var svg = document.getElementById(mod.div.id+'svg')
svg.setAttribute('viewBox',"0 0 "+(mod.img.width-1)+" "+(mod.img.height-1))
var g = document.getElementById(mod.div.id+'g')
svg.removeChild(g)
var g = document.createElementNS('http://www.w3.org/2000/svg','g')
g.setAttribute('id',mod.div.id+'g')
svg.appendChild(g)
}
//
// accumulate_path
// todo: replace inefficient insertion sort
// todo: move sort out of main thread
//
function accumulate_path(path) {
var forward = mod.forward.checked
var conventional = mod.conventional.checked
var sort = mod.sort.checked
for (var segnew = 0; segnew < path.length; ++segnew) {
if (conventional)
path[segnew].reverse()
if (mod.path.length == 0)
mod.path.splice(0,0,path[segnew])
else if (sort) {
var xnew = path[segnew][0][0]
var ynew = path[segnew][0][1]
var dmin = Number.MAX_VALUE
var segmin = -1
for (var segold = 0; segold < mod.path.length; ++segold) {
var xold = mod.path[segold][0][0]
var yold = mod.path[segold][0][1]
var dx = xnew-xold
var dy = ynew-yold
var d = Math.sqrt(dx*dx+dy*dy)
if (d < dmin) {
dmin = d
segmin = segold
}
}
if (forward)
mod.path.splice(segmin+1,0,path[segnew])
else
mod.path.splice(segmin,0,path[segnew])
}
else {
if (forward)
mod.path.splice(mod.path.length,0,path[segnew])
else
mod.path.splice(0,0,path[segnew])
}
}
}
//
// merge_path
//
function merge_path() {
var dmerge = mod.dpi*parseFloat(mod.merge.value)*parseFloat(mod.dia_in.value)
var seg = 0
while (seg < (mod.path.length-1)) {
var xold = mod.path[seg][mod.path[seg].length-1][0]
var yold = mod.path[seg][mod.path[seg].length-1][1]
var xnew = mod.path[seg+1][0][0]
var ynew = mod.path[seg+1][0][1]
var dx = xnew-xold
var dy = ynew-yold
var d = Math.sqrt(dx*dx+dy*dy)
if (d < dmerge)
mod.path.splice(seg,2,mod.path[seg].concat(mod.path[seg+1]))
else
seg += 1
}
}
//
// add_depth
//
function add_depth() {
var cut = parseFloat(mod.cut_in.value)
var max = parseFloat(mod.max_in.value)
var newpath = []
for (var seg = 0; seg < mod.path.length; ++seg) {
var depth = cut
if (mod.path[seg][0][0] == mod.path[seg][mod.path[seg].length-1][0]) {
var newseg = []
while (depth <= max) {
var idepth = -Math.round(mod.dpi*depth)
for (var pt = 0; pt < mod.path[seg].length; ++pt) {
var point = mod.path[seg][pt].concat(idepth)
newseg.splice(newseg.length,0,point)
}
if (depth == max)
break
depth += cut
if (depth > max)
depth = max
}
newpath.splice(newpath.length,0,newseg)
}
else {
var newseg = []
while (depth <= max) {
var idepth = -Math.round(mod.dpi*depth)
for (var pt = 0; pt < mod.path[seg].length; ++pt) {
var point = mod.path[seg][pt].concat(idepth)
newseg.splice(newseg.length,0,point)
}
newpath.splice(newpath.length,0,newseg)
newseg = []
if (depth == max)
break
depth += cut
if (depth > max)
depth = max
}
}
}
mod.path = newpath
mod.depth = Math.round(parseFloat(mod.max_in.value)*mod.dpi)
}
//
// draw_path
//
function draw_path(path) {
var g = document.getElementById(mod.div.id+'g')
var h = mod.img.height
var w = mod.img.width
var xend = null
var yend = null
//
// loop over segments
//
for (var segment = 0; segment < path.length; ++segment) {
if (path[segment].length > 1) {
//
// loop over points
//
for (var point = 1; point < path[segment].length; ++point) {
var line = document.createElementNS('http://www.w3.org/2000/svg','line')
line.setAttribute('stroke','black')
line.setAttribute('stroke-width',1)
line.setAttribute('stroke-linecap','round')
var x1 = path[segment][point-1][0]
var y1 = h-path[segment][point-1][1]-1
var x2 = path[segment][point][0]
var y2 = h-path[segment][point][1]-1
xend = x2
yend = y2
line.setAttribute('x1',x1)
line.setAttribute('y1',y1)
line.setAttribute('x2',x2)
line.setAttribute('y2',y2)
var dx = x2-x1
var dy = y2-y1
var d = Math.sqrt(dx*dx+dy*dy)
if (d > 0) {
nx = 6*dx/d
ny = 6*dy/d
var tx = 3*dy/d
var ty = -3*dx/d
g.appendChild(line)
triangle = document.createElementNS('http://www.w3.org/2000/svg','polygon')
triangle.setAttribute('points',x2+','+y2+' '+(x2-nx+tx)+','+(y2-ny+ty)
+' '+(x2-nx-tx)+','+(y2-ny-ty))
triangle.setAttribute('fill','black')
g.appendChild(triangle)
}
}
}
}
}
//
// draw_connections
//
function draw_connections() {
var g = document.getElementById(mod.div.id+'g')
var h = mod.img.height
var w = mod.img.width
//
// loop over segments
//
for (var segment = 1; segment < mod.path.length; ++segment) {
//
// draw connection from previous segment
//
var line = document.createElementNS('http://www.w3.org/2000/svg','line')
line.setAttribute('stroke','red')
line.setAttribute('stroke-width',1)
line.setAttribute('stroke-linecap','round')
var x1 = mod.path[segment-1][mod.path[segment-1].length-1][0]
var y1 = h-mod.path[segment-1][mod.path[segment-1].length-1][1]-1
var x2 = mod.path[segment][0][0]
var y2 = h-mod.path[segment][0][1]-1
line.setAttribute('x1',x1)
line.setAttribute('y1',y1)
line.setAttribute('x2',x2)
line.setAttribute('y2',y2)
var dx = x2-x1
var dy = y2-y1
var d = Math.sqrt(dx*dx+dy*dy)
if (d > 0) {
nx = 6*dx/d
ny = 6*dy/d
var tx = 3*dy/d
var ty = -3*dx/d
g.appendChild(line)
triangle = document.createElementNS('http://www.w3.org/2000/svg','polygon')
triangle.setAttribute('points',x2+','+y2+' '+(x2-nx+tx)+','+(y2-ny+ty)
+' '+(x2-nx-tx)+','+(y2-ny-ty))
triangle.setAttribute('fill','red')
g.appendChild(triangle)
}
}
}
//
// return values
//
return ({
mod:mod,
name:name,
init:init,
inputs:inputs,
outputs:outputs,
interface:interface
})
}())
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment