Mixed progress
- point tagging - extends clauses for drier config - classic/uniform support - mx/choc spacing support - intersect outlines - per-key footprint customization
This commit is contained in:
parent
55d60ba599
commit
c3d7643371
6 changed files with 305 additions and 141 deletions
36
README.md
36
README.md
|
@ -324,19 +324,21 @@ This is where the following section comes into play:
|
|||
|
||||
```yaml
|
||||
glue:
|
||||
top:
|
||||
left: <anchor>
|
||||
right: <anchor> | num
|
||||
bottom:
|
||||
left: <anchor>
|
||||
right: <anchor> | num
|
||||
waypoints:
|
||||
- percent: num
|
||||
width: num | [num_left, num_right]
|
||||
- ...
|
||||
extra:
|
||||
- <primitive shape>
|
||||
- ...
|
||||
glue_name:
|
||||
top:
|
||||
left: <anchor>
|
||||
right: <anchor> | num
|
||||
bottom:
|
||||
left: <anchor>
|
||||
right: <anchor> | num
|
||||
waypoints:
|
||||
- percent: num
|
||||
width: num | [num_left, num_right]
|
||||
- ...
|
||||
extra:
|
||||
- <primitive shape>
|
||||
- ...
|
||||
...
|
||||
```
|
||||
|
||||
...where an `<anchor>` is (mostly) the same as it was for points:
|
||||
|
@ -348,7 +350,7 @@ rotate: num # default = 0
|
|||
relative: boolean # default = true
|
||||
```
|
||||
|
||||
The section's `top` and `bottom` are both formatted the same, and describe the center line's top and bottom intersections, respectively.
|
||||
The `top` and `bottom` fields in each glue's section are both formatted the same, and describe the center line's top and bottom intersections, respectively.
|
||||
In a one-piece case, this means that we project a line from a left-side reference point (optionally rotated and translated), another from the right, and converge them to where they meet.
|
||||
Split designs can specify `right` as a single number to mean the x coordinate where the side should be "cut off".
|
||||
The `relative` flag means that the `shift` is interpreted in layout size units instead of mms (see below).
|
||||
|
@ -366,7 +368,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.
|
||||
|
||||
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.
|
||||
These are then added to what we have so far to finish out the glue. TODO!
|
||||
|
||||
<hr />
|
||||
|
||||
|
@ -381,6 +383,8 @@ Now we can configure what we want to "export" as outlines from this phase, given
|
|||
- `middle` means an "ideal" version of the glue (meaning that instead of the `outline.glue` we defined above, we get `both` - `left` - `right`, so the _exact_ middle piece we would have needed to glue everything together
|
||||
- `both` means both sides, held together by the glue
|
||||
- `glue` is just the raw glue shape we defined above under `outline.glue`
|
||||
- `tag: <array of tags>` : optional tags to filter which points to consider in this step, where tags can be specified as key-level attributes.
|
||||
- `glue: <glue_name>` : the name of the glue to use, if applicable
|
||||
- `size: num | [num_x, num_y]` : the width/height of the rectangles to lay onto the points. Note that the `relative` flag for the glue declaration above meant this size as the basis of the shift. So during a `keys` layout with a size of 18, for example, a relative shift of `[.5, .5]` actually means `[9, 9]` in mms.
|
||||
- `corner: num # default = 0)` : corner radius of the rectangles
|
||||
- `bevel: num # default = 0)` : corner bevel of the rectangles, can be combined with rounding
|
||||
|
@ -395,7 +399,7 @@ Now we can configure what we want to "export" as outlines from this phase, given
|
|||
- `radius: num` : the radius of the circle
|
||||
- `polygon` : an independent polygon primitive. Parameters:
|
||||
- `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.
|
||||
- `outline` : a previously defined outline, see below.
|
||||
- `name: outline_name` : the name of the referenced outline
|
||||
|
||||
Using these, we define exports as follows:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const m = require('makerjs')
|
||||
const u = require('./utils')
|
||||
const Point = require('./point')
|
||||
|
||||
const assert = exports.assert = (exp, msg) => {
|
||||
|
@ -79,11 +80,53 @@ exports.anchor = (raw, name, points={}, check_unexpected=true, default_point=new
|
|||
point.shift(xyval, true)
|
||||
}
|
||||
if (raw.rotate !== undefined) {
|
||||
let rot = sane(raw.rotate || 0, name + '.rotate', 'number')
|
||||
if (point.meta.mirrored) {
|
||||
rot = -rot
|
||||
}
|
||||
point.r += rot
|
||||
point.r += sane(raw.rotate || 0, name + '.rotate', 'number')
|
||||
}
|
||||
return point
|
||||
}
|
||||
|
||||
const extend_pair = exports.extend_pair = (to, from) => {
|
||||
const to_type = type(to)
|
||||
const from_type = type(from)
|
||||
if (from === undefined || from === null) return to
|
||||
if (from === '!!unset') return undefined
|
||||
if (to_type != from_type) return from
|
||||
if (from_type == 'object') {
|
||||
const res = u.deepcopy(to)
|
||||
for (const key of Object.keys(from)) {
|
||||
res[key] = extend_pair(to[key], from[key])
|
||||
}
|
||||
return res
|
||||
} else if (from_type == 'array') {
|
||||
const res = u.deepcopy(to)
|
||||
for (const [i, val] of from.entries()) {
|
||||
res[i] = extend_pair(res[i], val)
|
||||
}
|
||||
return res
|
||||
} else return from
|
||||
}
|
||||
|
||||
exports.extend = (...args) => {
|
||||
let res = args[0]
|
||||
for (const arg of args) {
|
||||
if (res == arg) continue
|
||||
res = extend_pair(res, arg)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
const inherit = exports.inherit = (config, name_prefix, name, set) => {
|
||||
let result = u.deepcopy(config)
|
||||
if (config.extends !== undefined) {
|
||||
let list = config.extends
|
||||
if (type(list) !== 'array') list = [list]
|
||||
for (const item of list) {
|
||||
const other = set[item]
|
||||
assert(other, `Field "${name_prefix}.${name}" does not name a valid target!`)
|
||||
result = extend_pair(inherit(other, name_prefix, config.extends, set), result)
|
||||
|
||||
}
|
||||
delete result.extends
|
||||
}
|
||||
return result
|
||||
}
|
|
@ -35,27 +35,32 @@ const layout = exports._layout = (config = {}, points = {}) => {
|
|||
|
||||
// Glue config sanitization
|
||||
|
||||
a.detect_unexpected(config, 'outline.glue', ['top', 'bottom', 'waypoints', 'extra'])
|
||||
|
||||
const parsed_glue = u.deepcopy(a.sane(config, 'outline.glue', 'object'))
|
||||
for (let [gkey, gval] of Object.entries(parsed_glue)) {
|
||||
gval = a.inherit(gval, 'outline.glue', gkey, config)
|
||||
a.detect_unexpected(gval, `outline.glue.${gkey}`, ['top', 'bottom', 'waypoints', 'extra'])
|
||||
|
||||
|
||||
for (const y of ['top', 'bottom']) {
|
||||
a.detect_unexpected(config[y], `outline.glue.${y}`, ['left', 'right'])
|
||||
config[y].left = relative_anchor(config[y].left, `outline.glue.${y}.left`, points)
|
||||
if (a.type(config[y].right) != 'number') {
|
||||
config[y].right = relative_anchor(config[y].right, `outline.glue.${y}.right`, points)
|
||||
for (const y of ['top', 'bottom']) {
|
||||
a.detect_unexpected(gval[y], `outline.glue.${gkey}.${y}`, ['left', 'right'])
|
||||
gval[y].left = relative_anchor(gval[y].left, `outline.glue.${gkey}.${y}.left`, points)
|
||||
if (a.type(gval[y].right) != 'number') {
|
||||
gval[y].right = relative_anchor(gval[y].right, `outline.glue.${gkey}.${y}.right`, points)
|
||||
}
|
||||
}
|
||||
|
||||
gval.waypoints = a.sane(gval.waypoints || [], `outline.glue.${gkey}.waypoints`, 'array')
|
||||
let wi = 0
|
||||
gval.waypoints = gval.waypoints.map(w => {
|
||||
const name = `outline.glue.${gkey}.waypoints[${++wi}]`
|
||||
a.detect_unexpected(w, name, ['percent', 'width'])
|
||||
w.percent = a.sane(w.percent, name + '.percent', 'number')
|
||||
w.width = a.wh(w.width, name + '.width')
|
||||
return w
|
||||
})
|
||||
|
||||
parsed_glue[gkey] = gval
|
||||
}
|
||||
|
||||
config.waypoints = a.sane(config.waypoints || [], 'outline.glue.waypoints', 'array')
|
||||
let wi = 0
|
||||
config.waypoints = config.waypoints.map(w => {
|
||||
const name = `outline.glue.waypoints[${++wi}]`
|
||||
a.detect_unexpected(w, name, ['percent', 'width'])
|
||||
w.percent = a.sane(w.percent, name + '.percent', 'number')
|
||||
w.width = a.wh(w.width, name + '.width')
|
||||
return w
|
||||
})
|
||||
|
||||
// TODO: handle glue.extra (or revoke it from the docs)
|
||||
|
||||
|
@ -63,8 +68,12 @@ const layout = exports._layout = (config = {}, points = {}) => {
|
|||
|
||||
// Layout params sanitization
|
||||
|
||||
a.detect_unexpected(params, `${export_name}`, expected.concat(['side', 'size', 'corner', 'bevel', 'bound']))
|
||||
a.detect_unexpected(params, `${export_name}`, expected.concat(['side', 'tags', 'glue', 'size', 'corner', 'bevel', 'bound']))
|
||||
const side = a.in(params.side, `${export_name}.side`, ['left', 'right', 'middle', 'both', 'glue'])
|
||||
const tags = a.sane(params.tags || [], `${export_name}.tags`, 'array')
|
||||
const default_glue_name = Object.keys(parsed_glue)[0]
|
||||
const glue_def = parsed_glue[a.sane(params.glue || default_glue_name, `${export_name}.glue`, 'string')]
|
||||
a.assert(glue_def, `Field "${export_name}.glue" does not name a valid 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')
|
||||
|
@ -77,6 +86,14 @@ const layout = exports._layout = (config = {}, points = {}) => {
|
|||
if (['left', 'right', 'middle', 'both'].includes(side)) {
|
||||
for (const [pname, p] of Object.entries(points)) {
|
||||
|
||||
// filter by tags, if necessary
|
||||
if (tags.length) {
|
||||
const source = p.meta.tags || {}
|
||||
const point_tags = Object.keys(source).filter(t => !!source[t])
|
||||
const relevant = point_tags.some(pt => tags.includes(pt))
|
||||
if (!relevant) continue
|
||||
}
|
||||
|
||||
let from_x = -size[0] / 2, to_x = size[0] / 2
|
||||
let from_y = -size[1] / 2, to_y = size[1] / 2
|
||||
|
||||
|
@ -130,15 +147,15 @@ const layout = exports._layout = (config = {}, points = {}) => {
|
|||
|
||||
return u.line(from.p, to.p)
|
||||
}
|
||||
|
||||
const tll = get_line(config.top.left)
|
||||
const trl = get_line(config.top.right)
|
||||
|
||||
const tll = get_line(glue_def.top.left)
|
||||
const trl = get_line(glue_def.top.right)
|
||||
const tip = m.path.converge(tll, trl)
|
||||
const tlp = u.eq(tll.origin, tip) ? tll.end : tll.origin
|
||||
const trp = u.eq(trl.origin, tip) ? trl.end : trl.origin
|
||||
|
||||
const bll = get_line(config.bottom.left)
|
||||
const brl = get_line(config.bottom.right)
|
||||
const bll = get_line(glue_def.bottom.left)
|
||||
const brl = get_line(glue_def.bottom.right)
|
||||
const bip = m.path.converge(bll, brl)
|
||||
const blp = u.eq(bll.origin, bip) ? bll.end : bll.origin
|
||||
const brp = u.eq(brl.origin, bip) ? brl.end : brl.origin
|
||||
|
@ -146,7 +163,7 @@ const layout = exports._layout = (config = {}, points = {}) => {
|
|||
const left_waypoints = []
|
||||
const right_waypoints = []
|
||||
|
||||
for (const w of config.waypoints) {
|
||||
for (const w of glue_def.waypoints) {
|
||||
const percent = w.percent / 100
|
||||
const center_x = tip[0] + percent * (bip[0] - tip[0])
|
||||
const center_y = tip[1] + percent * (bip[1] - tip[1])
|
||||
|
@ -157,7 +174,7 @@ const layout = exports._layout = (config = {}, points = {}) => {
|
|||
}
|
||||
|
||||
let waypoints
|
||||
const is_split = a.type(config.top.right) == 'number'
|
||||
const is_split = a.type(glue_def.top.right) == 'number'
|
||||
if (is_split) {
|
||||
waypoints = [tip, tlp]
|
||||
.concat(left_waypoints)
|
||||
|
@ -198,7 +215,7 @@ exports.parse = (config = {}, points = {}) => {
|
|||
for (const part of parts) {
|
||||
const name = `outline.exports.${key}[${++index}]`
|
||||
const expected = ['type', 'operation']
|
||||
part.type = a.in(part.type, `${name}.type`, ['keys', 'rectangle', 'circle', 'polygon', 'ref'])
|
||||
part.type = a.in(part.type, `${name}.type`, ['keys', 'rectangle', 'circle', 'polygon', 'outline'])
|
||||
part.operation = a.in(part.operation || 'add', `${name}.operation`, ['add', 'subtract', 'intersect', 'stack'])
|
||||
|
||||
let op = u.union
|
||||
|
@ -240,10 +257,12 @@ exports.parse = (config = {}, points = {}) => {
|
|||
}
|
||||
arg = u.poly(parsed_points)
|
||||
break
|
||||
case 'ref':
|
||||
case 'outline':
|
||||
a.assert(outlines[part.name], `Field "${name}.name" does not name an existing outline!`)
|
||||
arg = u.deepcopy(outlines[part.name])
|
||||
break
|
||||
default:
|
||||
throw new Error(`Field "${name}.type" (${part.type}) does not name a valid outline part type!`)
|
||||
}
|
||||
|
||||
result = op(result, arg)
|
||||
|
|
|
@ -143,6 +143,8 @@ const makerjs2kicad = exports._makerjs2kicad = (model, layer='Edge.Cuts') => {
|
|||
|
||||
const footprint_types = require('./footprints')
|
||||
const footprint = exports._footprint = (config, name, points, net_indexer, point) => {
|
||||
|
||||
if (config === false) return ''
|
||||
|
||||
// config sanitization
|
||||
a.detect_unexpected(config, name, ['type', 'anchor', 'nets', 'params'])
|
||||
|
|
|
@ -2,35 +2,6 @@ const m = require('makerjs')
|
|||
const u = require('./utils')
|
||||
const a = require('./assert')
|
||||
|
||||
const extend_pair = exports._extend_pair = (to, from) => {
|
||||
const to_type = a.type(to)
|
||||
const from_type = a.type(from)
|
||||
if (from === undefined || from === null) return to
|
||||
if (to_type != from_type) return from
|
||||
if (from_type == 'object') {
|
||||
const res = u.deepcopy(to)
|
||||
for (const key of Object.keys(from)) {
|
||||
res[key] = extend_pair(to[key], from[key])
|
||||
}
|
||||
return res
|
||||
} else if (from_type == 'array') {
|
||||
const res = u.deepcopy(to)
|
||||
for (const [i, val] of from.entries()) {
|
||||
res[i] = extend_pair(res[i], val)
|
||||
}
|
||||
return res
|
||||
} else return from
|
||||
}
|
||||
|
||||
const extend = exports._extend = (...args) => {
|
||||
let res = args[0]
|
||||
for (const arg of args) {
|
||||
if (res == arg) continue
|
||||
res = extend_pair(res, arg)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
const push_rotation = exports._push_rotation = (list, angle, origin) => {
|
||||
let candidate = origin
|
||||
for (const r of list) {
|
||||
|
@ -139,7 +110,7 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key)
|
|||
asym: 'both'
|
||||
}
|
||||
for (const row of Object.keys(actual_rows)) {
|
||||
const key = extend(
|
||||
const key = a.extend(
|
||||
default_key,
|
||||
global_key,
|
||||
zone_wide_key,
|
||||
|
@ -148,7 +119,8 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key)
|
|||
col.rows[row] || {}
|
||||
)
|
||||
|
||||
key.name = key.name || `${col_name}_${row}`
|
||||
key.name = key.name || `${zone_name}_${col_name}_${row}`
|
||||
key.colrow = `${col_name}_${row}`
|
||||
key.shift = a.xy(key.shift, `${key.name}.shift`)
|
||||
key.rotate = a.sane(key.rotate, `${key.name}.rotate`, 'number')
|
||||
key.padding = a.sane(key.padding, `${key.name}.padding`, 'number')
|
||||
|
@ -195,8 +167,6 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key)
|
|||
return points
|
||||
}
|
||||
|
||||
|
||||
|
||||
exports.parse = (config = {}) => {
|
||||
|
||||
a.detect_unexpected(config, 'points', ['zones', 'key', 'rotate', 'mirror'])
|
||||
|
@ -207,7 +177,11 @@ exports.parse = (config = {}) => {
|
|||
|
||||
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)) {
|
||||
for (let [zone_name, zone] of Object.entries(zones)) {
|
||||
|
||||
// handle zone-level `extends` clauses
|
||||
zone = a.inherit(zone, 'points.zones', zone_name, zones)
|
||||
|
||||
const anchor = a.anchor(zone.anchor || {}, `points.zones.${zone_name}.anchor`, points)
|
||||
points = Object.assign(points, render_zone(zone_name, zone, anchor, global_key))
|
||||
}
|
||||
|
@ -238,9 +212,11 @@ exports.parse = (config = {}) => {
|
|||
for (const [name, p] of Object.entries(points)) {
|
||||
if (p.meta.asym == 'left') continue
|
||||
const mp = p.clone().mirror(axis)
|
||||
mp.meta = extend(mp.meta, mp.meta.mirror || {})
|
||||
mp.meta = a.extend(mp.meta, mp.meta.mirror || {})
|
||||
mp.meta.mirrored = true
|
||||
mirrored_points[`mirror_${name}`] = mp
|
||||
const new_name = `mirror_${name}`
|
||||
mp.meta.name = new_name
|
||||
mirrored_points[new_name] = mp
|
||||
if (p.meta.asym == 'right') {
|
||||
p.meta.skip = true
|
||||
}
|
||||
|
|
234
test/fixtures/absolem.yaml
vendored
234
test/fixtures/absolem.yaml
vendored
|
@ -10,9 +10,9 @@ points:
|
|||
rows:
|
||||
bottom:
|
||||
home:
|
||||
bind: [,10]
|
||||
bind: [,15]
|
||||
top:
|
||||
bind: [,10]
|
||||
bind: [,15]
|
||||
key:
|
||||
column_net: P1
|
||||
ring:
|
||||
|
@ -61,21 +61,35 @@ points:
|
|||
rows:
|
||||
bottom:
|
||||
bind: [10]
|
||||
row_net: P7
|
||||
row_net: P16
|
||||
mirror:
|
||||
row_net: P16
|
||||
row_net: P7
|
||||
home:
|
||||
bind: [10]
|
||||
row_net: P6
|
||||
row_net: P14
|
||||
mirror:
|
||||
row_net: P14
|
||||
row_net: P6
|
||||
top:
|
||||
row_net: P5
|
||||
row_net: P15
|
||||
mirror:
|
||||
row_net: P15
|
||||
row_net: P5
|
||||
key:
|
||||
tags:
|
||||
s19: true
|
||||
choc:
|
||||
extends: matrix
|
||||
columns:
|
||||
pinky:
|
||||
stagger: 1
|
||||
origin: [7, -8]
|
||||
key:
|
||||
padding: 18
|
||||
tags:
|
||||
s19: false
|
||||
s18: true
|
||||
thumbfan:
|
||||
anchor:
|
||||
ref: inner_bottom
|
||||
ref: matrix_inner_bottom
|
||||
shift: [-7, -19]
|
||||
columns:
|
||||
near:
|
||||
|
@ -84,9 +98,11 @@ points:
|
|||
origin: [9.5, -9]
|
||||
rows:
|
||||
thumb:
|
||||
bind: [10,1,,]
|
||||
bind: [10,5,,]
|
||||
key:
|
||||
column_net: P2
|
||||
tags:
|
||||
classic: true
|
||||
home:
|
||||
spread: 21.25
|
||||
rotate: -28
|
||||
|
@ -96,17 +112,71 @@ points:
|
|||
bind: [,10,,15]
|
||||
key:
|
||||
column_net: P3
|
||||
tags:
|
||||
classic: true
|
||||
uniform: true
|
||||
far:
|
||||
rows:
|
||||
thumb:
|
||||
bind: [-1,,,5]
|
||||
key:
|
||||
column_net: P4
|
||||
tags:
|
||||
classic: true
|
||||
rows:
|
||||
thumb:
|
||||
row_net: P8
|
||||
row_net: P10
|
||||
mirror:
|
||||
row_net: P10
|
||||
row_net: P8
|
||||
unifar:
|
||||
anchor:
|
||||
ref: thumbfan_home_thumb
|
||||
columns:
|
||||
home_again:
|
||||
rotate: -28
|
||||
origin: [9.5, -9]
|
||||
key:
|
||||
skip: true
|
||||
far1u:
|
||||
rows:
|
||||
thumb:
|
||||
bind: [-1,,,5]
|
||||
key:
|
||||
column_net: P4
|
||||
footprints:
|
||||
diode: false
|
||||
tags:
|
||||
uniform: true
|
||||
rows:
|
||||
thumb:
|
||||
row_net: P10
|
||||
mirror:
|
||||
row_net: P8
|
||||
uninear:
|
||||
anchor:
|
||||
ref: thumbfan_home_thumb
|
||||
columns:
|
||||
home_again:
|
||||
spread: -19
|
||||
rotate: 28
|
||||
origin: [-9.5, -9]
|
||||
key:
|
||||
skip: true
|
||||
near1u:
|
||||
rows:
|
||||
thumb:
|
||||
bind: [10,5,,]
|
||||
key:
|
||||
column_net: P2
|
||||
footprints:
|
||||
diode: false
|
||||
tags:
|
||||
uniform: true
|
||||
rows:
|
||||
thumb:
|
||||
row_net: P10
|
||||
mirror:
|
||||
row_net: P8
|
||||
key:
|
||||
bind: [0,0,0,0]
|
||||
footprints:
|
||||
|
@ -114,95 +184,145 @@ points:
|
|||
type: mx
|
||||
nets:
|
||||
from: '!column_net'
|
||||
to: '!name'
|
||||
to: '!colrow'
|
||||
diode:
|
||||
type: diode
|
||||
anchor:
|
||||
rotate: 90
|
||||
shift: [-8, 0]
|
||||
shift: [8, 0]
|
||||
nets:
|
||||
from: '!name'
|
||||
to: '!row_net'
|
||||
mirror:
|
||||
footprints:
|
||||
mx:
|
||||
nets:
|
||||
from: '!colrow'
|
||||
to: '!column_net'
|
||||
rotate: -20
|
||||
mirror:
|
||||
ref: pinky_home
|
||||
ref: matrix_pinky_home
|
||||
distance: 223.7529778
|
||||
outline:
|
||||
glue:
|
||||
top:
|
||||
left:
|
||||
ref: inner_top
|
||||
shift: [, 0.5]
|
||||
right:
|
||||
ref: mirror_inner_top
|
||||
shift: [, 0.5]
|
||||
bottom:
|
||||
left:
|
||||
ref: far_thumb
|
||||
shift: [0.5, 0]
|
||||
rotate: 90
|
||||
right:
|
||||
ref: mirror_far_thumb
|
||||
shift: [0.5, 0]
|
||||
rotate: 90
|
||||
waypoints:
|
||||
- percent: 50
|
||||
width: 50
|
||||
- percent: 90
|
||||
width: 25
|
||||
classic:
|
||||
top:
|
||||
left:
|
||||
ref: matrix_inner_top
|
||||
shift: [, 0.5]
|
||||
right:
|
||||
ref: mirror_matrix_inner_top
|
||||
shift: [, 0.5]
|
||||
bottom:
|
||||
left:
|
||||
ref: thumbfan_far_thumb
|
||||
shift: [0.5, 0]
|
||||
rotate: 90
|
||||
right:
|
||||
ref: mirror_thumbfan_far_thumb
|
||||
shift: [0.5, 0]
|
||||
rotate: 90
|
||||
waypoints:
|
||||
- percent: 50
|
||||
width: 50
|
||||
- percent: 90
|
||||
width: 25
|
||||
uniform:
|
||||
extends: classic
|
||||
bottom:
|
||||
left:
|
||||
ref: unifar_far1u_thumb
|
||||
right:
|
||||
ref: mirror_unifar_far1u_thumb
|
||||
choc:
|
||||
extends: classic
|
||||
top:
|
||||
left:
|
||||
ref: choc_inner_top
|
||||
right:
|
||||
ref: mirror_choc_inner_top
|
||||
uniform_choc:
|
||||
extends:
|
||||
- uniform
|
||||
- choc
|
||||
exports:
|
||||
outline:
|
||||
classic_outline:
|
||||
- type: keys
|
||||
side: both
|
||||
size: 18
|
||||
tags:
|
||||
- s19
|
||||
- classic
|
||||
glue: classic
|
||||
size: 13.5
|
||||
corner: .5
|
||||
holes:
|
||||
uniform_outline:
|
||||
- type: keys
|
||||
operation: stack
|
||||
side: both
|
||||
tags:
|
||||
- s19
|
||||
- uniform
|
||||
glue: uniform
|
||||
size: 13.5
|
||||
corner: .5
|
||||
intersected_outline:
|
||||
- type: outline
|
||||
name: classic_outline
|
||||
- type: outline
|
||||
name: uniform_outline
|
||||
operation: intersect
|
||||
classic_holes:
|
||||
- type: keys
|
||||
side: both
|
||||
tags:
|
||||
- s19
|
||||
- classic
|
||||
glue: classic
|
||||
size: 14
|
||||
bound: false
|
||||
middle:
|
||||
classic_middle:
|
||||
- type: keys
|
||||
operation: stack
|
||||
side: middle
|
||||
tags:
|
||||
- s19
|
||||
- classic
|
||||
glue: classic
|
||||
size: 24
|
||||
- type: rectangle
|
||||
size: [25, 5]
|
||||
ref: home_thumb
|
||||
ref: thumbfan_home_thumb
|
||||
shift: [0, 12]
|
||||
- type: rectangle
|
||||
size: [25, 5]
|
||||
ref: far_thumb
|
||||
ref: thumbfan_far_thumb
|
||||
shift: [25, 12]
|
||||
- type: rectangle
|
||||
size: [25, 5]
|
||||
ref: mirror_home_thumb
|
||||
ref: mirror_thumbfan_home_thumb
|
||||
shift: [25, 12]
|
||||
- type: rectangle
|
||||
size: [25, 5]
|
||||
ref: mirror_far_thumb
|
||||
ref: mirror_thumbfan_far_thumb
|
||||
shift: [0, 12]
|
||||
- type: ref
|
||||
name: outline
|
||||
- type: outline
|
||||
name: classic_outline
|
||||
operation: intersect
|
||||
complex:
|
||||
- type: ref
|
||||
name: outline
|
||||
- type: ref
|
||||
name: holes
|
||||
- type: outline
|
||||
name: classic_outline
|
||||
- type: outline
|
||||
name: classic_holes
|
||||
operation: stack
|
||||
- type: ref
|
||||
name: middle
|
||||
- type: outline
|
||||
name: classic_middle
|
||||
operation: stack
|
||||
pcb:
|
||||
edge: outline
|
||||
edge: intersected_outline
|
||||
footprints:
|
||||
mcu:
|
||||
type: promicro
|
||||
anchor:
|
||||
ref:
|
||||
- inner_top
|
||||
- mirror_inner_top
|
||||
- choc_inner_top
|
||||
- mirror_choc_inner_top
|
||||
shift: [0, -20]
|
||||
rotate: 270
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue