Refactor, units, tests
This commit is contained in:
parent
519c34bc60
commit
cd90705ba1
24 changed files with 1221 additions and 1222 deletions
55
package-lock.json
generated
55
package-lock.json
generated
|
@ -604,6 +604,11 @@
|
|||
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
|
||||
"dev": true
|
||||
},
|
||||
"complex.js": {
|
||||
"version": "2.0.11",
|
||||
"resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.0.11.tgz",
|
||||
"integrity": "sha512-6IArJLApNtdg1P1dFtn3dnyzoZBEF0MwMnrfF1exSBRpZYoy4yieMkpZhQDC0uwctw48vii0CFVyHfpgZ/DfGw=="
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
|
@ -644,6 +649,11 @@
|
|||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
|
||||
},
|
||||
"decimal.js": {
|
||||
"version": "10.2.1",
|
||||
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz",
|
||||
"integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw=="
|
||||
},
|
||||
"deep-eql": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
|
||||
|
@ -739,6 +749,11 @@
|
|||
"integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
|
||||
"dev": true
|
||||
},
|
||||
"escape-latex": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz",
|
||||
"integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw=="
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
|
@ -804,6 +819,11 @@
|
|||
"signal-exit": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"fraction.js": {
|
||||
"version": "4.0.13",
|
||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.0.13.tgz",
|
||||
"integrity": "sha512-E1fz2Xs9ltlUp+qbiyx9wmt2n9dRzPsS11Jtdb8D2o+cC7wr9xkkKsVKJuBX0ST+LVS+LhLO+SbLJNtfWcJvXA=="
|
||||
},
|
||||
"fromentries": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.0.tgz",
|
||||
|
@ -1226,6 +1246,11 @@
|
|||
"iterate-iterator": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"javascript-natural-sort": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
|
||||
"integrity": "sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k="
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
|
@ -1344,6 +1369,21 @@
|
|||
"kdbush": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"mathjs": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/mathjs/-/mathjs-8.1.1.tgz",
|
||||
"integrity": "sha512-b3TX3EgiZObujjwb8lZnTDLUuivC2jar4ZBjmGJ4stFYCDXx/DNwx5yry5t/z65p9mvejyZel1qoeR05KtChcQ==",
|
||||
"requires": {
|
||||
"complex.js": "^2.0.11",
|
||||
"decimal.js": "^10.2.1",
|
||||
"escape-latex": "^1.2.0",
|
||||
"fraction.js": "^4.0.13",
|
||||
"javascript-natural-sort": "^0.7.1",
|
||||
"seedrandom": "^3.0.5",
|
||||
"tiny-emitter": "^2.1.0",
|
||||
"typed-function": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
|
@ -1867,6 +1907,11 @@
|
|||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"dev": true
|
||||
},
|
||||
"seedrandom": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
|
||||
"integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg=="
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
|
@ -2017,6 +2062,11 @@
|
|||
"minimatch": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"tiny-emitter": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
|
||||
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
|
||||
},
|
||||
"to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
|
@ -2044,6 +2094,11 @@
|
|||
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
|
||||
"dev": true
|
||||
},
|
||||
"typed-function": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/typed-function/-/typed-function-2.0.0.tgz",
|
||||
"integrity": "sha512-Hhy1Iwo/e4AtLZNK10ewVVcP2UEs408DS35ubP825w/YgSBK1KVLwALvvIG4yX75QJrxjCpcWkzkVRB0BwwYlA=="
|
||||
},
|
||||
"typedarray-to-buffer": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
|
||||
|
|
|
@ -11,18 +11,20 @@
|
|||
"bin": "./src/cli.js",
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"test": "nyc --reporter=html --reporter=text mocha -r chai/register-should"
|
||||
"test": "nyc --reporter=html --reporter=text mocha -r chai/register-should test/unit/*.js test/complex/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs-extra": "^9.0.1",
|
||||
"js-yaml": "^3.14.0",
|
||||
"makerjs": "github:mrzealot/maker.js-dist",
|
||||
"mathjs": "^8.1.1",
|
||||
"yargs": "^15.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^13.0.2",
|
||||
"@rollup/plugin-replace": "^2.3.3",
|
||||
"chai": "^4.2.0",
|
||||
"glob": "^7.1.6",
|
||||
"mocha": "^8.1.3",
|
||||
"nyc": "^15.1.0",
|
||||
"rollup": "^2.22.1"
|
||||
|
@ -33,7 +35,8 @@
|
|||
"src/*.js"
|
||||
],
|
||||
"exclude": [
|
||||
"src/cli.js"
|
||||
"src/cli.js",
|
||||
"src/io.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
61
src/anchor.js
Normal file
61
src/anchor.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
const u = require('./utils')
|
||||
const a = require('./assert')
|
||||
const Point = require('./point')
|
||||
|
||||
const anchor = module.exports = (raw, name, points={}, check_unexpected=true, default_point=new Point()) => units => {
|
||||
if (a.type(raw) == 'array') {
|
||||
// recursive call with incremental default_point mods, according to `affect`s
|
||||
let current = () => default_point.clone()
|
||||
for (const step of raw) {
|
||||
current = anchor(step, name, points, check_unexpected, current(units))
|
||||
}
|
||||
return current
|
||||
}
|
||||
if (check_unexpected) a.detect_unexpected(raw, name, ['ref', 'orient', 'shift', 'rotate', 'affect'])
|
||||
let point = default_point.clone()
|
||||
if (raw.ref !== undefined) {
|
||||
if (a.type(raw.ref) == 'array') {
|
||||
// averaging multiple anchors
|
||||
let x = 0, y = 0, r = 0
|
||||
const len = raw.ref.length
|
||||
for (const ref of raw.ref) {
|
||||
a.assert(points[ref], `Unknown point reference "${ref}" in anchor "${name}"!`)
|
||||
const resolved = points[ref]
|
||||
x += resolved.x
|
||||
y += resolved.y
|
||||
r += resolved.r
|
||||
}
|
||||
point = new Point(x / len, y / len, r / len)
|
||||
} else {
|
||||
a.assert(points[raw.ref], `Unknown point reference "${raw.ref}" in anchor "${name}"!`)
|
||||
point = points[raw.ref].clone()
|
||||
}
|
||||
}
|
||||
if (raw.orient !== undefined) {
|
||||
point.r += a.sane(raw.orient || 0, `${name}.orient`, 'number')(units)
|
||||
}
|
||||
if (raw.shift !== undefined) {
|
||||
let xyval = a.wh(raw.shift || [0, 0], `${name}.shift`)(units)
|
||||
if (point.meta.mirrored) {
|
||||
xyval[0] = -xyval[0]
|
||||
}
|
||||
point.shift(xyval, true)
|
||||
}
|
||||
if (raw.rotate !== undefined) {
|
||||
point.r += a.sane(raw.rotate || 0, `${name}.rotate`, 'number')(units)
|
||||
}
|
||||
if (raw.affect !== undefined) {
|
||||
const candidate = point
|
||||
point = default_point.clone()
|
||||
const valid_affects = ['x', 'y', 'r']
|
||||
let affect = raw.affect || valid_affects
|
||||
if (a.type(affect) == 'string') affect = affect.split('')
|
||||
affect = a.strarr(affect, `${name}.affect`)
|
||||
let i = 0
|
||||
for (const a of affect) {
|
||||
a._in(a, `${name}.affect[${++i}]`, valid_affects)
|
||||
point[a] = candidate[a]
|
||||
}
|
||||
}
|
||||
return point
|
||||
}
|
170
src/assert.js
170
src/assert.js
|
@ -1,6 +1,11 @@
|
|||
const m = require('makerjs')
|
||||
const u = require('./utils')
|
||||
const Point = require('./point')
|
||||
const mathjs = require('mathjs')
|
||||
|
||||
const mathnum = exports.mathnum = raw => units => {
|
||||
return mathjs.evaluate(`${raw}`, units || {})
|
||||
}
|
||||
|
||||
const assert = exports.assert = (exp, msg) => {
|
||||
if (!exp) {
|
||||
|
@ -8,19 +13,24 @@ const assert = exports.assert = (exp, msg) => {
|
|||
}
|
||||
}
|
||||
|
||||
const type = exports.type = (val) => {
|
||||
const type = exports.type = val => units => {
|
||||
if (Array.isArray(val)) return 'array'
|
||||
if (val === null) return 'null'
|
||||
try {
|
||||
const num = mathnum(val)(units)
|
||||
if (typeof num === 'number') return 'number'
|
||||
} catch (err) {}
|
||||
return typeof val
|
||||
}
|
||||
|
||||
const sane = exports.sane = (val, name, _type) => {
|
||||
assert(type(val) == _type, `Field "${name}" should be of type ${_type}!`)
|
||||
const sane = exports.sane = (val, name, _type) => units => {
|
||||
assert(type(val)(units) == _type, `Field "${name}" should be of type ${_type}!`)
|
||||
if (_type == 'number') return mathnum(val)(units)
|
||||
return val
|
||||
}
|
||||
|
||||
const detect_unexpected = exports.detect_unexpected = (obj, name, expected) => {
|
||||
const sane_obj = sane(obj, name, 'object')
|
||||
const sane_obj = sane(obj, name, 'object')()
|
||||
for (const key of Object.keys(sane_obj)) {
|
||||
assert(expected.includes(key), `Unexpected key "${key}" within field "${name}"!`)
|
||||
}
|
||||
|
@ -31,155 +41,29 @@ const _in = exports.in = (raw, name, arr) => {
|
|||
return raw
|
||||
}
|
||||
|
||||
const arr = exports.arr = (raw, name, length, _type, _default) => {
|
||||
assert(type(raw) == 'array', `Field "${name}" should be an array!`)
|
||||
const arr = exports.arr = (raw, name, length, _type, _default) => units => {
|
||||
assert(type(raw)(units) == 'array', `Field "${name}" should be an array!`)
|
||||
assert(length == 0 || raw.length == length, `Field "${name}" should be an array of length ${length}!`)
|
||||
raw = raw.map(val => val || _default)
|
||||
raw.map(val => assert(type(val) == _type, `Field "${name}" should contain ${_type}s!`))
|
||||
raw.map(val => assert(type(val)(units) == _type, `Field "${name}" should contain ${_type}s!`))
|
||||
if (_type == 'number') {
|
||||
raw = raw.map(val => mathnum(val)(units))
|
||||
}
|
||||
return raw
|
||||
}
|
||||
|
||||
const numarr = exports.numarr = (raw, name, length) => arr(raw, name, length, 'number', 0)
|
||||
const strarr = exports.strarr = (raw, name) => arr(raw, name, 0, 'string', '')
|
||||
const numarr = exports.numarr = (raw, name, length) => units => arr(raw, name, length, 'number', 0)(units)
|
||||
const strarr = exports.strarr = (raw, name) => arr(raw, name, 0, 'string', '')()
|
||||
|
||||
const xy = exports.xy = (raw, name) => numarr(raw, name, 2)
|
||||
const xy = exports.xy = (raw, name) => units => numarr(raw, name, 2)(units)
|
||||
|
||||
const wh = exports.wh = (raw, name) => {
|
||||
const wh = exports.wh = (raw, name) => units => {
|
||||
if (!Array.isArray(raw)) raw = [raw, raw]
|
||||
return xy(raw, name)
|
||||
return xy(raw, name)(units)
|
||||
}
|
||||
|
||||
exports.trbl = (raw, name) => {
|
||||
exports.trbl = (raw, name) => units => {
|
||||
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)
|
||||
return numarr(raw, name, 4, 'number', 0)(units)
|
||||
}
|
||||
|
||||
const anchor = exports.anchor = (raw, name, points={}, check_unexpected=true, default_point=new Point()) => {
|
||||
if (type(raw) == 'array') {
|
||||
// recursive call with incremental default_point mods, according to `affect`s
|
||||
let current = default_point.clone()
|
||||
for (const step of raw) {
|
||||
current = anchor(step, name, points, check_unexpected, current)
|
||||
}
|
||||
return current
|
||||
}
|
||||
if (check_unexpected) detect_unexpected(raw, name, ['ref', 'orient', 'shift', 'rotate', 'affect'])
|
||||
let point = default_point.clone()
|
||||
if (raw.ref !== undefined) {
|
||||
if (type(raw.ref) == 'array') {
|
||||
// averaging multiple anchors
|
||||
let x = 0, y = 0, r = 0
|
||||
const len = raw.ref.length
|
||||
for (const ref of raw.ref) {
|
||||
assert(points[ref], `Unknown point reference "${ref}" in anchor "${name}"!`)
|
||||
const resolved = points[ref]
|
||||
x += resolved.x
|
||||
y += resolved.y
|
||||
r += resolved.r
|
||||
}
|
||||
point = new Point(x / len, y / len, r / len)
|
||||
} else {
|
||||
assert(points[raw.ref], `Unknown point reference "${raw.ref}" in anchor "${name}"!`)
|
||||
point = points[raw.ref].clone()
|
||||
}
|
||||
}
|
||||
if (raw.orient !== undefined) {
|
||||
point.r += sane(raw.orient || 0, `${name}.orient`, 'number')
|
||||
}
|
||||
if (raw.shift !== undefined) {
|
||||
let xyval = wh(raw.shift || [0, 0], `${name}.shift`)
|
||||
if (point.meta.mirrored) {
|
||||
xyval[0] = -xyval[0]
|
||||
}
|
||||
point.shift(xyval, true)
|
||||
}
|
||||
if (raw.rotate !== undefined) {
|
||||
point.r += sane(raw.rotate || 0, `${name}.rotate`, 'number')
|
||||
}
|
||||
if (raw.affect !== undefined) {
|
||||
const candidate = point
|
||||
point = default_point.clone()
|
||||
const valid_affects = ['x', 'y', 'r']
|
||||
let affect = raw.affect || valid_affects
|
||||
if (type(affect) == 'string') affect = affect.split('')
|
||||
affect = strarr(affect, `${name}.affect`)
|
||||
let i = 0
|
||||
for (const a of affect) {
|
||||
_in(a, `${name}.affect[${++i}]`, valid_affects)
|
||||
point[a] = candidate[a]
|
||||
}
|
||||
}
|
||||
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])
|
||||
if (res[key] === undefined) delete res[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 inherit = exports.inherit = (name_prefix, name, set) => {
|
||||
let result = u.deepcopy(set[name])
|
||||
if (result.extends !== undefined) {
|
||||
let candidates = [name]
|
||||
const list = []
|
||||
while (candidates.length) {
|
||||
const item = candidates.shift()
|
||||
const other = u.deepcopy(set[item])
|
||||
assert(other, `"${item}" (reached from "${name_prefix}.${name}.extends") does not name a valid target!`)
|
||||
let parents = other.extends || []
|
||||
if (type(parents) !== 'array') parents = [parents]
|
||||
candidates = candidates.concat(parents)
|
||||
delete other.extends
|
||||
list.unshift(other)
|
||||
}
|
||||
result = extend.apply(this, list)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const op_prefix = exports.op_prefix = str => {
|
||||
const suffix = str.slice(1)
|
||||
if (str.startsWith('+')) return {name: suffix, operation: 'add'}
|
||||
if (str.startsWith('-')) return {name: suffix, operation: 'subtract'}
|
||||
if (str.startsWith('~')) return {name: suffix, operation: 'intersect'}
|
||||
if (str.startsWith('^')) return {name: suffix, operation: 'stack'}
|
||||
return {name: str, operation: 'add'}
|
||||
}
|
||||
|
||||
exports.op_str = (str, choices={}, order=Object.keys(choices)) => {
|
||||
let res = op_prefix(str)
|
||||
for (const key of order) {
|
||||
if (choices[key].includes(res.name)) {
|
||||
res.type = key
|
||||
break
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
59
src/cli.js
59
src/cli.js
|
@ -9,12 +9,8 @@ const yargs = require('yargs')
|
|||
|
||||
// internals
|
||||
|
||||
const u = require('./utils')
|
||||
const io = require('./io')
|
||||
const points_lib = require('./points')
|
||||
const outlines_lib = require('./outlines')
|
||||
const pcbs_lib = require('./pcbs')
|
||||
const cases_lib = require('./cases')
|
||||
const ergogen = require('./ergogen')
|
||||
|
||||
// command line args
|
||||
|
||||
|
@ -47,6 +43,8 @@ const args = yargs
|
|||
if (args.clean) fs.removeSync(args.o)
|
||||
fs.mkdirpSync(args.o)
|
||||
|
||||
// config parsing
|
||||
|
||||
let config_text
|
||||
try {
|
||||
config_text = fs.readFileSync(args.c).toString()
|
||||
|
@ -62,45 +60,38 @@ try {
|
|||
} catch (err) {
|
||||
throw new Error(`Malformed input within "${args.c}": ${err}`)
|
||||
}
|
||||
config = u.expand_nested_keys(config)
|
||||
|
||||
// points
|
||||
// processing
|
||||
|
||||
const results = ergogen.process(config, args.debug, s => console.log(s))
|
||||
|
||||
// output
|
||||
|
||||
console.log('Writing output to disk...')
|
||||
|
||||
console.log('Parsing points...')
|
||||
const points = points_lib.parse(config.points)
|
||||
if (args.debug) {
|
||||
const points_demo = points_lib.visualize(points)
|
||||
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})
|
||||
io.dump_model(results.points.demo, path.join(args.o, 'points/demo'), args.debug)
|
||||
fs.writeJSONSync(path.join(args.o, 'points/data.json'), results.points.data, {spaces: 4})
|
||||
}
|
||||
|
||||
// outlines
|
||||
|
||||
console.log('Generating outlines...')
|
||||
const outlines = outlines_lib.parse(config.outlines || {}, points)
|
||||
for (const [name, outline] of Object.entries(outlines)) {
|
||||
if (!args.debug && name.startsWith('_')) continue
|
||||
for (const [name, outline] of Object.entries(results.outlines)) {
|
||||
io.dump_model(outline, path.join(args.o, `outlines/${name}`), args.debug)
|
||||
}
|
||||
|
||||
// pcbs
|
||||
// for (const [name, pcb] of Object.entries(results.pcbs)) {
|
||||
// const file = path.join(args.o, `pcbs/${name}.kicad_pcb`)
|
||||
// fs.mkdirpSync(path.dirname(file))
|
||||
// fs.writeFileSync(file, pcb)
|
||||
// }
|
||||
|
||||
console.log('Scaffolding PCBs...')
|
||||
const pcbs = pcbs_lib.parse(config.pcbs || {}, points, outlines)
|
||||
for (const [pcb_name, pcb_text] of Object.entries(pcbs)) {
|
||||
const pcb_file = path.join(args.o, `pcbs/${pcb_name}.kicad_pcb`)
|
||||
fs.mkdirpSync(path.dirname(pcb_file))
|
||||
fs.writeFileSync(pcb_file, pcb_text)
|
||||
}
|
||||
// for (const [name, _case] of Object.entries(results.cases)) {
|
||||
// const file = path.join(args.o, `cases/${name}.jscad`)
|
||||
// fs.mkdirpSync(path.dirname(file))
|
||||
// fs.writeFileSync(file, _case)
|
||||
// }
|
||||
|
||||
// cases
|
||||
|
||||
console.log('Extruding cases...')
|
||||
const cases = cases_lib.parse(config.cases || {}, outlines)
|
||||
for (const [case_name, case_text] of Object.entries(cases)) {
|
||||
const case_file = path.join(args.o, `cases/${case_name}.jscad`)
|
||||
fs.mkdirpSync(path.dirname(case_file))
|
||||
fs.writeFileSync(case_file, case_text)
|
||||
if (args.debug) {
|
||||
fs.writeJSONSync(path.join(args.o, 'results.json'), results, {spaces: 4})
|
||||
}
|
||||
|
||||
// goodbye
|
||||
|
|
|
@ -1,8 +1,54 @@
|
|||
const prepare = require('./prepare')
|
||||
const points_lib = require('./points')
|
||||
const outlines_lib = require('./outlines')
|
||||
const cases_lib = require('./cases')
|
||||
const pcbs_lib = require('./pcbs')
|
||||
|
||||
const noop = () => {}
|
||||
|
||||
module.exports = {
|
||||
utils: require('./utils'),
|
||||
points: require('./points'),
|
||||
outlines: require('./outlines'),
|
||||
cases: require('./cases'),
|
||||
pcbs: require('./pcbs'),
|
||||
version: '__ergogen_version'
|
||||
version: '__ergogen_version',
|
||||
process: (config, debug=false, logger=noop) => {
|
||||
|
||||
logger('Preparing input...')
|
||||
config = prepare.unnest(config)
|
||||
config = prepare.inherit(config)
|
||||
const results = {}
|
||||
|
||||
logger('Parsing points...')
|
||||
const [points, units] = points_lib.parse(config.points)
|
||||
if (debug) {
|
||||
results.points = {
|
||||
demo: points_lib.visualize(points),
|
||||
data: points,
|
||||
units: units
|
||||
}
|
||||
}
|
||||
|
||||
logger('Generating outlines...')
|
||||
const outlines = outlines_lib.parse(config.outlines || {}, points, units)
|
||||
results.outlines = {}
|
||||
for (const [name, outline] of Object.entries(outlines)) {
|
||||
if (!debug && name.startsWith('_')) continue
|
||||
results.outlines[name] = outline
|
||||
}
|
||||
|
||||
// logger('Extruding cases...')
|
||||
// const cases = cases_lib.parse(config.cases || {}, outlines, units)
|
||||
// results.cases = {}
|
||||
// for (const [case_name, case_text] of Object.entries(cases)) {
|
||||
// if (!debug && case_name.startsWith('_')) continue
|
||||
// results.cases[case_name] = case_text
|
||||
// }
|
||||
|
||||
// logger('Scaffolding PCBs...')
|
||||
// const pcbs = pcbs_lib.parse(config.pcbs || {}, points, outlines, units)
|
||||
// results.pcbs = {}
|
||||
// for (const [pcb_name, pcb_text] of Object.entries(pcbs)) {
|
||||
// if (!debug && pcb_name.startsWith('_')) continue
|
||||
// results.cases[pcb_name] = pcb_text
|
||||
// }
|
||||
|
||||
return results
|
||||
}
|
||||
}
|
19
src/operation.js
Normal file
19
src/operation.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
const op_prefix = exports.op_prefix = str => {
|
||||
const suffix = str.slice(1)
|
||||
if (str.startsWith('+')) return {name: suffix, operation: 'add'}
|
||||
if (str.startsWith('-')) return {name: suffix, operation: 'subtract'}
|
||||
if (str.startsWith('~')) return {name: suffix, operation: 'intersect'}
|
||||
if (str.startsWith('^')) return {name: suffix, operation: 'stack'}
|
||||
return {name: str, operation: 'add'}
|
||||
}
|
||||
|
||||
exports.operation = (str, choices={}, order=Object.keys(choices)) => {
|
||||
let res = op_prefix(str)
|
||||
for (const key of order) {
|
||||
if (choices[key].includes(res.name)) {
|
||||
res.type = key
|
||||
break
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
107
src/outlines.js
107
src/outlines.js
|
@ -1,7 +1,10 @@
|
|||
const m = require('makerjs')
|
||||
const u = require('./utils')
|
||||
const a = require('./assert')
|
||||
const o = require('./operation')
|
||||
const Point = require('./point')
|
||||
const prep = require('./prepare')
|
||||
const make_anchor = require('./anchor')
|
||||
|
||||
const rectangle = (w, h, corner, bevel, name='') => {
|
||||
const error = (dim, val) => `Rectangle for "${name}" isn't ${dim} enough for its corner and bevel (${val} - 2 * ${corner} - 2 * ${bevel} <= 0)!`
|
||||
|
@ -17,44 +20,29 @@ const rectangle = (w, h, corner, bevel, name='') => {
|
|||
return m.model.moveRelative(res, [corner + bevel, corner + bevel])
|
||||
}
|
||||
|
||||
const relative_anchor = (decl, name, points={}, check_unexpected=true, default_point=new Point()) => {
|
||||
decl.shift = a.wh(decl.shift || [0, 0], name + '.shift')
|
||||
const relative = a.sane(decl.relative === undefined ? true : decl.relative, `${name}.relative`, 'boolean')
|
||||
delete decl.relative
|
||||
if (relative) {
|
||||
return size => {
|
||||
const copy = u.deepcopy(decl)
|
||||
copy.shift = [copy.shift[0] * size[0], copy.shift[1] * size[1]]
|
||||
return a.anchor(copy, name, points, check_unexpected, default_point)
|
||||
}
|
||||
}
|
||||
return () => a.anchor(decl, name, points, check_unexpected, default_point)
|
||||
}
|
||||
|
||||
const layout = exports._layout = (config = {}, points = {}) => {
|
||||
const layout = exports._layout = (config = {}, points = {}, units = {}) => {
|
||||
|
||||
// Glue config sanitization
|
||||
|
||||
const parsed_glue = u.deepcopy(a.sane(config, 'outlines.glue', 'object'))
|
||||
const parsed_glue = u.deepcopy(a.sane(config, 'outlines.glue', 'object')())
|
||||
for (let [gkey, gval] of Object.entries(parsed_glue)) {
|
||||
gval = a.inherit('outlines.glue', gkey, config)
|
||||
a.detect_unexpected(gval, `outlines.glue.${gkey}`, ['top', 'bottom', 'waypoints', 'extra'])
|
||||
|
||||
for (const y of ['top', 'bottom']) {
|
||||
a.detect_unexpected(gval[y], `outlines.glue.${gkey}.${y}`, ['left', 'right'])
|
||||
gval[y].left = relative_anchor(gval[y].left, `outlines.glue.${gkey}.${y}.left`, points)
|
||||
if (a.type(gval[y].right) != 'number') {
|
||||
gval[y].right = relative_anchor(gval[y].right, `outlines.glue.${gkey}.${y}.right`, points)
|
||||
gval[y].left = make_anchor(gval[y].left, `outlines.glue.${gkey}.${y}.left`, points)
|
||||
if (a.type(gval[y].right)(units) != 'number') {
|
||||
gval[y].right = make_anchor(gval[y].right, `outlines.glue.${gkey}.${y}.right`, points)
|
||||
}
|
||||
}
|
||||
|
||||
gval.waypoints = a.sane(gval.waypoints || [], `outlines.glue.${gkey}.waypoints`, 'array')
|
||||
gval.waypoints = a.sane(gval.waypoints || [], `outlines.glue.${gkey}.waypoints`, 'array')(units)
|
||||
let wi = 0
|
||||
gval.waypoints = gval.waypoints.map(w => {
|
||||
const name = `outlines.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')
|
||||
w.percent = a.sane(w.percent, name + '.percent', 'number')(units)
|
||||
w.width = a.wh(w.width, name + '.width')(units)
|
||||
return w
|
||||
})
|
||||
|
||||
|
@ -69,12 +57,19 @@ const layout = exports._layout = (config = {}, points = {}) => {
|
|||
// Layout params sanitization
|
||||
|
||||
a.detect_unexpected(params, `${export_name}`, expected.concat(['side', 'tags', 'glue', 'size', 'corner', 'bevel', 'bound']))
|
||||
const size = a.wh(params.size, `${export_name}.size`)(units)
|
||||
const relative_units = prep.extend({
|
||||
sx: size[0],
|
||||
sy: size[1]
|
||||
}, units)
|
||||
|
||||
|
||||
|
||||
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 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')
|
||||
const bound = a.sane(params.bound === undefined ? true : params.bound, `${export_name}.bound`, 'boolean')
|
||||
const tags = a.sane(params.tags || [], `${export_name}.tags`, 'array')()
|
||||
const corner = a.sane(params.corner || 0, `${export_name}.corner`, 'number')(relative_units)
|
||||
const bevel = a.sane(params.bevel || 0, `${export_name}.bevel`, 'number')(relative_units)
|
||||
const bound = a.sane(params.bound === undefined ? true : params.bound, `${export_name}.bound`, 'boolean')()
|
||||
|
||||
// Actual layout
|
||||
|
||||
|
@ -100,7 +95,7 @@ const layout = exports._layout = (config = {}, points = {}) => {
|
|||
|
||||
// extra binding "material", if necessary
|
||||
if (bound) {
|
||||
let bind = a.trbl(p.meta.bind || 0, `${pname}.bind`)
|
||||
let bind = a.trbl(p.meta.bind || 0, `${pname}.bind`)(relative_units)
|
||||
// if it's a mirrored key, we swap the left and right bind values
|
||||
if (p.meta.mirrored) {
|
||||
bind = [bind[0], bind[3], bind[2], bind[1]]
|
||||
|
@ -133,18 +128,17 @@ const layout = exports._layout = (config = {}, points = {}) => {
|
|||
if (bound && ['middle', 'both', 'glue'].includes(side)) {
|
||||
|
||||
const default_glue_name = Object.keys(parsed_glue)[0]
|
||||
const computed_glue_name = a.sane(params.glue || default_glue_name, `${export_name}.glue`, 'string')
|
||||
const computed_glue_name = a.sane(params.glue || default_glue_name, `${export_name}.glue`, 'string')()
|
||||
const glue_def = parsed_glue[computed_glue_name]
|
||||
a.assert(glue_def, `Field "${export_name}.glue" does not name a valid glue!`)
|
||||
|
||||
const get_line = (anchor) => {
|
||||
if (a.type(anchor) == 'number') {
|
||||
if (a.type(anchor)(relative_units) == 'number') {
|
||||
return u.line([anchor, -1000], [anchor, 1000])
|
||||
}
|
||||
|
||||
// if it wasn't a number, then it's a function returning an achor
|
||||
// have to feed it `size` first in case it's relative
|
||||
const from = anchor(size).clone()
|
||||
// if it wasn't a number, then it's a (possibly relative) achor
|
||||
const from = anchor(relative_units).clone()
|
||||
const to = from.clone().shift([from.meta.mirrored ? -1 : 1, 0])
|
||||
|
||||
return u.line(from.p, to.p)
|
||||
|
@ -182,7 +176,7 @@ const layout = exports._layout = (config = {}, points = {}) => {
|
|||
}
|
||||
|
||||
let waypoints
|
||||
const is_split = a.type(glue_def.top.right) == 'number'
|
||||
const is_split = a.type(glue_def.top.right)(relative_units) == 'number'
|
||||
if (is_split) {
|
||||
waypoints = [tip, tlp]
|
||||
.concat(left_waypoints)
|
||||
|
@ -210,24 +204,23 @@ const layout = exports._layout = (config = {}, points = {}) => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.parse = (config = {}, points = {}) => {
|
||||
exports.parse = (config = {}, points = {}, units = {}) => {
|
||||
a.detect_unexpected(config, 'outline', ['glue', 'exports'])
|
||||
const layout_fn = layout(config.glue, points)
|
||||
const layout_fn = layout(config.glue, points, units)
|
||||
|
||||
const outlines = {}
|
||||
|
||||
const ex = a.sane(config.exports || {}, 'outlines.exports', 'object')
|
||||
const ex = a.sane(config.exports || {}, 'outlines.exports', 'object')()
|
||||
for (let [key, parts] of Object.entries(ex)) {
|
||||
parts = a.inherit('outlines.exports', key, ex)
|
||||
if (a.type(parts) == 'array') {
|
||||
if (a.type(parts)() == 'array') {
|
||||
parts = {...parts}
|
||||
}
|
||||
parts = a.sane(parts, `outlines.exports.${key}`, 'object')
|
||||
parts = a.sane(parts, `outlines.exports.${key}`, 'object')()
|
||||
let result = {models: {}}
|
||||
for (let [part_name, part] of Object.entries(parts)) {
|
||||
const name = `outlines.exports.${key}.${part_name}`
|
||||
if (a.type(part) == 'string') {
|
||||
part = a.op_str(part, {outline: Object.keys(outlines)})
|
||||
if (a.type(part)() == 'string') {
|
||||
part = o.operation(part, {outline: Object.keys(outlines)})
|
||||
}
|
||||
const expected = ['type', 'operation']
|
||||
part.type = a.in(part.type || 'outline', `${name}.type`, ['keys', 'rectangle', 'circle', 'polygon', 'outline'])
|
||||
|
@ -246,45 +239,49 @@ exports.parse = (config = {}, points = {}) => {
|
|||
break
|
||||
case 'rectangle':
|
||||
a.detect_unexpected(part, name, expected.concat(['ref', 'shift', 'rotate', 'size', 'corner', 'bevel', 'mirror']))
|
||||
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')
|
||||
const rect_mirror = a.sane(part.mirror || false, `${name}.mirror`, 'boolean')
|
||||
const size = a.wh(part.size, `${name}.size`)(units)
|
||||
const rec_units = prep.extend({
|
||||
sx: size[0],
|
||||
sy: size[1]
|
||||
}, units)
|
||||
anchor = a.anchor(part, name, points, false)(rec_units)
|
||||
const corner = a.sane(part.corner || 0, `${name}.corner`, 'number')(rec_units)
|
||||
const bevel = a.sane(part.bevel || 0, `${name}.bevel`, 'number')(rec_units)
|
||||
const rect_mirror = a.sane(part.mirror || false, `${name}.mirror`, 'boolean')()
|
||||
const rect = rectangle(size[0], size[1], corner, bevel, name)
|
||||
arg = anchor.position(u.deepcopy(rect))
|
||||
if (rect_mirror) {
|
||||
const mirror_part = u.deepcopy(part)
|
||||
a.assert(mirror_part.ref, `Field "${name}.ref" must be speficied if mirroring is required!`)
|
||||
mirror_part.ref = `mirror_${mirror_part.ref}`
|
||||
anchor = a.anchor(mirror_part, name, points, false)
|
||||
anchor = make_anchor(mirror_part, name, points, false)(rec_units)
|
||||
const mirror_rect = m.model.moveRelative(u.deepcopy(rect), [-size[0], 0])
|
||||
arg = u.union(arg, anchor.position(mirror_rect))
|
||||
}
|
||||
break
|
||||
case 'circle':
|
||||
a.detect_unexpected(part, name, expected.concat(['ref', 'shift', 'rotate', 'radius', 'mirror']))
|
||||
anchor = a.anchor(part, name, points, false)
|
||||
const radius = a.sane(part.radius, `${name}.radius`, 'number')
|
||||
const circle_mirror = a.sane(part.mirror || false, `${name}.mirror`, 'boolean')
|
||||
anchor = make_anchor(part, name, points, false)(units)
|
||||
const radius = a.sane(part.radius, `${name}.radius`, 'number')(units)
|
||||
const circle_mirror = a.sane(part.mirror || false, `${name}.mirror`, 'boolean')()
|
||||
arg = u.circle(anchor.p, radius)
|
||||
if (circle_mirror) {
|
||||
const mirror_part = u.deepcopy(part)
|
||||
a.assert(mirror_part.ref, `Field "${name}.ref" must be speficied if mirroring is required!`)
|
||||
mirror_part.ref = `mirror_${mirror_part.ref}`
|
||||
anchor = a.anchor(mirror_part, name, points, false)
|
||||
anchor = make_anchor(mirror_part, name, points, false)(units)
|
||||
arg = u.union(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 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(poly_point, poly_name, points, true, last_anchor)
|
||||
const anchor = make_anchor(poly_point, poly_name, points, true, last_anchor)(units)
|
||||
parsed_points.push(anchor.p)
|
||||
}
|
||||
arg = u.poly(parsed_points)
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
const m = require('makerjs')
|
||||
const u = require('./utils')
|
||||
const a = require('./assert')
|
||||
const prep = require('./prepare')
|
||||
const make_anchor = require('./anchor')
|
||||
|
||||
const push_rotation = exports._push_rotation = (list, angle, origin) => {
|
||||
let candidate = origin
|
||||
|
@ -13,18 +15,18 @@ const push_rotation = exports._push_rotation = (list, angle, origin) => {
|
|||
})
|
||||
}
|
||||
|
||||
const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key) => {
|
||||
const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key, units) => {
|
||||
|
||||
// zone-wide sanitization
|
||||
|
||||
a.detect_unexpected(zone, `points.zones.${zone_name}`, ['columns', 'rows', 'key'])
|
||||
// the anchor comes from "above", because it needs other zones too (for references)
|
||||
const cols = a.sane(zone.columns || {}, `points.zones.${zone_name}.columns`, 'object')
|
||||
const zone_wide_rows = a.sane(zone.rows || {}, `points.zones.${zone_name}.rows`, 'object')
|
||||
const cols = a.sane(zone.columns || {}, `points.zones.${zone_name}.columns`, 'object')()
|
||||
const zone_wide_rows = a.sane(zone.rows || {}, `points.zones.${zone_name}.rows`, 'object')()
|
||||
for (const [key, val] of Object.entries(zone_wide_rows)) {
|
||||
zone_wide_rows[key] = a.sane(val || {}, `points.zones.${zone_name}.rows.${key}`, 'object')
|
||||
zone_wide_rows[key] = a.sane(val || {}, `points.zones.${zone_name}.rows.${key}`, 'object')()
|
||||
}
|
||||
const zone_wide_key = a.sane(zone.key || {}, `points.zones.${zone_name}.key`, 'object')
|
||||
const zone_wide_key = a.sane(zone.key || {}, `points.zones.${zone_name}.key`, 'object')()
|
||||
|
||||
// algorithm prep
|
||||
|
||||
|
@ -54,47 +56,47 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key)
|
|||
col.stagger || 0,
|
||||
`points.zones.${zone_name}.columns.${col_name}.stagger`,
|
||||
'number'
|
||||
)
|
||||
)(units)
|
||||
col.spread = a.sane(
|
||||
col.spread || (first_col ? 0 : 19),
|
||||
col.spread || (first_col ? 0 : 'u'),
|
||||
`points.zones.${zone_name}.columns.${col_name}.spread`,
|
||||
'number'
|
||||
)
|
||||
)(units)
|
||||
col.rotate = a.sane(
|
||||
col.rotate || 0,
|
||||
`points.zones.${zone_name}.columns.${col_name}.rotate`,
|
||||
'number'
|
||||
)
|
||||
)(units)
|
||||
col.origin = a.xy(
|
||||
col.origin || [0, 0],
|
||||
`points.zones.${zone_name}.columns.${col_name}.origin`,
|
||||
)
|
||||
`points.zones.${zone_name}.columns.${col_name}.origin`
|
||||
)(units)
|
||||
let override = false
|
||||
col.rows = a.sane(
|
||||
col.rows || {},
|
||||
`points.zones.${zone_name}.columns.${col_name}.rows`,
|
||||
'object'
|
||||
)
|
||||
)()
|
||||
if (col.row_overrides) {
|
||||
override = true
|
||||
col.rows = a.sane(
|
||||
col.row_overrides,
|
||||
`points.zones.${zone_name}.columns.${col_name}.row_overrides`,
|
||||
'object'
|
||||
)
|
||||
)()
|
||||
}
|
||||
for (const [key, val] of Object.entries(col.rows)) {
|
||||
col.rows[key] = a.sane(
|
||||
val || {},
|
||||
`points.zones.${zone_name}.columns.${col_name}.rows.${key}`,
|
||||
'object'
|
||||
)
|
||||
)()
|
||||
}
|
||||
col.key = a.sane(
|
||||
col.key || {},
|
||||
`points.zones.${zone_name}.columns.${col_name}.key`,
|
||||
'object'
|
||||
)
|
||||
)()
|
||||
|
||||
// propagating object key to name field
|
||||
|
||||
|
@ -104,7 +106,7 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key)
|
|||
// (while also handling potential overrides)
|
||||
|
||||
const actual_rows = override ? Object.keys(col.rows)
|
||||
: Object.keys(a.extend(zone_wide_rows, col.rows))
|
||||
: Object.keys(prep.extend(zone_wide_rows, col.rows))
|
||||
if (!actual_rows.length) {
|
||||
actual_rows.push('default')
|
||||
}
|
||||
|
@ -134,14 +136,14 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key)
|
|||
const default_key = {
|
||||
shift: [0, 0],
|
||||
rotate: 0,
|
||||
padding: 19,
|
||||
padding: 'u',
|
||||
width: 1,
|
||||
height: 1,
|
||||
skip: false,
|
||||
asym: 'both'
|
||||
}
|
||||
for (const row of actual_rows) {
|
||||
const key = a.extend(
|
||||
const key = prep.extend(
|
||||
default_key,
|
||||
global_key,
|
||||
zone_wide_key,
|
||||
|
@ -152,12 +154,12 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key)
|
|||
|
||||
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.width = a.sane(key.width, `${key.name}.width`, 'number')
|
||||
key.height = a.sane(key.height, `${key.name}.height`, 'number')
|
||||
key.padding = a.sane(key.padding, `${key.name}.padding`, 'number')
|
||||
key.skip = a.sane(key.skip, `${key.name}.skip`, 'boolean')
|
||||
key.shift = a.xy(key.shift, `${key.name}.shift`)(units)
|
||||
key.rotate = a.sane(key.rotate, `${key.name}.rotate`, 'number')(units)
|
||||
key.width = a.sane(key.width, `${key.name}.width`, 'number')(units)
|
||||
key.height = a.sane(key.height, `${key.name}.height`, 'number')(units)
|
||||
key.padding = a.sane(key.padding, `${key.name}.padding`, 'number')(units)
|
||||
key.skip = a.sane(key.skip, `${key.name}.skip`, 'boolean')()
|
||||
key.asym = a.in(key.asym, `${key.name}.asym`, ['left', 'right', 'both'])
|
||||
key.col = col
|
||||
key.row = row
|
||||
|
@ -184,12 +186,12 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key)
|
|||
return points
|
||||
}
|
||||
|
||||
const parse_axis = exports._parse_axis = (config, name, points) => {
|
||||
if (!['number', 'undefined'].includes(a.type(config))) {
|
||||
const mirror_obj = a.sane(config || {}, name, 'object')
|
||||
const distance = a.sane(mirror_obj.distance || 0, `${name}.distance`, 'number')
|
||||
const parse_axis = exports._parse_axis = (config, name, points, units) => {
|
||||
if (!['number', 'undefined'].includes(a.type(config)(units))) {
|
||||
const mirror_obj = a.sane(config || {}, name, 'object')()
|
||||
const distance = a.sane(mirror_obj.distance || 0, `${name}.distance`, 'number')(units)
|
||||
delete mirror_obj.distance
|
||||
let axis = a.anchor(mirror_obj, name, points).x
|
||||
let axis = make_anchor(mirror_obj, name, points)(units).x
|
||||
axis += distance / 2
|
||||
return axis
|
||||
} else return config
|
||||
|
@ -201,7 +203,7 @@ const perform_mirror = exports._perform_mirror = (point, axis) => {
|
|||
if (point.meta.asym == 'left') return ['', null]
|
||||
const mp = point.clone().mirror(axis)
|
||||
const mirrored_name = `mirror_${point.meta.name}`
|
||||
mp.meta = a.extend(mp.meta, mp.meta.mirror || {})
|
||||
mp.meta = prep.extend(mp.meta, mp.meta.mirror || {})
|
||||
mp.meta.name = mirrored_name
|
||||
mp.meta.colrow = `mirror_${mp.meta.colrow}`
|
||||
mp.meta.mirrored = true
|
||||
|
@ -215,32 +217,41 @@ const perform_mirror = exports._perform_mirror = (point, axis) => {
|
|||
|
||||
exports.parse = (config = {}) => {
|
||||
|
||||
// parsing units
|
||||
const raw_units = prep.extend({
|
||||
u: 19,
|
||||
cx: 18,
|
||||
cy: 17
|
||||
}, a.sane(config.units || {}, 'points.units', 'object')())
|
||||
const units = {}
|
||||
for (const [key, val] of Object.entries(raw_units)) {
|
||||
units[key] = a.mathnum(val)(units)
|
||||
}
|
||||
|
||||
// config sanitization
|
||||
a.detect_unexpected(config, 'points', ['zones', 'key', 'rotate', 'mirror'])
|
||||
const zones = a.sane(config.zones || {}, 'points.zones', 'object')
|
||||
const global_key = a.sane(config.key || {}, 'points.key', 'object')
|
||||
const global_rotate = a.sane(config.rotate || 0, 'points.rotate', 'number')
|
||||
a.detect_unexpected(config, 'points', ['units', 'zones', 'key', 'rotate', 'mirror'])
|
||||
const zones = a.sane(config.zones || {}, 'points.zones', 'object')()
|
||||
const global_key = a.sane(config.key || {}, 'points.key', 'object')()
|
||||
const global_rotate = a.sane(config.rotate || 0, 'points.rotate', 'number')(units)
|
||||
const global_mirror = config.mirror
|
||||
let points = {}
|
||||
let mirrored_points = {}
|
||||
let all_points = {}
|
||||
|
||||
|
||||
// rendering zones
|
||||
for (let [zone_name, zone] of Object.entries(zones)) {
|
||||
|
||||
// handle zone-level `extends` clauses
|
||||
zone = a.inherit('points.zones', zone_name, zones)
|
||||
|
||||
// extracting keys that are handled here, not at the zone render level
|
||||
const anchor = a.anchor(zone.anchor || {}, `points.zones.${zone_name}.anchor`, all_points)
|
||||
const rotate = a.sane(zone.rotate || 0, `points.zones.${zone_name}.rotate`, 'number')
|
||||
const anchor = make_anchor(zone.anchor || {}, `points.zones.${zone_name}.anchor`, all_points)(units)
|
||||
const rotate = a.sane(zone.rotate || 0, `points.zones.${zone_name}.rotate`, 'number')(units)
|
||||
const mirror = zone.mirror
|
||||
delete zone.anchor
|
||||
delete zone.rotate
|
||||
delete zone.mirror
|
||||
|
||||
// creating new points
|
||||
const new_points = render_zone(zone_name, zone, anchor, global_key)
|
||||
const new_points = render_zone(zone_name, zone, anchor, global_key, units)
|
||||
|
||||
// adjusting new points
|
||||
for (const [new_name, new_point] of Object.entries(new_points)) {
|
||||
|
@ -261,7 +272,7 @@ exports.parse = (config = {}) => {
|
|||
all_points = Object.assign(all_points, points)
|
||||
|
||||
// per-zone mirroring for the new keys
|
||||
const axis = parse_axis(mirror, `points.zones.${zone_name}.mirror`, all_points)
|
||||
const axis = parse_axis(mirror, `points.zones.${zone_name}.mirror`, all_points, units)
|
||||
if (axis) {
|
||||
for (const new_point of Object.values(new_points)) {
|
||||
const [mname, mp] = perform_mirror(new_point, axis)
|
||||
|
@ -284,7 +295,7 @@ exports.parse = (config = {}) => {
|
|||
}
|
||||
|
||||
// global mirroring for points that haven't been mirrored yet
|
||||
const global_axis = parse_axis(global_mirror, `points.mirror`, points)
|
||||
const global_axis = parse_axis(global_mirror, `points.mirror`, points, units)
|
||||
const global_mirrored_points = {}
|
||||
for (const point of Object.values(points)) {
|
||||
if (global_axis && point.mirrored === undefined) {
|
||||
|
@ -306,7 +317,7 @@ exports.parse = (config = {}) => {
|
|||
}
|
||||
|
||||
// done
|
||||
return filtered
|
||||
return [filtered, units]
|
||||
}
|
||||
|
||||
exports.visualize = (points) => {
|
||||
|
|
71
src/prepare.js
Normal file
71
src/prepare.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
const u = require('./utils')
|
||||
const a = require('./assert')
|
||||
|
||||
const unnest = exports.unnest = (config) => {
|
||||
if (a.type(config)() !== 'object') return config
|
||||
const result = {}
|
||||
for (const [key, val] of Object.entries(config)) {
|
||||
u.deep(result, key, unnest(val))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const _extend = exports._extend = (to, from) => {
|
||||
const to_type = a.type(to)()
|
||||
const from_type = a.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(to[key], from[key])
|
||||
if (res[key] === undefined) delete res[key]
|
||||
}
|
||||
return res
|
||||
} else if (from_type == 'array') {
|
||||
const res = u.deepcopy(to)
|
||||
for (const [i, val] of from.entries()) {
|
||||
res[i] = _extend(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(res, arg)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
const _inherit = exports._inherit = (config, root, breadcrumbs) => {
|
||||
if (a.type(config)() !== 'object') return config
|
||||
const result = {}
|
||||
for (const [key, val] of Object.entries(config)) {
|
||||
breadcrumbs.push(key)
|
||||
let newval = _inherit(val, root, breadcrumbs)
|
||||
if (newval && newval.extends !== undefined) {
|
||||
let candidates = [newval.extends]
|
||||
const list = [newval]
|
||||
while (candidates.length) {
|
||||
const path = candidates.shift()
|
||||
const other = u.deepcopy(u.deep(root, path))
|
||||
a.assert(other, `"${path}" (reached from "${breadcrumbs.join('.')}.${key}.extends") does not name a valid target!`)
|
||||
let parents = other.extends || []
|
||||
if (a.type(parents)() !== 'array') parents = [parents]
|
||||
candidates = candidates.concat(parents)
|
||||
list.unshift(other)
|
||||
}
|
||||
newval = extend.apply(this, list)
|
||||
delete newval.extends
|
||||
}
|
||||
result[key] = newval
|
||||
breadcrumbs.pop()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const inherit = exports.inherit = (config) => _inherit(config, config, [])
|
14
src/utils.js
14
src/utils.js
|
@ -2,7 +2,7 @@ const m = require('makerjs')
|
|||
|
||||
exports.deepcopy = (value) => JSON.parse(JSON.stringify(value))
|
||||
|
||||
const deep_assign = exports.deep_assign = (obj, key, val) => {
|
||||
const deep = exports.deep = (obj, key, val) => {
|
||||
const levels = key.split('.')
|
||||
const last = levels.pop()
|
||||
let step = obj
|
||||
|
@ -10,21 +10,11 @@ const deep_assign = exports.deep_assign = (obj, key, val) => {
|
|||
step[level] = step[level] || {}
|
||||
step = step[level]
|
||||
}
|
||||
if (val === undefined) return step[last]
|
||||
step[last] = val
|
||||
return obj
|
||||
}
|
||||
|
||||
const expand_nested_keys = exports.expand_nested_keys = (config) => {
|
||||
if (typeof config == 'object') {
|
||||
const result = {}
|
||||
for (const [key, val] of Object.entries(config)) {
|
||||
deep_assign(result, key, expand_nested_keys(val))
|
||||
}
|
||||
return result
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
const eq = exports.eq = (a=[], b=[]) => {
|
||||
return a[0] === b[0] && a[1] === b[1]
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const yaml = require('js-yaml')
|
||||
const points_lib = require('../src/points')
|
||||
|
||||
const fixtures = path.join(__dirname, 'fixtures')
|
||||
const absolem_config = yaml.load(fs.readFileSync(path.join(fixtures, 'absolem.yaml')).toString())
|
||||
|
||||
describe('Absolem', function() {
|
||||
it('#points', function() {
|
||||
const expected = fs.readJSONSync(path.join(fixtures, 'absolem_points.json'))
|
||||
const actual = points_lib.parse(absolem_config.points)
|
||||
// remove metadata, so that it only checks the points
|
||||
Object.values(actual).map(val => delete val.meta)
|
||||
// only check points in the "main" zones
|
||||
for (const key of Object.keys(actual)) {
|
||||
if (!expected[key]) {
|
||||
delete actual[key]
|
||||
}
|
||||
}
|
||||
actual.should.deep.equal(expected)
|
||||
})
|
||||
})
|
28
test/complex/index.js
Normal file
28
test/complex/index.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const yaml = require('js-yaml')
|
||||
const glob = require('glob')
|
||||
const u = require('../../src/utils')
|
||||
const ergogen = require('../../src/ergogen')
|
||||
|
||||
const cap = s => s.charAt(0).toUpperCase() + s.slice(1)
|
||||
|
||||
for (const part of ['points', 'outlines', 'cases', 'pcbs']) {
|
||||
describe(cap(part), function() {
|
||||
const dir = path.join(__dirname, part)
|
||||
for (const input_path of glob.sync(path.join(dir, '*.yaml'))) {
|
||||
const basename = path.basename(input_path, '.yaml')
|
||||
const title = basename.split('_').join(' ')
|
||||
it(title, function() {
|
||||
const dirname = path.dirname(input_path)
|
||||
const input = yaml.load(fs.readFileSync(input_path).toString())
|
||||
const actual = ergogen.process(input, true)
|
||||
for (const expected_path of glob.sync(path.join(dirname, basename + '___*'))) {
|
||||
const expected = JSON.parse(fs.readFileSync(expected_path).toString())
|
||||
const comp_path = expected_path.split('___')[1].split('.')[0].split('_').join('.')
|
||||
u.deep(actual, comp_path).should.deep.equal(expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
24
test/complex/outlines/001_basic_outline.yaml
Normal file
24
test/complex/outlines/001_basic_outline.yaml
Normal file
|
@ -0,0 +1,24 @@
|
|||
points:
|
||||
zones:
|
||||
matrix:
|
||||
columns:
|
||||
left.key.bind: [,10,,]
|
||||
right.key.bind: [,,,10]
|
||||
rows:
|
||||
bottom.key.bind: [10,,,]
|
||||
top.key.bind: [,,10,]
|
||||
key:
|
||||
bind: [0, 0, 0, 0]
|
||||
outlines:
|
||||
exports:
|
||||
outline:
|
||||
main:
|
||||
type: keys
|
||||
side: left
|
||||
size: 20
|
||||
min:
|
||||
type: keys
|
||||
side: left
|
||||
bound: false
|
||||
size: 14
|
||||
operation: subtract
|
506
test/complex/outlines/001_basic_outline___outlines.json
Normal file
506
test/complex/outlines/001_basic_outline___outlines.json
Normal file
|
@ -0,0 +1,506 @@
|
|||
{
|
||||
"outline": {
|
||||
"models": {
|
||||
"a": {
|
||||
"models": {
|
||||
"a": {
|
||||
"models": {},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"models": {
|
||||
"a": {
|
||||
"models": {
|
||||
"a": {
|
||||
"models": {
|
||||
"a": {
|
||||
"models": {
|
||||
"a": {
|
||||
"models": {},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"models": {
|
||||
"a": {
|
||||
"models": {
|
||||
"a": {
|
||||
"paths": {
|
||||
"ShapeLine1": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
-10,
|
||||
-10
|
||||
],
|
||||
"end": [
|
||||
29,
|
||||
-10
|
||||
]
|
||||
},
|
||||
"ShapeLine4": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
-10,
|
||||
-10
|
||||
],
|
||||
"end": [
|
||||
-10,
|
||||
29
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"paths": {},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"paths": {},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"models": {
|
||||
"a": {
|
||||
"models": {
|
||||
"a": {
|
||||
"paths": {
|
||||
"ShapeLine3": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
-10,
|
||||
29
|
||||
],
|
||||
"end": [
|
||||
29,
|
||||
29
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"paths": {},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"paths": {},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"models": {
|
||||
"a": {
|
||||
"models": {
|
||||
"a": {
|
||||
"paths": {
|
||||
"ShapeLine2": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
29,
|
||||
-10
|
||||
],
|
||||
"end": [
|
||||
29,
|
||||
29
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"paths": {},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"paths": {},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"models": {
|
||||
"a": {
|
||||
"models": {
|
||||
"a": {
|
||||
"paths": {},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"paths": {},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"paths": {},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"models": {
|
||||
"a": {
|
||||
"models": {
|
||||
"a": {
|
||||
"models": {
|
||||
"a": {
|
||||
"models": {
|
||||
"a": {
|
||||
"models": {},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"paths": {
|
||||
"ShapeLine1": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
-7,
|
||||
-7
|
||||
],
|
||||
"end": [
|
||||
7,
|
||||
-7
|
||||
]
|
||||
},
|
||||
"ShapeLine2": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
7,
|
||||
-7
|
||||
],
|
||||
"end": [
|
||||
7,
|
||||
7
|
||||
]
|
||||
},
|
||||
"ShapeLine3": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
7,
|
||||
7
|
||||
],
|
||||
"end": [
|
||||
-7,
|
||||
7
|
||||
]
|
||||
},
|
||||
"ShapeLine4": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
-7,
|
||||
7
|
||||
],
|
||||
"end": [
|
||||
-7,
|
||||
-7
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"paths": {
|
||||
"ShapeLine1": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
-7,
|
||||
12
|
||||
],
|
||||
"end": [
|
||||
7,
|
||||
12
|
||||
]
|
||||
},
|
||||
"ShapeLine2": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
7,
|
||||
12
|
||||
],
|
||||
"end": [
|
||||
7,
|
||||
26
|
||||
]
|
||||
},
|
||||
"ShapeLine3": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
7,
|
||||
26
|
||||
],
|
||||
"end": [
|
||||
-7,
|
||||
26
|
||||
]
|
||||
},
|
||||
"ShapeLine4": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
-7,
|
||||
26
|
||||
],
|
||||
"end": [
|
||||
-7,
|
||||
12
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"paths": {
|
||||
"ShapeLine1": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
12,
|
||||
-7
|
||||
],
|
||||
"end": [
|
||||
26,
|
||||
-7
|
||||
]
|
||||
},
|
||||
"ShapeLine2": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
26,
|
||||
-7
|
||||
],
|
||||
"end": [
|
||||
26,
|
||||
7
|
||||
]
|
||||
},
|
||||
"ShapeLine3": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
26,
|
||||
7
|
||||
],
|
||||
"end": [
|
||||
12,
|
||||
7
|
||||
]
|
||||
},
|
||||
"ShapeLine4": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
12,
|
||||
7
|
||||
],
|
||||
"end": [
|
||||
12,
|
||||
-7
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"paths": {
|
||||
"ShapeLine1": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
12,
|
||||
12
|
||||
],
|
||||
"end": [
|
||||
26,
|
||||
12
|
||||
]
|
||||
},
|
||||
"ShapeLine2": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
26,
|
||||
12
|
||||
],
|
||||
"end": [
|
||||
26,
|
||||
26
|
||||
]
|
||||
},
|
||||
"ShapeLine3": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
26,
|
||||
26
|
||||
],
|
||||
"end": [
|
||||
12,
|
||||
26
|
||||
]
|
||||
},
|
||||
"ShapeLine4": {
|
||||
"type": "line",
|
||||
"origin": [
|
||||
12,
|
||||
26
|
||||
],
|
||||
"end": [
|
||||
12,
|
||||
12
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
}
|
44
test/complex/outlines/002_gluing.yaml
Normal file
44
test/complex/outlines/002_gluing.yaml
Normal file
|
@ -0,0 +1,44 @@
|
|||
points:
|
||||
zones:
|
||||
matrix:
|
||||
columns:
|
||||
left.key.bind: [,10,,]
|
||||
right.key.bind: [,,,10]
|
||||
rows:
|
||||
bottom.key.bind: [10,,,]
|
||||
top.key.bind: [,,10,]
|
||||
key:
|
||||
bind: [0, 0, 0, 0]
|
||||
rotate: -20
|
||||
mirror:
|
||||
ref: matrix_right_top
|
||||
distance: 30
|
||||
outlines:
|
||||
glue:
|
||||
default:
|
||||
top:
|
||||
left:
|
||||
ref: matrix_right_top
|
||||
shift: [,sy / 2]
|
||||
right:
|
||||
ref: mirror_matrix_right_top
|
||||
shift: [,sy / 2]
|
||||
bottom:
|
||||
left:
|
||||
ref: matrix_right_bottom
|
||||
shift: [,sy / -2]
|
||||
right:
|
||||
ref: mirror_matrix_right_bottom
|
||||
shift: [,sy / -2]
|
||||
exports:
|
||||
outline:
|
||||
main:
|
||||
type: keys
|
||||
side: both
|
||||
size: 20
|
||||
min:
|
||||
type: keys
|
||||
side: both
|
||||
bound: false
|
||||
size: 14
|
||||
operation: subtract
|
9
test/complex/points/001_basic_2x2.yaml
Normal file
9
test/complex/points/001_basic_2x2.yaml
Normal file
|
@ -0,0 +1,9 @@
|
|||
points:
|
||||
zones:
|
||||
matrix:
|
||||
columns:
|
||||
left:
|
||||
right:
|
||||
rows:
|
||||
bottom:
|
||||
top:
|
130
test/complex/points/001_basic_2x2___points_data.json
Normal file
130
test/complex/points/001_basic_2x2___points_data.json
Normal file
|
@ -0,0 +1,130 @@
|
|||
{
|
||||
"matrix_left_bottom": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"r": 0,
|
||||
"meta": {
|
||||
"shift": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"rotate": 0,
|
||||
"padding": 19,
|
||||
"width": 1,
|
||||
"height": 1,
|
||||
"skip": false,
|
||||
"asym": "both",
|
||||
"name": "matrix_left_bottom",
|
||||
"colrow": "left_bottom",
|
||||
"col": {
|
||||
"stagger": 0,
|
||||
"spread": 0,
|
||||
"rotate": 0,
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"rows": {},
|
||||
"key": {},
|
||||
"name": "left"
|
||||
},
|
||||
"row": "bottom"
|
||||
}
|
||||
},
|
||||
"matrix_left_top": {
|
||||
"x": 0,
|
||||
"y": 19,
|
||||
"r": 0,
|
||||
"meta": {
|
||||
"shift": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"rotate": 0,
|
||||
"padding": 19,
|
||||
"width": 1,
|
||||
"height": 1,
|
||||
"skip": false,
|
||||
"asym": "both",
|
||||
"name": "matrix_left_top",
|
||||
"colrow": "left_top",
|
||||
"col": {
|
||||
"stagger": 0,
|
||||
"spread": 0,
|
||||
"rotate": 0,
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"rows": {},
|
||||
"key": {},
|
||||
"name": "left"
|
||||
},
|
||||
"row": "top"
|
||||
}
|
||||
},
|
||||
"matrix_right_bottom": {
|
||||
"x": 19,
|
||||
"y": 0,
|
||||
"r": 0,
|
||||
"meta": {
|
||||
"shift": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"rotate": 0,
|
||||
"padding": 19,
|
||||
"width": 1,
|
||||
"height": 1,
|
||||
"skip": false,
|
||||
"asym": "both",
|
||||
"name": "matrix_right_bottom",
|
||||
"colrow": "right_bottom",
|
||||
"col": {
|
||||
"stagger": 0,
|
||||
"spread": 19,
|
||||
"rotate": 0,
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"rows": {},
|
||||
"key": {},
|
||||
"name": "right"
|
||||
},
|
||||
"row": "bottom"
|
||||
}
|
||||
},
|
||||
"matrix_right_top": {
|
||||
"x": 19,
|
||||
"y": 19,
|
||||
"r": 0,
|
||||
"meta": {
|
||||
"shift": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"rotate": 0,
|
||||
"padding": 19,
|
||||
"width": 1,
|
||||
"height": 1,
|
||||
"skip": false,
|
||||
"asym": "both",
|
||||
"name": "matrix_right_top",
|
||||
"colrow": "right_top",
|
||||
"col": {
|
||||
"stagger": 0,
|
||||
"spread": 19,
|
||||
"rotate": 0,
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"rows": {},
|
||||
"key": {},
|
||||
"name": "right"
|
||||
},
|
||||
"row": "top"
|
||||
}
|
||||
}
|
||||
}
|
13
test/complex/points/002_adjustments.yaml
Normal file
13
test/complex/points/002_adjustments.yaml
Normal file
|
@ -0,0 +1,13 @@
|
|||
points:
|
||||
zones:
|
||||
matrix:
|
||||
columns:
|
||||
left:
|
||||
right:
|
||||
stagger: 5
|
||||
spread: 25
|
||||
rotate: 5
|
||||
origin: [-9, -9]
|
||||
rows:
|
||||
bottom:
|
||||
top:
|
707
test/fixtures/absolem.yaml
vendored
707
test/fixtures/absolem.yaml
vendored
|
@ -1,707 +0,0 @@
|
|||
points:
|
||||
zones:
|
||||
matrix:
|
||||
anchor:
|
||||
rotate: 5
|
||||
columns:
|
||||
pinky:
|
||||
rotate: -5
|
||||
origin: [7, -7]
|
||||
rows:
|
||||
bottom:
|
||||
home:
|
||||
bind: [,15,-1]
|
||||
top:
|
||||
bind: [,15,-1]
|
||||
key:
|
||||
column_net: P1
|
||||
column_mark: P
|
||||
ring:
|
||||
stagger: 12
|
||||
rows:
|
||||
bottom:
|
||||
bind: [,,,10]
|
||||
home:
|
||||
bind: [,10]
|
||||
top:
|
||||
bind: [,10]
|
||||
key:
|
||||
column_net: P0
|
||||
column_mark: R
|
||||
middle:
|
||||
stagger: 5
|
||||
rows:
|
||||
bottom:
|
||||
bind: [,10,,10]
|
||||
home:
|
||||
bind: [,10,,10]
|
||||
top:
|
||||
key:
|
||||
column_net: P2
|
||||
column_mark: M
|
||||
index:
|
||||
stagger: -6
|
||||
rows:
|
||||
bottom:
|
||||
bind: [,10]
|
||||
home:
|
||||
bind: [,,,10]
|
||||
top:
|
||||
bind: [,,,10]
|
||||
key:
|
||||
column_net: P3
|
||||
column_mark: X
|
||||
inner:
|
||||
stagger: -2
|
||||
rows:
|
||||
bottom:
|
||||
bind: [,,10,]
|
||||
home:
|
||||
bind: [,,,10]
|
||||
top:
|
||||
bind: [,,,10]
|
||||
key:
|
||||
column_net: P4
|
||||
column_mark: I
|
||||
rows:
|
||||
bottom:
|
||||
bind: [10]
|
||||
row_net: P16
|
||||
row_mark: LB
|
||||
mirror:
|
||||
row_net: P7
|
||||
row_mark: RB
|
||||
home:
|
||||
bind: [10]
|
||||
row_net: P14
|
||||
row_mark: LH
|
||||
mirror:
|
||||
row_net: P6
|
||||
row_mark: RH
|
||||
top:
|
||||
row_net: P15
|
||||
row_mark: LT
|
||||
mirror:
|
||||
row_net: P5
|
||||
row_mark: RT
|
||||
s19:
|
||||
extends: matrix
|
||||
columns:
|
||||
pinky:
|
||||
rows:
|
||||
bottom:
|
||||
footprints:
|
||||
diode:
|
||||
anchor:
|
||||
shift: [,12]
|
||||
home:
|
||||
footprints:
|
||||
diode:
|
||||
anchor:
|
||||
shift: [,6]
|
||||
top:
|
||||
footprints:
|
||||
row_ext:
|
||||
anchor:
|
||||
shift: [, -10]
|
||||
extra_column:
|
||||
type: pad
|
||||
anchor:
|
||||
shift: [-4, 4]
|
||||
nets:
|
||||
net: 'P19'
|
||||
params:
|
||||
width: 2
|
||||
height: 2
|
||||
front: false
|
||||
text: 'E'
|
||||
align: right
|
||||
key:
|
||||
footprints:
|
||||
row_ext:
|
||||
type: pad
|
||||
anchor:
|
||||
shift: [-4, -4]
|
||||
nets:
|
||||
net: '!row_net'
|
||||
params:
|
||||
width: 2
|
||||
height: 2
|
||||
front: false
|
||||
text: '!row_mark'
|
||||
align: right
|
||||
ring:
|
||||
rows:
|
||||
bottom:
|
||||
footprints:
|
||||
diode:
|
||||
anchor:
|
||||
shift: [,5]
|
||||
home:
|
||||
footprints:
|
||||
diode:
|
||||
anchor:
|
||||
shift: [,2.5]
|
||||
middle:
|
||||
rows:
|
||||
top:
|
||||
footprints:
|
||||
diode:
|
||||
anchor:
|
||||
shift: [,-6]
|
||||
home:
|
||||
footprints:
|
||||
diode:
|
||||
anchor:
|
||||
shift: [,-3]
|
||||
index:
|
||||
rows:
|
||||
bottom:
|
||||
footprints:
|
||||
diode:
|
||||
anchor:
|
||||
shift: [-8.25,6]
|
||||
home:
|
||||
footprints:
|
||||
diode:
|
||||
anchor:
|
||||
shift: [-8.25,3]
|
||||
top:
|
||||
footprints:
|
||||
diode:
|
||||
anchor:
|
||||
shift: [-8.25,]
|
||||
rows:
|
||||
top:
|
||||
footprints:
|
||||
mx:
|
||||
anchor:
|
||||
rotate: 180
|
||||
alps:
|
||||
anchor:
|
||||
rotate: 180
|
||||
choc:
|
||||
anchor:
|
||||
rotate: 180
|
||||
col_ext:
|
||||
type: pad
|
||||
anchor:
|
||||
shift: [4, 4]
|
||||
nets:
|
||||
net: '!column_net'
|
||||
params:
|
||||
width: 2
|
||||
height: 2
|
||||
front: false
|
||||
text: '!column_mark'
|
||||
bottom:
|
||||
footprints:
|
||||
diode:
|
||||
anchor:
|
||||
rotate: 270
|
||||
col_ext:
|
||||
type: pad
|
||||
anchor:
|
||||
shift: [4, -4]
|
||||
nets:
|
||||
net: '!column_net'
|
||||
params:
|
||||
width: 2
|
||||
height: 2
|
||||
front: false
|
||||
text: '!column_mark'
|
||||
key:
|
||||
tags:
|
||||
s19: true
|
||||
footprints: &quad
|
||||
mx:
|
||||
type: mx
|
||||
nets:
|
||||
from: '!colrow'
|
||||
to: '!column_net'
|
||||
alps:
|
||||
type: alps
|
||||
nets:
|
||||
from: '!colrow'
|
||||
to: '!column_net'
|
||||
<<: &choc
|
||||
choc:
|
||||
type: choc
|
||||
nets:
|
||||
from: '!colrow'
|
||||
to: '!column_net'
|
||||
diode:
|
||||
type: diode
|
||||
anchor:
|
||||
rotate: 90
|
||||
shift: [8.25, 0]
|
||||
nets:
|
||||
from: '!colrow'
|
||||
to: '!row_net'
|
||||
mirror:
|
||||
footprints: &quad_mirror
|
||||
mx:
|
||||
nets:
|
||||
from: '!column_net'
|
||||
to: '!colrow'
|
||||
alps:
|
||||
nets:
|
||||
from: '!column_net'
|
||||
to: '!colrow'
|
||||
<<: &choc_mirror
|
||||
choc:
|
||||
nets:
|
||||
from: '!column_net'
|
||||
to: '!colrow'
|
||||
s18:
|
||||
extends: matrix
|
||||
columns:
|
||||
pinky:
|
||||
stagger: 1
|
||||
origin: [7, -8]
|
||||
rows:
|
||||
top:
|
||||
footprints:
|
||||
choc:
|
||||
anchor:
|
||||
rotate: 180
|
||||
key:
|
||||
padding: 18
|
||||
tags:
|
||||
s18: true
|
||||
footprints: *choc
|
||||
mirror:
|
||||
footprints: *choc_mirror
|
||||
thumbfan:
|
||||
anchor:
|
||||
ref: matrix_inner_bottom
|
||||
shift: [-7, -19]
|
||||
columns:
|
||||
near:
|
||||
spread: 21.25
|
||||
rotate: -28
|
||||
origin: [9.5, -9]
|
||||
rows:
|
||||
thumb:
|
||||
bind: [10,5,,]
|
||||
column_net: P2
|
||||
tags:
|
||||
classic: true
|
||||
footprints:
|
||||
choc:
|
||||
anchor:
|
||||
rotate: 180
|
||||
diode:
|
||||
anchor:
|
||||
shift: [8,]
|
||||
row_ext:
|
||||
type: pad
|
||||
anchor:
|
||||
shift: [-3, 9]
|
||||
nets:
|
||||
net: '!row_net'
|
||||
params:
|
||||
width: 2
|
||||
height: 2
|
||||
front: false
|
||||
text: '!row_mark'
|
||||
align: right
|
||||
home:
|
||||
spread: 21.25
|
||||
rotate: -28
|
||||
origin: [11.75, -9]
|
||||
rows:
|
||||
thumb:
|
||||
bind: [,10,,15]
|
||||
column_net: P3
|
||||
tags:
|
||||
classic: true
|
||||
uniform: true
|
||||
footprints:
|
||||
diode:
|
||||
anchor:
|
||||
shift: [8,]
|
||||
far:
|
||||
rows:
|
||||
thumb:
|
||||
bind: [-1,,,5]
|
||||
column_net: P4
|
||||
tags:
|
||||
classic: true
|
||||
footprints:
|
||||
choc:
|
||||
anchor:
|
||||
rotate: 180
|
||||
diode:
|
||||
anchor:
|
||||
shift: [-4,]
|
||||
rotate: 0
|
||||
mirror:
|
||||
footprints:
|
||||
diode:
|
||||
anchor:
|
||||
rotate: 180
|
||||
rows:
|
||||
thumb:
|
||||
row_net: P10
|
||||
row_mark: LF
|
||||
footprints:
|
||||
diode:
|
||||
anchor:
|
||||
shift: [0, 9]
|
||||
rotate: 180
|
||||
mirror:
|
||||
row_net: P8
|
||||
row_mark: RF
|
||||
footprints:
|
||||
diode:
|
||||
anchor:
|
||||
rotate: 0
|
||||
key:
|
||||
footprints: *quad
|
||||
mirror: *quad_mirror
|
||||
unifar:
|
||||
anchor:
|
||||
ref: thumbfan_home_thumb
|
||||
columns:
|
||||
home_again:
|
||||
rotate: -28
|
||||
origin: [9.5, -9]
|
||||
key:
|
||||
skip: true
|
||||
far:
|
||||
rows:
|
||||
thumb:
|
||||
bind: [-1,,,5]
|
||||
key:
|
||||
column_net: P4
|
||||
footprints:
|
||||
choc:
|
||||
anchor:
|
||||
rotate: 180
|
||||
diode: '!!unset'
|
||||
mirror:
|
||||
footprints:
|
||||
diode: '!!unset'
|
||||
tags:
|
||||
uniform: true
|
||||
rows:
|
||||
thumb:
|
||||
row_net: P10
|
||||
mirror:
|
||||
row_net: P8
|
||||
key:
|
||||
footprints: *quad
|
||||
mirror: *quad_mirror
|
||||
uninear:
|
||||
anchor:
|
||||
ref: thumbfan_home_thumb
|
||||
columns:
|
||||
home_again:
|
||||
spread: -19
|
||||
rotate: 28
|
||||
origin: [-9.5, -9]
|
||||
key:
|
||||
skip: true
|
||||
near:
|
||||
rows:
|
||||
thumb:
|
||||
bind: [10,5,,]
|
||||
key:
|
||||
column_net: P2
|
||||
footprints:
|
||||
choc:
|
||||
anchor:
|
||||
rotate: 180
|
||||
diode: '!!unset'
|
||||
mirror:
|
||||
footprints:
|
||||
diode: '!!unset'
|
||||
tags:
|
||||
uniform: true
|
||||
rows:
|
||||
thumb:
|
||||
row_net: P10
|
||||
mirror:
|
||||
row_net: P8
|
||||
key:
|
||||
footprints: *quad
|
||||
mirror: *quad_mirror
|
||||
key:
|
||||
bind: [0,0,0,0]
|
||||
rotate: -20
|
||||
mirror:
|
||||
ref: matrix_pinky_home
|
||||
distance: 223.7529778
|
||||
outlines:
|
||||
glue:
|
||||
classic_s19:
|
||||
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_s19:
|
||||
extends: classic_s19
|
||||
bottom:
|
||||
left:
|
||||
ref: unifar_far_thumb
|
||||
right:
|
||||
ref: mirror_unifar_far_thumb
|
||||
classic_s18:
|
||||
extends: classic_s19
|
||||
top:
|
||||
left:
|
||||
ref: s18_inner_top
|
||||
right:
|
||||
ref: mirror_s18_inner_top
|
||||
uniform_s18:
|
||||
extends:
|
||||
- uniform_s19
|
||||
- classic_s18
|
||||
exports:
|
||||
classic_s19_outline:
|
||||
main:
|
||||
type: keys
|
||||
side: both
|
||||
tags:
|
||||
- s19
|
||||
- classic
|
||||
glue: classic_s19
|
||||
size: 13.5
|
||||
corner: .5
|
||||
uniform_s19_outline:
|
||||
extends: classic_s19_outline
|
||||
main:
|
||||
tags:
|
||||
- s19
|
||||
- uniform
|
||||
glue: uniform_s19
|
||||
uniform_s18_outline:
|
||||
extends: uniform_s19_outline
|
||||
main:
|
||||
tags:
|
||||
- s18
|
||||
- uniform
|
||||
glue: uniform_s18
|
||||
mounting_holes:
|
||||
ring_top:
|
||||
type: circle
|
||||
ref: matrix_ring_home
|
||||
shift: [-10, 5]
|
||||
radius: 2.25
|
||||
mirror: true
|
||||
ring_bottom:
|
||||
type: circle
|
||||
ref: matrix_ring_home
|
||||
shift: [-9, -9]
|
||||
radius: 2.25
|
||||
mirror: true
|
||||
operation: stack
|
||||
index_top:
|
||||
type: circle
|
||||
ref: matrix_index_home
|
||||
shift: [9.5, 9.5]
|
||||
radius: 2.25
|
||||
mirror: true
|
||||
operation: stack
|
||||
index_bottom:
|
||||
type: circle
|
||||
ref: matrix_index_home
|
||||
shift: [9.5, -9.5]
|
||||
radius: 2.25
|
||||
mirror: true
|
||||
operation: stack
|
||||
thumb_near:
|
||||
type: circle
|
||||
ref: thumbfan_home_thumb
|
||||
shift: [-12, 2]
|
||||
radius: 2.25
|
||||
mirror: true
|
||||
operation: stack
|
||||
thumb_far:
|
||||
type: circle
|
||||
ref: thumbfan_home_thumb
|
||||
shift: [12, 2]
|
||||
radius: 2.25
|
||||
mirror: true
|
||||
operation: stack
|
||||
middle:
|
||||
type: circle
|
||||
ref: thumbfan_home_thumb
|
||||
shift: [-8, 19]
|
||||
radius: 2.25
|
||||
mirror: true
|
||||
operation: stack
|
||||
intersected_outline:
|
||||
one:
|
||||
type: outline
|
||||
name: classic_s19_outline
|
||||
two:
|
||||
type: outline
|
||||
name: uniform_s18_outline
|
||||
operation: intersect
|
||||
controller_cutout:
|
||||
type: rectangle
|
||||
ref:
|
||||
- s18_inner_top
|
||||
- mirror_s18_inner_top
|
||||
shift: [-10, -5]
|
||||
size: [20, 10]
|
||||
operation: subtract
|
||||
mounting_holes:
|
||||
type: outline
|
||||
name: mounting_holes
|
||||
operation: subtract
|
||||
classic_s19_switches:
|
||||
main:
|
||||
type: keys
|
||||
side: both
|
||||
tags:
|
||||
- classic
|
||||
glue: classic_s19
|
||||
size: 14
|
||||
bound: false
|
||||
uniform_s19_switches:
|
||||
main:
|
||||
type: keys
|
||||
side: both
|
||||
tags:
|
||||
- uniform
|
||||
glue: uniform_s19
|
||||
size: 14
|
||||
bound: false
|
||||
pcb_middle:
|
||||
raw:
|
||||
type: keys
|
||||
side: middle
|
||||
tags:
|
||||
- s19
|
||||
- classic
|
||||
glue: classic_s19
|
||||
size: 24
|
||||
helper1:
|
||||
type: rectangle
|
||||
size: [25, 5]
|
||||
ref: thumbfan_home_thumb
|
||||
shift: [0, 12]
|
||||
mirror: true
|
||||
helper2:
|
||||
type: rectangle
|
||||
size: [25, 5]
|
||||
ref: thumbfan_far_thumb
|
||||
shift: [-25, 12]
|
||||
mirror: true
|
||||
outer_bounds:
|
||||
type: outline
|
||||
name: classic_s19_outline
|
||||
operation: intersect
|
||||
pcbs:
|
||||
main:
|
||||
outlines:
|
||||
edge:
|
||||
outline: intersected_outline
|
||||
layer: Edge.Cuts
|
||||
middle:
|
||||
outline: pcb_middle
|
||||
layer: F.SilkS
|
||||
footprints:
|
||||
mcu:
|
||||
type: promicro
|
||||
anchor:
|
||||
ref:
|
||||
- s18_inner_top
|
||||
- mirror_s18_inner_top
|
||||
shift: [0, -23]
|
||||
rotate: 270
|
||||
slider:
|
||||
type: slider
|
||||
anchor:
|
||||
ref:
|
||||
- s18_inner_top
|
||||
- mirror_s18_inner_top
|
||||
shift: [0, -7.5]
|
||||
nets:
|
||||
from: RAWER
|
||||
to: RAW
|
||||
params:
|
||||
side: B
|
||||
reset:
|
||||
type: reset
|
||||
anchor:
|
||||
ref:
|
||||
- s18_inner_top
|
||||
- mirror_s18_inner_top
|
||||
shift: [0, -17]
|
||||
rotate: 90
|
||||
nets:
|
||||
from: RST
|
||||
to: GND
|
||||
params:
|
||||
side: B
|
||||
extra_row_left:
|
||||
type: pad
|
||||
anchor:
|
||||
ref:
|
||||
- s18_inner_top
|
||||
- mirror_s18_inner_top
|
||||
shift: [-15, -10]
|
||||
nets:
|
||||
net: 'P20'
|
||||
params:
|
||||
width: 3
|
||||
height: 3
|
||||
front: false
|
||||
text: 'LN'
|
||||
align: right
|
||||
extra_row_right:
|
||||
type: pad
|
||||
anchor:
|
||||
ref:
|
||||
- s18_inner_top
|
||||
- mirror_s18_inner_top
|
||||
shift: [15, -10]
|
||||
nets:
|
||||
net: 'P21'
|
||||
params:
|
||||
width: 3
|
||||
height: 3
|
||||
front: false
|
||||
text: 'RN'
|
||||
battery:
|
||||
type: jstph
|
||||
anchor:
|
||||
ref:
|
||||
- matrix_inner_bottom
|
||||
- mirror_matrix_inner_bottom
|
||||
shift: [0, -43]
|
||||
rotate: 180
|
||||
nets:
|
||||
pos: RAWER
|
||||
neg: GND
|
||||
led:
|
||||
type: rgb
|
||||
anchor:
|
||||
ref:
|
||||
- matrix_inner_bottom
|
||||
- mirror_matrix_inner_bottom
|
||||
shift: [0, -48]
|
||||
nets:
|
||||
din: 'P9'
|
||||
dout: ''
|
182
test/fixtures/absolem_points.json
vendored
182
test/fixtures/absolem_points.json
vendored
|
@ -1,182 +0,0 @@
|
|||
{
|
||||
"matrix_pinky_bottom": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"r": -15
|
||||
},
|
||||
"matrix_pinky_home": {
|
||||
"x": 4.9175619,
|
||||
"y": 18.3525907,
|
||||
"r": -15
|
||||
},
|
||||
"matrix_pinky_top": {
|
||||
"x": 9.8351237,
|
||||
"y": 36.7051814,
|
||||
"r": -15
|
||||
},
|
||||
"matrix_ring_bottom": {
|
||||
"x": 22.7244416,
|
||||
"y": 5.176704,
|
||||
"r": -20
|
||||
},
|
||||
"matrix_ring_home": {
|
||||
"x": 29.2228244,
|
||||
"y": 23.0308638,
|
||||
"r": -20
|
||||
},
|
||||
"matrix_ring_top": {
|
||||
"x": 35.7212071,
|
||||
"y": 40.8850235,
|
||||
"r": -20
|
||||
},
|
||||
"matrix_middle_bottom": {
|
||||
"x": 42.2887022,
|
||||
"y": 3.3767843,
|
||||
"r": -20
|
||||
},
|
||||
"matrix_middle_home": {
|
||||
"x": 48.7870849,
|
||||
"y": 21.2309442,
|
||||
"r": -20
|
||||
},
|
||||
"matrix_middle_top": {
|
||||
"x": 55.2854676,
|
||||
"y": 39.0851039,
|
||||
"r": -20
|
||||
},
|
||||
"matrix_index_bottom": {
|
||||
"x": 58.0907411,
|
||||
"y": -8.7597541,
|
||||
"r": -20
|
||||
},
|
||||
"matrix_index_home": {
|
||||
"x": 64.5891238,
|
||||
"y": 9.0944057,
|
||||
"r": -20
|
||||
},
|
||||
"matrix_index_top": {
|
||||
"x": 71.0875065,
|
||||
"y": 26.9485655,
|
||||
"r": -20
|
||||
},
|
||||
"matrix_inner_bottom": {
|
||||
"x": 75.2608606,
|
||||
"y": -17.1375221,
|
||||
"r": -20
|
||||
},
|
||||
"matrix_inner_home": {
|
||||
"x": 81.7592433,
|
||||
"y": 0.7166377,
|
||||
"r": -20
|
||||
},
|
||||
"matrix_inner_top": {
|
||||
"x": 88.257626,
|
||||
"y": 18.5707976,
|
||||
"r": -20
|
||||
},
|
||||
"thumbfan_near_thumb": {
|
||||
"x": 62.1846295,
|
||||
"y": -32.5975409,
|
||||
"r": -20
|
||||
},
|
||||
"thumbfan_home_thumb": {
|
||||
"x": 82.5841162,
|
||||
"y": -47.013742,
|
||||
"r": -48
|
||||
},
|
||||
"thumbfan_far_thumb": {
|
||||
"x": 94.7890169,
|
||||
"y": -68.8083815,
|
||||
"r": -76
|
||||
},
|
||||
"mirror_matrix_pinky_bottom": {
|
||||
"x": 233.5881016,
|
||||
"y": 0,
|
||||
"r": 15
|
||||
},
|
||||
"mirror_matrix_pinky_home": {
|
||||
"x": 228.67053969999998,
|
||||
"y": 18.3525907,
|
||||
"r": 15
|
||||
},
|
||||
"mirror_matrix_pinky_top": {
|
||||
"x": 223.7529779,
|
||||
"y": 36.7051814,
|
||||
"r": 15
|
||||
},
|
||||
"mirror_matrix_ring_bottom": {
|
||||
"x": 210.86365999999998,
|
||||
"y": 5.176704,
|
||||
"r": 20
|
||||
},
|
||||
"mirror_matrix_ring_home": {
|
||||
"x": 204.36527719999998,
|
||||
"y": 23.0308638,
|
||||
"r": 20
|
||||
},
|
||||
"mirror_matrix_ring_top": {
|
||||
"x": 197.8668945,
|
||||
"y": 40.8850235,
|
||||
"r": 20
|
||||
},
|
||||
"mirror_matrix_middle_bottom": {
|
||||
"x": 191.29939939999997,
|
||||
"y": 3.3767843,
|
||||
"r": 20
|
||||
},
|
||||
"mirror_matrix_middle_home": {
|
||||
"x": 184.8010167,
|
||||
"y": 21.2309442,
|
||||
"r": 20
|
||||
},
|
||||
"mirror_matrix_middle_top": {
|
||||
"x": 178.30263399999998,
|
||||
"y": 39.0851039,
|
||||
"r": 20
|
||||
},
|
||||
"mirror_matrix_index_bottom": {
|
||||
"x": 175.49736049999998,
|
||||
"y": -8.7597541,
|
||||
"r": 20
|
||||
},
|
||||
"mirror_matrix_index_home": {
|
||||
"x": 168.99897779999998,
|
||||
"y": 9.0944057,
|
||||
"r": 20
|
||||
},
|
||||
"mirror_matrix_index_top": {
|
||||
"x": 162.5005951,
|
||||
"y": 26.9485655,
|
||||
"r": 20
|
||||
},
|
||||
"mirror_matrix_inner_bottom": {
|
||||
"x": 158.327241,
|
||||
"y": -17.1375221,
|
||||
"r": 20
|
||||
},
|
||||
"mirror_matrix_inner_home": {
|
||||
"x": 151.82885829999998,
|
||||
"y": 0.7166377,
|
||||
"r": 20
|
||||
},
|
||||
"mirror_matrix_inner_top": {
|
||||
"x": 145.3304756,
|
||||
"y": 18.5707976,
|
||||
"r": 20
|
||||
},
|
||||
"mirror_thumbfan_near_thumb": {
|
||||
"x": 171.4034721,
|
||||
"y": -32.5975409,
|
||||
"r": 20
|
||||
},
|
||||
"mirror_thumbfan_home_thumb": {
|
||||
"x": 151.00398539999998,
|
||||
"y": -47.013742,
|
||||
"r": 48
|
||||
},
|
||||
"mirror_thumbfan_far_thumb": {
|
||||
"x": 138.79908469999998,
|
||||
"y": -68.8083815,
|
||||
"r": 76
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
const Point = require('../src/point')
|
||||
|
||||
describe('Point', function() {
|
||||
it('#constructor', function() {
|
||||
const point = new Point(1, 2, 45)
|
||||
point.p.should.deep.equal([1, 2])
|
||||
})
|
||||
})
|
44
test/unit/prepare.js
Normal file
44
test/unit/prepare.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
const p = require('../../src/prepare')
|
||||
|
||||
describe('Prepare', function() {
|
||||
it('unnest', function() {
|
||||
p.unnest({'a.b.c': 1}).should.deep.equal({a: {b: {c: 1}}})
|
||||
p.unnest({'a.b.c': {
|
||||
d: 2,
|
||||
'e.f': 3
|
||||
}}).should.deep.equal({a: {b: {c: {d: 2, e: {f: 3}}}}})
|
||||
})
|
||||
|
||||
it('extend', function() {
|
||||
p.extend('something', undefined).should.equal('something')
|
||||
should.equal(p.extend('something', '!!unset'), undefined)
|
||||
p.extend(undefined, 'something').should.equal('something')
|
||||
p.extend(28, 'something').should.equal('something')
|
||||
p.extend('something', 28).should.equal(28)
|
||||
p.extend(27, 28).should.equal(28)
|
||||
p.extend({a: 1, c: 1, d: 1}, {b: 2, c: 2, d: '!!unset'}).should.deep.equal({a: 1, b: 2, c: 2})
|
||||
p.extend([3, 2, 1], [null, 4, 5]).should.deep.equal([3, 4, 5])
|
||||
})
|
||||
|
||||
it('inherit', function() {
|
||||
p.inherit({
|
||||
a: {
|
||||
x: 1,
|
||||
y: 2
|
||||
},
|
||||
b: {
|
||||
extends: 'a',
|
||||
z: 3
|
||||
},
|
||||
c: {
|
||||
extends: 'b',
|
||||
w: 4
|
||||
}
|
||||
}).c.should.deep.equal({
|
||||
x: 1,
|
||||
y: 2,
|
||||
z: 3,
|
||||
w: 4
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,7 +0,0 @@
|
|||
const u = require('../src/utils')
|
||||
|
||||
describe('Utils', function() {
|
||||
it('deep_assign', function() {
|
||||
u.deep_assign({}, 'a.b.c', 1).should.deep.equal({a: {b: {c: 1}}})
|
||||
})
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue