Various progress

This commit is contained in:
Bán Dénes 2020-06-28 22:35:53 +02:00
parent 8d6be0ea00
commit fad615045a
6 changed files with 135 additions and 65 deletions

View file

@ -310,7 +310,9 @@ neighbors: [dir_x, dir_y]
bind: num | [num_x, num_y] | [num_t, num_r, num_b, num_l] # default = 10 bind: num | [num_x, num_y] | [num_t, num_r, num_b, num_l] # default = 10
``` ```
The former declares the directions we want to bind in, where `dir_x` can be one of `left`, `right`, or `both`; and `dir_y` can be one of `up`, `down`, or `both`. Again, key-level declaration means that both of these should be specified in the `points` section, benefiting from the same extension process every key-level setting does.
The former declares the directions we want to bind in, where `dir_x` can be one of `left`, `right`, `both` or `neither`; and `dir_y` can be one of `up`, `down`, `both` or `neither`.
(If left empty, `neither` will be assumed.)
The latter declares how much we want to bind, i.e., the amount of overlap we want in that direction to make sure that we can reach the neighbor (`num` applies to all directions, `num_x` horizontally, `num_y` vertically, and the t/r/b/l versions to top/right/bottom/left, respectively). The latter declares how much we want to bind, i.e., the amount of overlap we want in that direction to make sure that we can reach the neighbor (`num` applies to all directions, `num_x` horizontally, `num_y` vertically, and the t/r/b/l versions to top/right/bottom/left, respectively).
If it's a one-piece design, we also need to "glue" the halves together (or we might want to leave some extra space for the controller on the inner side for splits). If it's a one-piece design, we also need to "glue" the halves together (or we might want to leave some extra space for the controller on the inner side for splits).
@ -319,11 +321,11 @@ This is where the following section comes into play:
```yaml ```yaml
glue: glue:
top: top:
left: <line def> left: <anchor>
right: <line def> | num right: <anchor> | num
bottom: bottom:
left: <line def> left: <anchor>
right: <line def> | num right: <anchor> | num
waypoints: waypoints:
- percent: num - percent: num
width: num | [num_left, num_right] width: num | [num_left, num_right]
@ -333,13 +335,12 @@ glue:
- ... - ...
``` ```
...where a `<line def>` looks like: ...where an `<anchor>` is the same as it was for points:
```yaml ```yaml
ref: <point reference> ref: <point reference>
shift: [x, y] shift: [x, y] # default = [0, 0]
rotate: num rotate: num # default = 0
origin: [x, y]
``` ```
The section's `top` and `bottom` are both formatted the same, and describe the center line's top and bottom intersections, respectively. The section's `top` and `bottom` are both formatted the same, and describe the center line's top and bottom intersections, respectively.
@ -359,6 +360,7 @@ If this is insufficient (maybe because it would leave holes), the `waypoints` ca
Here, `percent` means the y coordinate along the centerline (going from the top intersection to the bottom intersection), and `width` means the offset on the x axis. Here, `percent` means the y coordinate along the centerline (going from the top intersection to the bottom intersection), and `width` means the offset on the x axis.
If this is somehow _still_ insufficient (or there were problems with the binding phase), we can specify additional primitive shapes under the `extra` key (similarly to how we would use them in the exports; see below). If this is somehow _still_ insufficient (or there were problems with the binding phase), we can specify additional primitive shapes under the `extra` key (similarly to how we would use them in the exports; see below).
These are then added to what we have so far to finish out the glue.
<hr /> <hr />
@ -376,7 +378,9 @@ Now we can configure what we want to "export" as outlines from this phase, given
- `side: left | right` : the side we want - `side: left | right` : the side we want
- `glue` : just the glue, but the "ideal" version of it. This means that instead of the `glue` we defined above, we get `all` - `left` - `right`, so the _exact_ middle piece we would have needed to glue everything together. Parameters: - `glue` : just the glue, but the "ideal" version of it. This means that instead of the `glue` we defined above, we get `all` - `left` - `right`, so the _exact_ middle piece we would have needed to glue everything together. Parameters:
- everything we could specify for `all` (since those are needed for the calculation) - everything we could specify for `all` (since those are needed for the calculation)
- `side: left | right | both # default = both)` : optionally, we could choose only one side of the glue as well - `raw: boolean # default = false)` : optionally, we could choose to get the "raw" (i.e., the non-idealized) glue as well
- `ref` : a previously defined outline, see below.
- `name: outline_name` : the name of the referenced outline
Additionally, we can use primitive shapes: Additionally, we can use primitive shapes:
@ -384,8 +388,7 @@ Additionally, we can use primitive shapes:
- `ref: <point reference>` : what position and rotation to consider as the origin - `ref: <point reference>` : what position and rotation to consider as the origin
- `rotate: num` : extra rotation - `rotate: num` : extra rotation
- `shift: [x, y]` : extra translation - `shift: [x, y]` : extra translation
- `width: num` : the width of the rectangle - `size: num | [width, height]` : the size of the rectangle
- `height: num` : the height of the rectangle
- `circle` : an independent circle primitive. Parameters: - `circle` : an independent circle primitive. Parameters:
- `ref`, `rotate`, and `shift` are the same as above - `ref`, `rotate`, and `shift` are the same as above
- `radius: num` : the radius of the circle - `radius: num` : the radius of the circle
@ -405,7 +408,7 @@ exports:
``` ```
Operations are performed in order, and the resulting shape is exported as an output. Operations are performed in order, and the resulting shape is exported as an output.
Additionally, it is going to be available to further export declarations under the name specified (`my_name`, in this case). Additionally, it is going to be available to further export declarations (using the `ref` type) under the name specified (`my_name`, in this case).
If we only want to use it as a building block for further exports, we can start the name with an underscore (e.g., `_my_name`) to prevent it from being actually exported. If we only want to use it as a building block for further exports, we can start the name with an underscore (e.g., `_my_name`) to prevent it from being actually exported.

View file

@ -24,16 +24,28 @@ const detect_unexpected = exports.detect_unexpected = (obj, name, expected) => {
} }
} }
const xy = exports.xy = (raw, name) => { const numarr = exports.numarr = (raw, name, length) => {
assert(type(raw) == 'array' && raw.length == 2, `Field "${name}" should be an array of length 2!`) assert(type(raw) == 'array' && raw.length == length, `Field "${name}" should be an array of length ${length}!`)
const x = raw[0] || 0 raw = raw.map(val => val || 0)
const y = raw[1] || 0 raw.map(val => assert(type(val) == 'number', `Field "${name}" should contain numbers!`))
assert(type(x) == 'number' && type(y) == 'number', `Field "${name}" should contain numbers!`) return raw
return {x, y}
} }
exports.anchor = (raw, name, points={}) => { const xy = exports.xy = (raw, name) => numarr(raw, name, 2)
detect_unexpected(raw, name, ['ref', 'shift', 'rotate'])
exports.wh = (raw, name) => {
if (!Array.isArray(raw)) raw = [raw, raw]
return a.xy(raw, name)
}
exports.trbl = (raw, name) => {
if (!Array.isArray(raw)) raw = [raw, raw, raw, raw]
if (raw.length == 2) raw = [raw[1], raw[0], raw[1], raw[0]]
return numarr(raw, name, 4)
}
exports.anchor = (raw, name, points={}, check_unexpected=true) => {
if (check_unexpected) detect_unexpected(raw, name, ['ref', 'shift', 'rotate'])
let a = new Point() let a = new Point()
if (raw.ref !== undefined) { if (raw.ref !== undefined) {
assert(points[raw.ref], `Unknown point reference "${raw.ref}" in anchor "${name}"!`) assert(points[raw.ref], `Unknown point reference "${raw.ref}" in anchor "${name}"!`)
@ -41,8 +53,8 @@ exports.anchor = (raw, name, points={}) => {
} }
if (raw.shift !== undefined) { if (raw.shift !== undefined) {
const xyval = xy(raw.shift, name + '.shift') const xyval = xy(raw.shift, name + '.shift')
a.x += xyval.x a.x += xyval[0]
a.y += xyval.y a.y += xyval[1]
} }
if (raw.rotate !== undefined) { if (raw.rotate !== undefined) {
a.r += sane(raw.rotate || 0, name + '.rotate', 'number') a.r += sane(raw.rotate || 0, name + '.rotate', 'number')

View file

@ -1,33 +1,26 @@
#!/usr/bin/env node #!/usr/bin/env node
const m = require('makerjs') // libs
const fs = require('fs-extra') const fs = require('fs-extra')
const path = require('path') const path = require('path')
const yaml = require('js-yaml') const yaml = require('js-yaml')
const yargs = require('yargs') const yargs = require('yargs')
// internals
const u = require('./utils') const u = require('./utils')
const io = require('./io')
const points_lib = require('./points') const points_lib = require('./points')
// const outline_lib = require('./outline') const outline_lib = require('./outline')
const dump_model = (model, file='model') => { // command line args
const assembly = m.model.originate({
models: u.deepcopy(model),
units: 'mm'
})
fs.mkdirpSync(path.dirname(`${file}.dxf`))
fs.writeFileSync(`${file}.dxf`, m.exporter.toDXF(assembly))
if (args.debug) {
fs.writeJSONSync(`${file}.json`, assembly, {spaces: 4})
}
}
const args = yargs const args = yargs
.option('config', { .option('config', {
alias: 'c', alias: 'c',
demandOption: true, demandOption: true,
describe: 'Config yaml file', describe: 'Config yaml/json file',
type: 'string' type: 'string'
}) })
.option('output', { .option('output', {
@ -37,8 +30,9 @@ const args = yargs
type: 'string' type: 'string'
}) })
.option('debug', { .option('debug', {
alias: 'd',
default: false, default: false,
hidden: true, describe: 'Debug mode',
type: 'boolean' type: 'boolean'
}) })
.argv .argv
@ -46,15 +40,28 @@ const args = yargs
fs.mkdirpSync(args.o) fs.mkdirpSync(args.o)
const config_parser = args.c.endsWith('.yaml') ? yaml.load : JSON.parse const config_parser = args.c.endsWith('.yaml') ? yaml.load : JSON.parse
const config = config_parser(fs.readFileSync(args.c).toString()) let config
try {
config = config_parser(fs.readFileSync(args.c).toString())
} catch (err) {
throw new Error(`Malformed input "${args.c}": ${err}`)
}
// points
console.log('Parsing points...')
const points = points_lib.parse(config.points) const points = points_lib.parse(config.points)
if (args.debug) { if (args.debug) {
fs.writeJSONSync(path.join(args.o, 'points.json'), points, {spaces: 4}) fs.writeJSONSync(path.join(args.o, 'points.json'), points, {spaces: 4})
const size = 14 const rect = u.rect(18, 18, [-9, -9])
const rect = u.rect(size, size, [-size/2, -size/2]) const points_demo = points_lib.position(points, rect)
const points_demo = outline_lib.layout(points, rect) io.dump_model(points_demo, path.join(args.o, 'points_demo'), args.debug)
dump_model(points_demo, path.join(args.o, 'points_demo'))
} }
// outlines
// console.log('Generating outlines...')
// goodbye
console.log('Done.') console.log('Done.')

18
src/io.js Normal file
View file

@ -0,0 +1,18 @@
const m = require('makerjs')
const fs = require('fs-extra')
const path = require('path')
const u = require('./utils')
exports.dump_model = (model, file='model', debug=false) => {
const assembly = m.model.originate({
models: u.deepcopy(model),
units: 'mm'
})
fs.mkdirpSync(path.dirname(`${file}.dxf`))
fs.writeFileSync(`${file}.dxf`, m.exporter.toDXF(assembly))
if (debug) {
fs.writeJSONSync(`${file}.json`, assembly, {spaces: 4})
}
}

View file

@ -1,20 +1,14 @@
const m = require('makerjs') const m = require('makerjs')
const u = require('./utils') const u = require('./utils')
const a = require('./assert')
const layout = exports.layout = (points, shape) => {
const shapes = {}
for (const [pname, p] of Object.entries(points)) {
shapes[pname] = p.position(u.deepcopy(shape))
}
return {layout: {models: shapes}}
}
const outline = exports._outline = (points, config={}) => params => { const outline = exports._outline = (points, config={}) => params => {
let size = params.size || [18, 18] const size = a.wh(params.size || [18, 18], '')
if (!Array.isArray(size)) size = [size, size] if (!Array.isArray(size)) size = [size, size]
size = a.xy(size, `outline.exports.${params.name}.size`)
const corner = params.corner || 0 const corner = params.corner || 0
@ -142,3 +136,39 @@ const outline = exports._outline = (points, config={}) => params => {
u.dump_model({a: glue, b: left_keys, c: {models: right_keys}}, `all_after_left`) u.dump_model({a: glue, b: left_keys, c: {models: right_keys}}, `all_after_left`)
glue = m.model.combineUnion(glue, right_keys) glue = m.model.combineUnion(glue, right_keys)
u.dump_model({a: glue, b: {models: keys}}, `fullll`) u.dump_model({a: glue, b: {models: keys}}, `fullll`)
}
const parse_glue = exports._parse_glue = (config = {}, points = {}) => {
a.detect_unexpected(config, 'outline.glue', ['top', 'bottom', 'waypoints', 'extra'])
for (const y in ['top', 'bottom']) {
a.detect_unexpected(config[y], `outline.glue.${y}`, ['left', 'right'])
config[y].left = a.anchor(config[y].left, `outline.glue.${y}.left`, points)
if (a.type(config[y].right) != 'number') {
config[y].right = a.anchor(config[y].right, `outline.glue.${y}.right`, points)
}
}
config.bottom = a.sane(config.bottom, 'outline.glue.bottom', 'object')
config.bottom.left = a.anchor(config.bottom.left, 'outline.glue.bottom.left', points)
if (a.type(config.bottom.right) != 'number') {
config.bottom.right = a.anchor(config.bottom.right, 'outline.glue.bottom.right', points)
}
}
exports.parse = (config = {}, points = {}) => {
a.detect_unexpected(config, 'outline', ['glue', 'exports'])
const glue = parse_glue(config.glue, points)
}

View file

@ -8,7 +8,7 @@ const extend_pair = exports._extend_pair = (to, from) => {
if (from === undefined || from === null) return to if (from === undefined || from === null) return to
if (to_type != from_type) return from if (to_type != from_type) return from
if (from_type == 'object') { if (from_type == 'object') {
const res = {} const res = u.deepcopy(to)
for (const key of Object.keys(from)) { for (const key of Object.keys(from)) {
res[key] = extend_pair(to[key], from[key]) res[key] = extend_pair(to[key], from[key])
} }
@ -147,16 +147,6 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor) => {
col.rows[row] || {} col.rows[row] || {}
) )
require('fs-extra').writeJSONSync('arst.json', {
default_key,
zone_wide_key,
col_key: col.key,
zone_wide_rows: zone_wide_rows[row] || {},
col_rows: col.rows[row] || {},
result: key
}, {spaces: 4})
throw 28
key.name = key.name || `${col_name}_${row}` key.name = key.name || `${col_name}_${row}`
key.shift = a.xy(key.shift, `${key.name}.shift`) key.shift = a.xy(key.shift, `${key.name}.shift`)
key.rotate = a.sane(key.rotate, `${key.name}.rotate`, 'number') key.rotate = a.sane(key.rotate, `${key.name}.rotate`, 'number')
@ -206,7 +196,9 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor) => {
exports.parse = (config) => { exports.parse = (config = {}) => {
a.detect_unexpected(config, 'points', ['zones', 'rotate', 'mirror'])
let points = {} let points = {}
@ -264,3 +256,11 @@ exports.parse = (config) => {
return filtered return filtered
} }
exports.position = (points, shape) => {
const shapes = {}
for (const [pname, p] of Object.entries(points)) {
shapes[pname] = p.position(u.deepcopy(shape))
}
return {layout: {models: shapes}}
}