
* Added intersect aggregator * Addressed stylistic PR feedback * Set the rotation of the intersected point to the second point’s rotation * Revert "Set the rotation of the intersected point to the second point’s rotation" This reverts commit d210a98f79a8866519fc9695487a9ea235167b8b. * Adjusted aggregate function to not need axis1 and axis2 parameters * Add assert to check for exactly 2 parts * Add unit tests for the aggregate intersect method * Change the assert string to use ${name.length} * Change test group name to align with style guide * Update intersect logic to consider negative Y axis --------- Co-authored-by: Marco Massarelli <60667061+ceoloide@users.noreply.github.com>
263 lines
No EOL
7.6 KiB
JavaScript
263 lines
No EOL
7.6 KiB
JavaScript
const {parse} = require('../../src/anchor')
|
|
const Point = require('../../src/point')
|
|
const {check} = require('../helpers/point')
|
|
|
|
describe('Anchor', function() {
|
|
|
|
const points = {
|
|
o: new Point(0, 0, 0, {label: 'o'}),
|
|
rotated_o: new Point(0, 0, 90, {label: 'rotated_o'}),
|
|
o_five: new Point(0, 5, 0, {label: 'o_five'}),
|
|
five_o: new Point(5, 0, 0, {label: 'five_o'}),
|
|
five: new Point(5, 5, 90, {label: 'five'}),
|
|
ten: new Point(10, 10, -90, {label: 'ten'}),
|
|
mirror_ten: new Point(-10, 10, 90, {mirrored: true})
|
|
}
|
|
|
|
it('params', function() {
|
|
// an empty anchor definition leads to the default point
|
|
check(
|
|
parse({}, 'name')(),
|
|
[0, 0, 0, {}]
|
|
)
|
|
// single reference
|
|
check(
|
|
parse({ref: 'o'}, 'name', points)(),
|
|
[0, 0, 0, {label: 'o'}]
|
|
)
|
|
// default point can be overridden
|
|
check(
|
|
parse({}, 'name', {}, new Point(1, 1))(),
|
|
[1, 1, 0, {}]
|
|
)
|
|
// mirrored references can be forced
|
|
check(
|
|
parse({ref: 'ten'}, 'name', points, undefined, true)(),
|
|
[-10, 10, 90, {mirrored: true}]
|
|
)
|
|
})
|
|
|
|
it('recursive', function() {
|
|
// recursive references are supported (keeping metadata)
|
|
check(
|
|
parse({
|
|
ref: {
|
|
ref: 'o',
|
|
shift: [2, 2]
|
|
}
|
|
}, 'name', points)(),
|
|
[2, 2, 0, {label: 'o'}]
|
|
)
|
|
})
|
|
|
|
it('aggregate', function() {
|
|
// average of multiple references (metadata gets ignored)
|
|
check(
|
|
parse({
|
|
aggregate: {
|
|
parts: ['o', 'ten']
|
|
}
|
|
}, 'name', points)(),
|
|
[5, 5, -45, {}]
|
|
)
|
|
// empty parts
|
|
check(
|
|
parse({
|
|
aggregate: {
|
|
}
|
|
}, 'name', points)(),
|
|
[0, 0, 0, {}]
|
|
)
|
|
// can't have aggregate and ref together
|
|
parse({
|
|
aggregate: {
|
|
parts: ['o', 'ten']
|
|
},
|
|
ref : 'ten'
|
|
}, 'name', points).should.throw()
|
|
})
|
|
it('intersect', function() {
|
|
// points that intersect on a negative Y axis
|
|
check(
|
|
parse({
|
|
aggregate: {
|
|
parts: ['o','ten'],
|
|
method: 'intersect'
|
|
}
|
|
}, 'name', points)(),
|
|
[0,10,0,{}]
|
|
)
|
|
|
|
// points that have parallel Y axis, i.e. never intersect
|
|
parse({
|
|
aggregate: {
|
|
parts: ['o','five_o'],
|
|
method: 'intersect'
|
|
}
|
|
}, 'name', points).should.throw(`The points under "name.aggregate.parts" do not intersect!`)
|
|
|
|
// points intersect on their positive Y axis
|
|
check(
|
|
parse({
|
|
aggregate: {
|
|
parts: ['o','five'],
|
|
method: 'intersect'
|
|
}
|
|
}, 'name', points)(),
|
|
[0, 5, 0, {}]
|
|
)
|
|
|
|
// intersecting points with the same coordinates, but different rotations
|
|
check(
|
|
parse({
|
|
aggregate: {
|
|
parts: ['o','rotated_o'],
|
|
method: 'intersect'
|
|
}
|
|
}, 'name', points)(),
|
|
[0, 0, 0, {}]
|
|
)
|
|
|
|
// points with overlapping Y axis
|
|
parse({
|
|
aggregate: {
|
|
parts: ['o','o_five'],
|
|
method: 'intersect'
|
|
}
|
|
}, 'name', points).should.throw(`The points under "name.aggregate.parts" do not intersect!`)
|
|
|
|
// more than two parts
|
|
parse({
|
|
aggregate: {
|
|
parts: ['o', `five`, `ten`],
|
|
method: 'intersect'
|
|
}
|
|
}, 'name', points).should.throw(`Intersect expects exactly two parts, but it got 3!`)
|
|
|
|
// only one part
|
|
parse({
|
|
aggregate: {
|
|
parts: ['o'],
|
|
method: 'intersect'
|
|
}
|
|
}, 'name', points).should.throw(`Intersect expects exactly two parts, but it got 1!`)
|
|
|
|
// no parts
|
|
parse({
|
|
aggregate: {
|
|
method: 'intersect'
|
|
}
|
|
}, 'name', points).should.throw(`Intersect expects exactly two parts, but it got 0!`)
|
|
})
|
|
|
|
it('shift', function() {
|
|
// normal shift
|
|
check(
|
|
parse({shift: [1, 1]}, 'name')(),
|
|
[1, 1, 0, {}]
|
|
)
|
|
// shift should respect mirrored points (and invert along the x axis)
|
|
check(
|
|
parse({ref: 'mirror_ten', shift: [1, 1]}, 'name', points)(),
|
|
[-11, 9, 90, {mirrored: true}]
|
|
)
|
|
})
|
|
|
|
it('orient', function() {
|
|
// an orient by itself is equal to rotation
|
|
check(
|
|
parse({orient: 10}, 'name')(),
|
|
[0, 0, 10, {}]
|
|
)
|
|
// orient acts before shifting
|
|
// so when we orient to the right, an upward shift goes to the right
|
|
check(
|
|
parse({orient: -90, shift: [0, 1]}, 'name')(),
|
|
[1, 0, -90, {}]
|
|
)
|
|
// orient towards another point (and then move a diagonal to get to [1, 1])
|
|
check(
|
|
parse({orient: 'ten', shift: [0, Math.SQRT2]}, 'name', points)(),
|
|
[1, 1, -45, {}]
|
|
)
|
|
})
|
|
|
|
it('rotate', function() {
|
|
// basic rotation
|
|
check(
|
|
parse({rotate: 10}, 'name')(),
|
|
[0, 0, 10, {}]
|
|
)
|
|
// rotate acts *after* shifting
|
|
// so even tho we rotate to the right, an upward shift does go upward
|
|
check(
|
|
parse({shift: [0, 1], rotate: -90}, 'name')(),
|
|
[0, 1, -90, {}]
|
|
)
|
|
// rotate towards another point
|
|
check(
|
|
parse({rotate: {shift: [-1, -1]}}, 'name')(),
|
|
[0, 0, 135, {}]
|
|
)
|
|
})
|
|
|
|
it('affect', function() {
|
|
// affect can restrict which point fields (x, y, r) are affected by the transformations
|
|
check(
|
|
parse({orient: -90, shift: [0, 1], rotate: 10, affect: 'r'}, 'name')(),
|
|
[0, 0, -80, {}]
|
|
)
|
|
check(
|
|
parse({orient: -90, shift: [0, 1], rotate: 10, affect: 'xy'}, 'name')(),
|
|
[1, 0, 0, {}]
|
|
)
|
|
// affects can also be arrays (example same as above)
|
|
check(
|
|
parse({orient: -90, shift: [0, 1], rotate: 10, affect: ['x', 'y']}, 'name')(),
|
|
[1, 0, 0, {}]
|
|
)
|
|
})
|
|
|
|
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(
|
|
parse('ten', 'name', points)(),
|
|
[10, 10, -90, {label: 'ten'}]
|
|
)
|
|
})
|
|
|
|
it('array', function() {
|
|
// basic multi-anchor
|
|
check(
|
|
parse([
|
|
{shift: [1, 1]},
|
|
{rotate: 10}
|
|
], 'name')(),
|
|
[1, 1, 10, {}]
|
|
)
|
|
})
|
|
}) |