77 lines
No EOL
2.7 KiB
JavaScript
77 lines
No EOL
2.7 KiB
JavaScript
const u = require('./utils')
|
|
const a = require('./assert')
|
|
const Point = require('./point')
|
|
|
|
const mirror_ref = exports.mirror = (ref, mirror) => {
|
|
if (mirror) {
|
|
if (ref.startsWith('mirror_')) {
|
|
return ref.substring(7)
|
|
} else {
|
|
return 'mirror_' + ref
|
|
}
|
|
}
|
|
return ref
|
|
}
|
|
|
|
const anchor = exports.parse = (raw, name, points={}, check_unexpected=true, default_point=new Point(), mirror=false) => 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, mirror)(units)
|
|
}
|
|
return current
|
|
}
|
|
if (check_unexpected) a.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) {
|
|
const parsed_ref = mirror_ref(ref, mirror)
|
|
a.assert(points[parsed_ref], `Unknown point reference "${parsed_ref}" in anchor "${name}"!`)
|
|
const resolved = points[parsed_ref]
|
|
x += resolved.x
|
|
y += resolved.y
|
|
r += resolved.r
|
|
}
|
|
point = new Point(x / len, y / len, r / len)
|
|
} else {
|
|
const parsed_ref = mirror_ref(raw.ref, mirror)
|
|
a.assert(points[parsed_ref], `Unknown point reference "${parsed_ref}" in anchor "${name}"!`)
|
|
point = points[parsed_ref].clone()
|
|
}
|
|
}
|
|
if (raw.orient !== undefined) {
|
|
point.r += a.sane(raw.orient, `${name}.orient`, 'number')(units)
|
|
}
|
|
if (raw.shift !== undefined) {
|
|
let xyval = a.wh(raw.shift, `${name}.shift`)(units)
|
|
if (point.meta.mirrored) {
|
|
xyval[0] = -xyval[0]
|
|
}
|
|
point.shift(xyval, true)
|
|
}
|
|
if (raw.rotate !== undefined) {
|
|
let angle = a.sane(raw.rotate, `${name}.rotate`, 'number')(units)
|
|
if (point.meta.mirrored) {
|
|
angle = -angle
|
|
}
|
|
point.r += angle
|
|
}
|
|
if (raw.affect !== undefined) {
|
|
const candidate = point
|
|
point = default_point.clone()
|
|
let affect = raw.affect
|
|
if (a.type(affect)() == 'string') affect = affect.split('')
|
|
affect = a.strarr(affect, `${name}.affect`)
|
|
let i = 0
|
|
for (const aff of affect) {
|
|
a.in(aff, `${name}.affect[${++i}]`, ['x', 'y', 'r'])
|
|
point[aff] = candidate[aff]
|
|
}
|
|
}
|
|
return point
|
|
} |