1
0

Allow points/anchors to resist special mirror treatment

This commit is contained in:
Bán Dénes 2022-12-04 12:24:17 +01:00
parent 2cfdf10327
commit 3aef729465
4 changed files with 54 additions and 16 deletions

View File

@ -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('')

View File

@ -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)
}

View File

@ -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(

View File

@ -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