Still more outline progress
This commit is contained in:
parent
999a5dfad8
commit
066e1a54ea
6 changed files with 132 additions and 62 deletions
23
README.md
23
README.md
|
@ -154,12 +154,13 @@ That's where `column.rows` can help, specifying a row-override for just that col
|
|||
Easy.
|
||||
|
||||
Now for the trickier part: keys.
|
||||
There are four ways to set key-related options (again, to minimize the need for repetition):
|
||||
There are five ways to set key-related options (again, to minimize the need for repetition):
|
||||
|
||||
1. at the zone-level
|
||||
2. at the column-level
|
||||
3. at the row-level
|
||||
4. at the key-level
|
||||
1. at the global-level (affecting all zones)
|
||||
2. at the zone-level
|
||||
3. at the column-level
|
||||
4. at the row-level
|
||||
5. at the key-level
|
||||
|
||||
These "extend" each other in this order so by the time we reach a specific key, every level had an opportunity to modify something.
|
||||
Note that unlike the overriding for rows, key-related extension is additive.
|
||||
|
@ -172,7 +173,7 @@ But if `key = {a: 1}` is extended by `key = {b: 2}`, the result is `key = {a: 1,
|
|||
|
||||
Lastly, while there are a few key-specific attributes that have special meaning in the context of points (listed below), any key with any data can be specified here.
|
||||
This can be useful for storing arbitrary meta-info about the keys, or just configuring later stages with key-level parameters.
|
||||
So, for example, when the outline phase specifies `bind` as a key-level parameter (see below), it means that the global value can be extended just like any other key-level attribute.
|
||||
So, for example, when the outline phase specifies `bind` as a key-level parameter (see below), it means that it can be specified just like any other key-level attribute.
|
||||
|
||||
Now for the "official" key-level attributes:
|
||||
|
||||
|
@ -201,6 +202,7 @@ Indeed:
|
|||
```yaml
|
||||
points:
|
||||
zones: <what we talked about so far...>
|
||||
key: <global key def>
|
||||
rotate: num # default = 0
|
||||
mirror:
|
||||
axis: num # default = 0
|
||||
|
@ -384,8 +386,7 @@ Now we can configure what we want to "export" as outlines from this phase, given
|
|||
- `ref`, `rotate`, and `shift` are the same as above
|
||||
- `radius: num` : the radius of the circle
|
||||
- `polygon` : an independent polygon primitive. Parameters:
|
||||
- `ref`, `rotate`, and `shift` are the same as above
|
||||
- `points: [[x, y], ...]` : the points of the polygon
|
||||
- `points: [<point_def>, ...]` : the points of the polygon. Each `<point_def>` can have its own `ref` and `shift`, all of which are still the same as above. If `ref` is unspecified, the previous point's will be assumed. For the first, it's `[0, 0]` by default.
|
||||
- `ref` : a previously defined outline, see below.
|
||||
- `name: outline_name` : the name of the referenced outline
|
||||
|
||||
|
@ -394,7 +395,7 @@ Using these, we define exports as follows:
|
|||
```yaml
|
||||
exports:
|
||||
my_name:
|
||||
- op: add | sub | diff # default = add
|
||||
- operation: add | subtract | intersect # default = add
|
||||
type: <one of the types>
|
||||
<type-specific params>
|
||||
- ...
|
||||
|
@ -481,13 +482,13 @@ case:
|
|||
extrude: num # default = 1
|
||||
translate: [x, y, z] # default = [0, 0, 0]
|
||||
rotate: [ax, ay, az] # default = [0, 0, 0]
|
||||
op: add | sub | diff # default = add
|
||||
operation: add | subtract | intersect # default = add
|
||||
- ...
|
||||
...
|
||||
```
|
||||
|
||||
`outline` specifies which outline to import onto the xy plane, while `extrude` specifies how much it should be extruded along the z axis.
|
||||
After that, the object is `translate`d, `rotate`d, and combined with what we have so far according to `op`.
|
||||
After that, the object is `translate`d, `rotate`d, and combined with what we have so far according to `operation`.
|
||||
If we only want to use an object as a building block for further objects, we can employ the same "start with an underscore" trick we learned at the outlines section to make it "private".
|
||||
|
||||
|
||||
|
|
|
@ -38,9 +38,9 @@ const numarr = exports.numarr = (raw, name, length) => {
|
|||
|
||||
const xy = exports.xy = (raw, name) => numarr(raw, name, 2)
|
||||
|
||||
exports.wh = (raw, name) => {
|
||||
const wh = exports.wh = (raw, name) => {
|
||||
if (!Array.isArray(raw)) raw = [raw, raw]
|
||||
return a.xy(raw, name)
|
||||
return xy(raw, name)
|
||||
}
|
||||
|
||||
exports.trbl = (raw, name) => {
|
||||
|
@ -49,15 +49,15 @@ exports.trbl = (raw, name) => {
|
|||
return numarr(raw, name, 4)
|
||||
}
|
||||
|
||||
exports.anchor = (raw, name, points={}, check_unexpected=true) => {
|
||||
exports.anchor = (raw, name, points={}, check_unexpected=true, default_point=new Point()) => {
|
||||
if (check_unexpected) detect_unexpected(raw, name, ['ref', 'shift', 'rotate'])
|
||||
let a = new Point()
|
||||
let a = default_point.clone()
|
||||
if (raw.ref !== undefined) {
|
||||
assert(points[raw.ref], `Unknown point reference "${raw.ref}" in anchor "${name}"!`)
|
||||
a = points[raw.ref].clone()
|
||||
}
|
||||
if (raw.shift !== undefined) {
|
||||
const xyval = xy(raw.shift, name + '.shift')
|
||||
const xyval = wh(raw.shift || [0, 0], name + '.shift')
|
||||
a.x += xyval[0]
|
||||
a.y += xyval[1]
|
||||
}
|
||||
|
|
11
src/cli.js
11
src/cli.js
|
@ -52,15 +52,20 @@ try {
|
|||
console.log('Parsing points...')
|
||||
const points = points_lib.parse(config.points)
|
||||
if (args.debug) {
|
||||
fs.writeJSONSync(path.join(args.o, 'points.json'), points, {spaces: 4})
|
||||
const rect = u.rect(18, 18, [-9, -9])
|
||||
const points_demo = points_lib.position(points, rect)
|
||||
io.dump_model(points_demo, path.join(args.o, 'points_demo'), args.debug)
|
||||
io.dump_model(points_demo, path.join(args.o, 'points/points_demo'), args.debug)
|
||||
fs.writeJSONSync(path.join(args.o, 'points/points.json'), points, {spaces: 4})
|
||||
}
|
||||
|
||||
// outlines
|
||||
|
||||
// console.log('Generating outlines...')
|
||||
console.log('Generating outlines...')
|
||||
const outlines = outline_lib.parse(config.outline, points)
|
||||
for (const [name, outline] of Object.entries(outlines)) {
|
||||
if (!args.debug && name.startsWith('_')) continue
|
||||
io.dump_model(outline, path.join(args.o, `outline/${name}`), args.debug)
|
||||
}
|
||||
|
||||
// goodbye
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const m = require('makerjs')
|
||||
const u = require('./utils')
|
||||
const a = require('./assert')
|
||||
const Point = require('./point')
|
||||
|
||||
const rectangle = (w, h, corner, bevel, name='') => {
|
||||
const error = (dim, val) => `Rectangle for "${name}" isn't ${dim} enough for its corner and bevel (${val} - ${corner} - ${bevel} <= 0)!`
|
||||
|
@ -19,7 +20,7 @@ const parse_glue = exports._parse_glue = (config = {}, points = {}) => {
|
|||
|
||||
a.detect_unexpected(config, 'outline.glue', ['top', 'bottom', 'waypoints', 'extra'])
|
||||
|
||||
for (const y in ['top', 'bottom']) {
|
||||
for (const y of ['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') {
|
||||
|
@ -39,17 +40,17 @@ const parse_glue = exports._parse_glue = (config = {}, points = {}) => {
|
|||
|
||||
// TODO: handle glue.extra (or revoke it from the docs)
|
||||
|
||||
return (export_name, params) => {
|
||||
return (params, export_name, expected) => {
|
||||
|
||||
a.detect_unexpected(params, `${export_name}`, ['side', 'size', 'corner', 'bevel'])
|
||||
a.detect_unexpected(params, `${export_name}`, expected.concat(['side', 'size', 'corner', 'bevel']))
|
||||
const side = a.in(params.side, `${export_name}.side`, ['left', 'right', 'middle', 'both', 'glue'])
|
||||
const size = a.wh(params.size, `${export_name}.size`)
|
||||
const corner = a.sane(params.corner || 0, `${export_name}.corner`, 'number')
|
||||
const bevel = a.sane(params.bevel || 0, `${export_name}.bevel`, 'number')
|
||||
|
||||
let left = {paths: {}}
|
||||
let right = {paths: {}}
|
||||
if (['left', 'right', 'middle', 'both'].includes(params.side)) {
|
||||
let left = {models: {}}
|
||||
let right = {models: {}}
|
||||
if (['left', 'right', 'middle', 'both'].includes(side)) {
|
||||
for (const [pname, p] of Object.entries(points)) {
|
||||
|
||||
let from_x = -size[0] / 2, to_x = size[0] / 2
|
||||
|
@ -77,11 +78,11 @@ const parse_glue = exports._parse_glue = (config = {}, points = {}) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (params.side == 'left') return left
|
||||
if (params.side == 'right') return right
|
||||
if (side == 'left') return left
|
||||
if (side == 'right') return right
|
||||
|
||||
let glue = {paths: {}}
|
||||
if (['middle', 'both', 'glue'].includes(params.side)) {
|
||||
let glue = {models: {}}
|
||||
if (['middle', 'both', 'glue'].includes(side)) {
|
||||
|
||||
const get_line = (anchor) => {
|
||||
if (a.type(anchor) == 'number') {
|
||||
|
@ -135,11 +136,11 @@ const parse_glue = exports._parse_glue = (config = {}, points = {}) => {
|
|||
|
||||
glue = u.poly(waypoints)
|
||||
}
|
||||
if (params.side == 'glue') return glue
|
||||
if (side == 'glue') return glue
|
||||
|
||||
let both = m.model.combineUnion(u.deepcopy(left), glue)
|
||||
both = m.model.combineUnion(both, u.deepcopy(right))
|
||||
if (params.side == 'both') return both
|
||||
if (side == 'both') return both
|
||||
|
||||
let middle = m.model.combineSubtraction(both, left)
|
||||
middle = m.model.combineSubtraction(both, right)
|
||||
|
@ -151,14 +152,68 @@ exports.parse = (config = {}, points = {}) => {
|
|||
a.detect_unexpected(config, 'outline', ['glue', 'exports'])
|
||||
const glue = parse_glue(config.glue, points)
|
||||
|
||||
config = a.sane(config, 'outline.exports', 'object')
|
||||
for (const [key, parts] of Object.entries(config)) {
|
||||
const outlines = {}
|
||||
|
||||
const ex = a.sane(config.exports, 'outline.exports', 'object')
|
||||
for (const [key, parts] of Object.entries(ex)) {
|
||||
let index = 0
|
||||
let result = {models: {}}
|
||||
for (const part of parts) {
|
||||
const name = `outline.exports.${key}[${++index}]`
|
||||
part.op = a.in(part.op || 'add', `${name}.op`, ['add', 'sub', 'diff'])
|
||||
const expected = ['type', 'operation']
|
||||
part.type = a.in(part.type, `${name}.type`, ['keys', 'rectangle', 'circle', 'polygon', 'ref'])
|
||||
part.operation = a.in(part.operation || 'add', `${name}.operation`, ['add', 'subtract', 'intersect'])
|
||||
|
||||
let op = m.model.combineUnion
|
||||
if (part.operation == 'subtract') op = m.model.combineSubtraction
|
||||
else if (part.operation == 'intersect') op = m.model.combineIntersection
|
||||
|
||||
let arg
|
||||
let anchor
|
||||
switch (part.type) {
|
||||
case 'keys':
|
||||
arg = glue(part, name, expected)
|
||||
break
|
||||
case 'rectangle':
|
||||
a.detect_unexpected(part, name, expected.concat(['ref', 'shift', 'rotate', 'size', 'corner', 'bevel']))
|
||||
anchor = a.anchor(part, name, points, false)
|
||||
const size = a.wh(part.size, `${name}.size`)
|
||||
const corner = a.sane(part.corner || 0, `${name}.corner`, 'number')
|
||||
const bevel = a.sane(part.bevel || 0, `${name}.bevel`, 'number')
|
||||
arg = rectangle(size[0], size[1], corner, bevel, name)
|
||||
arg = m.model.move(arg, [-size[0]/2, -size[1]/2]) // center
|
||||
arg = anchor.position(arg)
|
||||
break
|
||||
case 'circle':
|
||||
a.detect_unexpected(part, name, expected.concat(['ref', 'shift', 'rotate', 'radius']))
|
||||
anchor = a.anchor(part, name, points, false)
|
||||
const radius = a.sane(part.radius, `${name}.radius`, 'number')
|
||||
arg = u.circle(anchor.p, radius)
|
||||
break
|
||||
case 'polygon':
|
||||
a.detect_unexpected(part, name, expected.concat(['points']))
|
||||
const poly_points = a.sane(part.points, `${name}.points`, 'array')
|
||||
const parsed_points = []
|
||||
let last_anchor = new Point()
|
||||
let poly_index = 0
|
||||
for (const poly_point of poly_points) {
|
||||
const poly_name = `${name}.points[${++poly_index}]`
|
||||
const anchor = a.anchor(point, point_name, points, true, last_anchor)
|
||||
parsed_points.push(anchor.p)
|
||||
}
|
||||
arg = u.poly(parsed_points)
|
||||
break
|
||||
case 'ref':
|
||||
a.assert(outlines[part.name], `Field "${name}.name" does not name an existing outline!`)
|
||||
arg = outlines[part.name]
|
||||
break
|
||||
}
|
||||
|
||||
result = op(result, arg)
|
||||
}
|
||||
|
||||
outlines[key] = result
|
||||
}
|
||||
|
||||
return outlines
|
||||
}
|
|
@ -42,7 +42,7 @@ const push_rotation = exports._push_rotation = (list, angle, origin) => {
|
|||
})
|
||||
}
|
||||
|
||||
const render_zone = exports._render_zone = (zone_name, zone, anchor) => {
|
||||
const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key) => {
|
||||
|
||||
// zone-wide sanitization
|
||||
|
||||
|
@ -141,6 +141,7 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor) => {
|
|||
for (const row of Object.keys(actual_rows)) {
|
||||
const key = extend(
|
||||
default_key,
|
||||
global_key,
|
||||
zone_wide_key,
|
||||
col.key,
|
||||
zone_wide_rows[row] || {},
|
||||
|
@ -198,16 +199,17 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor) => {
|
|||
|
||||
exports.parse = (config = {}) => {
|
||||
|
||||
a.detect_unexpected(config, 'points', ['zones', 'rotate', 'mirror'])
|
||||
a.detect_unexpected(config, 'points', ['zones', 'key', 'rotate', 'mirror'])
|
||||
|
||||
let points = {}
|
||||
|
||||
// getting original points
|
||||
|
||||
const zones = a.sane(config.zones || {}, 'points.zones', 'object')
|
||||
const global_key = a.sane(config.key || {}, 'points.key', 'object')
|
||||
for (const [zone_name, zone] of Object.entries(zones)) {
|
||||
const anchor = a.anchor(zone.anchor || new Point(), `points.zones.${zone_name}.anchor`, points)
|
||||
points = Object.assign(points, render_zone(zone_name, zone, anchor))
|
||||
const anchor = a.anchor(zone.anchor || {}, `points.zones.${zone_name}.anchor`, points)
|
||||
points = Object.assign(points, render_zone(zone_name, zone, anchor, global_key))
|
||||
}
|
||||
|
||||
// applying global rotation
|
||||
|
|
55
test/fixtures/absolem.yaml
vendored
55
test/fixtures/absolem.yaml
vendored
|
@ -10,48 +10,48 @@ points:
|
|||
rows:
|
||||
bottom:
|
||||
home:
|
||||
neighbors: [right]
|
||||
bind: [,10]
|
||||
top:
|
||||
neighbors: [right]
|
||||
bind: [,10]
|
||||
ring:
|
||||
stagger: 12
|
||||
rows:
|
||||
bottom:
|
||||
neighbors: [left]
|
||||
bind: [,,,10]
|
||||
home:
|
||||
neighbors: [right]
|
||||
bind: [,10]
|
||||
top:
|
||||
neighbors: [right]
|
||||
bind: [,10]
|
||||
middle:
|
||||
stagger: 5
|
||||
rows:
|
||||
bottom:
|
||||
neighbors: [both]
|
||||
bind: [,10,,10]
|
||||
home:
|
||||
neighbors: [both]
|
||||
bind: [,10,,10]
|
||||
top:
|
||||
index:
|
||||
stagger: -6
|
||||
rows:
|
||||
bottom:
|
||||
neighbors: [right]
|
||||
bind: [,10]
|
||||
home:
|
||||
neighbors: [left]
|
||||
bind: [,,,10]
|
||||
top:
|
||||
neighbors: [left]
|
||||
bind: [,,,10]
|
||||
inner:
|
||||
stagger: -2
|
||||
rows:
|
||||
bottom:
|
||||
home:
|
||||
neighbors: [left]
|
||||
bind: [,,,10]
|
||||
top:
|
||||
neighbors: [left]
|
||||
bind: [,,,10]
|
||||
rows:
|
||||
bottom:
|
||||
neighbors: [,up]
|
||||
bind: [10]
|
||||
home:
|
||||
neighbors: [,up]
|
||||
bind: [10]
|
||||
top:
|
||||
thumbfan:
|
||||
anchor:
|
||||
|
@ -64,46 +64,53 @@ points:
|
|||
origin: [9.5, -9]
|
||||
rows:
|
||||
thumb:
|
||||
neighbors: [right]
|
||||
bind: [,10]
|
||||
home:
|
||||
spread: 21.25
|
||||
rotate: -28
|
||||
origin: [11.75, -9]
|
||||
rows:
|
||||
thumb:
|
||||
neighbors: [both]
|
||||
bind: [,10,,10]
|
||||
far:
|
||||
rows:
|
||||
thumb:
|
||||
neighbors: [left]
|
||||
bind: [,,,10]
|
||||
rows:
|
||||
thumb:
|
||||
neighbors: [,up]
|
||||
bind: [10]
|
||||
key:
|
||||
bind: [0, 0, 0, 0]
|
||||
rotate: -20
|
||||
mirror:
|
||||
ref: pinky_home
|
||||
distance: 223.7529778
|
||||
outline:
|
||||
bind: 10
|
||||
glue:
|
||||
top:
|
||||
left:
|
||||
ref: inner_top
|
||||
shift: [,.5]
|
||||
shift: [, 0.5]
|
||||
right:
|
||||
ref: mirror_inner_top
|
||||
shift: [,.5]
|
||||
shift: [, 0.5]
|
||||
bottom:
|
||||
left:
|
||||
ref: far_thumb
|
||||
shift: [.5]
|
||||
shift: [0.5, 0]
|
||||
rotate: 90
|
||||
right:
|
||||
ref: mirror_far_thumb
|
||||
shift: [-.5]
|
||||
shift: [-0.5, 0]
|
||||
rotate: 90
|
||||
waypoints:
|
||||
- percent: 50
|
||||
width: 100
|
||||
- percent: 90
|
||||
width: 50
|
||||
width: 50
|
||||
exports:
|
||||
basic:
|
||||
- type: keys
|
||||
side: both
|
||||
size: 18
|
||||
corner: .5
|
Loading…
Add table
Add a link
Reference in a new issue