Allow points/anchors to resist
special mirror treatment
This commit is contained in:
parent
2cfdf10327
commit
3aef729465
4 changed files with 54 additions and 16 deletions
|
@ -28,7 +28,7 @@ const aggregators = {
|
|||
}
|
||||
}
|
||||
|
||||
const anchor = exports.parse = (raw, name, points={}, default_point=new Point(), mirror=false) => units => {
|
||||
const anchor = exports.parse = (raw, name, points={}, start=new Point(), mirror=false) => units => {
|
||||
|
||||
//
|
||||
// Anchor type handling
|
||||
|
@ -39,8 +39,8 @@ const anchor = exports.parse = (raw, name, points={}, default_point=new Point(),
|
|||
}
|
||||
|
||||
else if (a.type(raw)() == 'array') {
|
||||
// recursive call with incremental default_point mods, according to `affect`s
|
||||
let current = default_point.clone()
|
||||
// recursive call with incremental start mods, according to `affect`s
|
||||
let current = start.clone()
|
||||
let index = 1
|
||||
for (const step of raw) {
|
||||
current = anchor(step, `${name}[${index++}]`, points, current, mirror)(units)
|
||||
|
@ -48,13 +48,13 @@ const anchor = exports.parse = (raw, name, points={}, default_point=new Point(),
|
|||
return current
|
||||
}
|
||||
|
||||
a.unexpected(raw, name, ['ref', 'aggregate', 'orient', 'shift', 'rotate', 'affect'])
|
||||
a.unexpected(raw, name, ['ref', 'aggregate', 'orient', 'shift', 'rotate', 'affect', 'resist'])
|
||||
|
||||
//
|
||||
// Reference or aggregate handling
|
||||
//
|
||||
|
||||
let point = default_point.clone()
|
||||
let point = start.clone()
|
||||
if (raw.ref !== undefined && raw.aggregate !== undefined) {
|
||||
throw new Error(`Fields "ref" and "aggregate" cannot appear together in anchor "${name}"!`)
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ const anchor = exports.parse = (raw, name, points={}, default_point=new Point(),
|
|||
point = points[parsed_ref].clone()
|
||||
// recursive case
|
||||
} else {
|
||||
point = anchor(raw.ref, `${name}.ref`, points, default_point, mirror)(units)
|
||||
point = anchor(raw.ref, `${name}.ref`, points, start, mirror)(units)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ const anchor = exports.parse = (raw, name, points={}, default_point=new Point(),
|
|||
const parts = []
|
||||
let index = 1
|
||||
for (const part of raw.aggregate.parts) {
|
||||
parts.push(anchor(part, `${name}.aggregate.parts[${index++}]`, points, default_point, mirror)(units))
|
||||
parts.push(anchor(part, `${name}.aggregate.parts[${index++}]`, points, start, mirror)(units))
|
||||
}
|
||||
|
||||
point = aggregators[raw.aggregate.method](raw.aggregate, `${name}.aggregate`, parts)
|
||||
|
@ -90,14 +90,15 @@ const anchor = exports.parse = (raw, name, points={}, default_point=new Point(),
|
|||
// Actual orient/shift/rotate/affect handling
|
||||
//
|
||||
|
||||
resist = a.sane(raw.resist || false, `${name}.resist`, 'boolean')()
|
||||
const rotator = (config, name, point) => {
|
||||
// simple case: number gets added to point rotation
|
||||
if (a.type(config)(units) == 'number') {
|
||||
let angle = a.sane(config, name, 'number')(units)
|
||||
point.rotate(angle, false)
|
||||
point.rotate(angle, false, resist)
|
||||
// recursive case: points turns "towards" target anchor
|
||||
} else {
|
||||
const target = anchor(config, name, points, default_point, mirror)(units)
|
||||
const target = anchor(config, name, points, start, mirror)(units)
|
||||
point.r = point.angle(target)
|
||||
}
|
||||
}
|
||||
|
@ -107,14 +108,14 @@ const anchor = exports.parse = (raw, name, points={}, default_point=new Point(),
|
|||
}
|
||||
if (raw.shift !== undefined) {
|
||||
let xyval = a.wh(raw.shift, `${name}.shift`)(units)
|
||||
point.shift(xyval)
|
||||
point.shift(xyval, true, resist)
|
||||
}
|
||||
if (raw.rotate !== undefined) {
|
||||
rotator(raw.rotate, `${name}.rotate`, point)
|
||||
}
|
||||
if (raw.affect !== undefined) {
|
||||
const candidate = point.clone()
|
||||
point = default_point.clone()
|
||||
point = start.clone()
|
||||
point.meta = candidate.meta
|
||||
let affect = raw.affect
|
||||
if (a.type(affect)() == 'string') affect = affect.split('')
|
||||
|
|
|
@ -24,8 +24,8 @@ module.exports = class Point {
|
|||
[this.x, this.y] = val
|
||||
}
|
||||
|
||||
shift(s, relative=true) {
|
||||
s[0] *= this.meta.mirrored ? -1 : 1
|
||||
shift(s, relative=true, resist=false) {
|
||||
s[0] *= (!resist && this.meta.mirrored) ? -1 : 1
|
||||
if (relative) {
|
||||
s = m.point.rotate(s, this.r)
|
||||
}
|
||||
|
@ -34,8 +34,8 @@ module.exports = class Point {
|
|||
return this
|
||||
}
|
||||
|
||||
rotate(angle, origin=[0, 0]) {
|
||||
angle *= this.meta.mirrored ? -1 : 1
|
||||
rotate(angle, origin=[0, 0], resist=false) {
|
||||
angle *= (!resist && this.meta.mirrored) ? -1 : 1
|
||||
if (origin) {
|
||||
this.p = m.point.rotate(this.p, angle, origin)
|
||||
}
|
||||
|
|
|
@ -126,6 +126,30 @@ describe('Anchor', function() {
|
|||
)
|
||||
})
|
||||
|
||||
it('resist', function() {
|
||||
const p = new Point(0, 0, 0, {mirrored: true}) // origin, but mirrored
|
||||
|
||||
// resistance should be correctly propagated for shifts
|
||||
check(
|
||||
parse({shift: [1, 1]}, 'name', {}, p)(),
|
||||
[-1, 1, 0, {mirrored: true}]
|
||||
)
|
||||
check(
|
||||
parse({shift: [1, 1], resist: true}, 'name', {}, p)(),
|
||||
[1, 1, 0, {mirrored: true}]
|
||||
)
|
||||
|
||||
// ...and orients/rotations too
|
||||
check(
|
||||
parse({rotate: 10}, 'name', {}, p)(),
|
||||
[0, 0, -10, {mirrored: true}]
|
||||
)
|
||||
check(
|
||||
parse({rotate: 10, resist: true}, 'name', {}, p)(),
|
||||
[0, 0, 10, {mirrored: true}]
|
||||
)
|
||||
})
|
||||
|
||||
it('string', function() {
|
||||
// basic string form
|
||||
check(
|
||||
|
|
|
@ -36,7 +36,7 @@ describe('Point', function() {
|
|||
|
||||
it('shifting', function() {
|
||||
const p = new Point(0, 0, -90) // at origin, "looking right"
|
||||
// absolute shift up and left, should be up and left
|
||||
// non-relative shift up and left, should be up and left
|
||||
check(p.clone().shift([-1, 1], false), [-1, 1, -90, {}])
|
||||
// relative shift up and left, should be up and right
|
||||
check(p.clone().shift([-1, 1]), [1, 1, -90, {}])
|
||||
|
@ -50,6 +50,19 @@ describe('Point', function() {
|
|||
check(p.clone().rotate(-90, [1, 1]), [1, 2, -90, {}])
|
||||
})
|
||||
|
||||
it('resistance', function() {
|
||||
const p = new Point(0, 0, 0, {mirrored: true}) // origin, but mirrored
|
||||
// non-relative shift up and left, mirroring changes it to up and right
|
||||
check(p.clone().shift([-1, 1], false), [1, 1, 0, {mirrored: true}])
|
||||
// ...but resistance keeps it up and left
|
||||
check(p.clone().shift([-1, 1], false, true), [-1, 1, 0, {mirrored: true}])
|
||||
|
||||
// mirroring changes rotation direction, too
|
||||
check(p.clone().rotate(-90), [0, 0, 90, {mirrored: true}])
|
||||
// ...but not when resistance is applied
|
||||
check(p.clone().rotate(-90, false, true), [0, 0, -90, {mirrored: true}])
|
||||
})
|
||||
|
||||
it('mirroring', function() {
|
||||
const p = new Point(0, 1, 0)
|
||||
// make sure mirroring inverts rotation, as well as positions correctly
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue