295 lines
No EOL
7 KiB
JavaScript
295 lines
No EOL
7 KiB
JavaScript
const m = require('makerjs')
|
|
const fs = require('fs-extra')
|
|
|
|
|
|
|
|
|
|
// TODO: refactor this to use the new config format
|
|
|
|
// const column = (func, col) => ({
|
|
// models: {
|
|
// bottom: up(func(col, 'bottom'), 0 * (side + padding)),
|
|
// middle: up(func(col, 'middle'), 1 * (side + padding)),
|
|
// top: up(func(col, 'top'), 2 * (side + padding))
|
|
// }
|
|
// })
|
|
|
|
// const matrix = (func) => {
|
|
// const models = {}
|
|
// let i = 0
|
|
// let sum = 0
|
|
// for (const {name, shift} of columns) {
|
|
// let col = column(func, name)
|
|
// sum += shift
|
|
// if (name == 'pinky') {
|
|
// col = rotate(col, pinky_angle, [side, 0])
|
|
// }
|
|
// col = up(col, sum)
|
|
// col = right(col, i * (side + padding))
|
|
// models[name] = col
|
|
// i++
|
|
// }
|
|
// return {models}
|
|
// }
|
|
|
|
// const thumbfan = (func) => ({
|
|
// models: {
|
|
// inner: func('thumb', 'inner'),
|
|
// home: rotate(
|
|
// right(
|
|
// func('thumb', 'home'),
|
|
// side + padding + kc_diff
|
|
// ),
|
|
// thumb_angle,
|
|
// [side + padding / 2, -overhang]
|
|
// ),
|
|
// outer: rotate(
|
|
// right(
|
|
// rotate(
|
|
// right(
|
|
// func('thumb', 'outer'),
|
|
// side + padding + kc_diff
|
|
// ),
|
|
// thumb_angle,
|
|
// [side + padding / 2 + kc_diff, -overhang]
|
|
// ),
|
|
// side + padding + kc_diff
|
|
// ),
|
|
// thumb_angle,
|
|
// [side + padding / 2, -overhang]
|
|
// )
|
|
// }
|
|
// })
|
|
|
|
// const half = (func) => {
|
|
// const result = {
|
|
// models: {
|
|
// matrix: matrix(func),
|
|
// thumbfan: move(
|
|
// thumbfan(func),
|
|
// [
|
|
// 3 * (side + padding) + thumb_start,
|
|
// -(side + padding) + staggers_sum
|
|
// ]
|
|
// )
|
|
// }
|
|
// }
|
|
// return m.model.rotate(result, half_angle)
|
|
// }
|
|
|
|
|
|
// TODO temp
|
|
let _debug_key = 0
|
|
const _debug = {}
|
|
const debug = (xy) => {
|
|
_debug[_debug_key++] = {
|
|
type: 'circle',
|
|
origin: [xy[0], xy[1]],
|
|
radius: 1
|
|
}
|
|
}
|
|
|
|
const dump = exports.dump = (points, opts={}) => {
|
|
|
|
const line = (a, b) => ({
|
|
type: 'line',
|
|
origin: a,
|
|
end: b
|
|
})
|
|
const s = (opts.side || 14) / 2
|
|
|
|
const models = {}
|
|
for (const [key, point] of Object.entries(points)) {
|
|
const paths = {
|
|
l: line([-s, -s], [-s, s]),
|
|
t: line([-s, s], [ s, s]),
|
|
r: line([ s, s], [ s, -s]),
|
|
b: line([ s, -s], [-s, -s])
|
|
}
|
|
models[key] = m.model.moveRelative(m.model.rotate({paths}, point.r), point.p)
|
|
}
|
|
|
|
// TODO
|
|
models['debug'] = {paths: _debug}
|
|
|
|
const assembly = m.model.originate({
|
|
models,
|
|
units: 'mm'
|
|
})
|
|
|
|
fs.writeFileSync(`${opts.file || 'dump'}.dxf`, m.exporter.toDXF(assembly))
|
|
}
|
|
|
|
|
|
|
|
|
|
const Point = exports.Point = class Point {
|
|
constructor(x, y, r, col={}, row={}) {
|
|
this.x = x
|
|
this.y = y
|
|
this.r = r
|
|
this.col = col
|
|
this.row = row
|
|
}
|
|
|
|
get p() {
|
|
return [this.x, this.y]
|
|
}
|
|
|
|
set p(val) {
|
|
[this.x, this.y] = val
|
|
}
|
|
}
|
|
|
|
|
|
const push_rotation = (list, angle, origin) => {
|
|
let candidate = origin
|
|
for (const r of list) {
|
|
candidate = m.point.rotate(candidate, r.angle, r.origin)
|
|
}
|
|
list.push({
|
|
angle: angle,
|
|
origin: candidate
|
|
})
|
|
}
|
|
|
|
|
|
const matrix = (cols, rows, anchor=new Point(0, 0, 0), reverse=false) => {
|
|
|
|
console.log('matrix', cols, rows, anchor, reverse)
|
|
|
|
|
|
const sign = reverse ? -1 : 1
|
|
const points = {}
|
|
let x = anchor.x
|
|
let stagger_sum = anchor.y
|
|
let rotation_sum = anchor.r
|
|
const rotations = [{
|
|
angle: anchor.r,
|
|
origin: [0, 0]
|
|
}]
|
|
for (const col of cols) {
|
|
|
|
|
|
// TODO rotation origin reversal is not this easy
|
|
// and probably the whole reversal idea is not even necessary
|
|
// sleep on it, and possibly remove to simplify
|
|
|
|
|
|
if (reverse) {
|
|
x -= col.padding || 19
|
|
if (col.rotate) {
|
|
let ox = 0, oy = 0
|
|
if (col.origin) {
|
|
ox = -col.origin[0]
|
|
oy = col.origin[1]
|
|
}
|
|
push_rotation(
|
|
rotations,
|
|
col.rotate,
|
|
m.point.add([ox, oy], [x, stagger_sum])
|
|
)
|
|
rotation_sum += col.rotate
|
|
}
|
|
}
|
|
|
|
stagger_sum += sign * col.stagger || 0
|
|
let y = stagger_sum
|
|
|
|
|
|
for (const row of (col.rows || rows || [{name: 'default'}])) {
|
|
let point = [x, y]
|
|
debug(point)
|
|
for (const r of rotations) {
|
|
point = m.point.rotate(point, r.angle, r.origin)
|
|
debug(point)
|
|
}
|
|
points[col.name + '_' + row.name] = new Point(
|
|
point[0],
|
|
point[1],
|
|
rotation_sum + (row.angle || 0),
|
|
col,
|
|
row
|
|
)
|
|
console.log('new Point', points[col.name + '_' + row.name])
|
|
y += row.padding || 19
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!reverse) {
|
|
if (col.rotate) {
|
|
push_rotation(
|
|
rotations,
|
|
-col.rotate,
|
|
m.point.add(col.origin || [0, 0], [x, stagger_sum])
|
|
)
|
|
|
|
a = rotations.pop()
|
|
debug(a.origin)
|
|
rotations.push(a)
|
|
|
|
rotation_sum += -col.rotate
|
|
}
|
|
x += col.padding || 19
|
|
}
|
|
|
|
|
|
|
|
}
|
|
return points
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
exports.parse = (config) => {
|
|
|
|
// basic matrix
|
|
let matrix_anchor
|
|
if (config.anchor) {
|
|
let x = 0
|
|
let y = 0
|
|
if (config.anchor.shift) {
|
|
x = config.anchor.shift[0]
|
|
y = config.anchor.shift[1]
|
|
}
|
|
const r = -config.anchor.angle || 0
|
|
matrix_anchor = new Point(x, y, r)
|
|
}
|
|
let points = matrix(config.columns, config.rows, matrix_anchor)
|
|
|
|
// thumbfan
|
|
let thumb_anchor = new Point(0, 0, 0)
|
|
let thumb_anchor_index = -1
|
|
for (const key of config.thumbfan) {
|
|
thumb_anchor_index++
|
|
if (key.anchor) {
|
|
const ref = points[key.anchor.ref] || thumb_anchor
|
|
thumb_anchor.p = m.point.add(ref.p, key.anchor.shift)
|
|
thumb_anchor.r += key.anchor.angle || 0
|
|
break
|
|
} else continue
|
|
}
|
|
|
|
const forward = config.thumbfan.slice(thumb_anchor_index)
|
|
const rewind = config.thumbfan.slice(0, thumb_anchor_index)
|
|
const thumb_rows = config.thumb_rows || [{name: 'thumb'}]
|
|
|
|
points = Object.assign(points, matrix(forward, thumb_rows, thumb_anchor))
|
|
points = Object.assign(points, matrix(rewind, thumb_rows, thumb_anchor, true))
|
|
|
|
|
|
dump(points)
|
|
throw 2
|
|
|
|
|
|
|
|
|
|
return points
|
|
} |