Add intersect aggregator (#102)
* 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>
This commit is contained in:
parent
e924352763
commit
6e520e745a
2 changed files with 114 additions and 2 deletions
|
@ -1,6 +1,7 @@
|
|||
const u = require('./utils')
|
||||
const a = require('./assert')
|
||||
const Point = require('./point')
|
||||
const m = require('makerjs')
|
||||
|
||||
const mirror_ref = exports.mirror = (ref, mirror=true) => {
|
||||
if (mirror) {
|
||||
|
@ -28,7 +29,41 @@ const aggregators = {
|
|||
r += part.r
|
||||
}
|
||||
return new Point(x / len, y / len, r / len)
|
||||
}
|
||||
},
|
||||
intersect: (config, name, parts) => {
|
||||
// a line is generated from a point by taking their
|
||||
// (rotated) Y axis. The line is not extended to
|
||||
// +/- Infinity as that doesn't work with makerjs.
|
||||
// An arbitrary offset of 1 meter is considered
|
||||
// sufficient for practical purposes, and the point
|
||||
// coordinates are used as pivot point for the rotation.
|
||||
const get_line_from_point = (point, offset=1000) => {
|
||||
const origin = [point.x, point.y]
|
||||
const p1 = [point.x, point.y - offset]
|
||||
const p2 = [point.x, point.y + offset]
|
||||
|
||||
let line = new m.paths.Line(p1, p2)
|
||||
line = m.path.rotate(line, point.r, origin)
|
||||
|
||||
return line
|
||||
}
|
||||
|
||||
a.unexpected(config, name, aggregator_common)
|
||||
a.assert(parts.length==2, `Intersect expects exactly two parts, but it got ${parts.length}!`)
|
||||
|
||||
const line1 = get_line_from_point(parts[0])
|
||||
const line2 = get_line_from_point(parts[1])
|
||||
const intersection = m.path.intersection(line1, line2)
|
||||
|
||||
a.assert(intersection, `The points under "${name}.parts" do not intersect!`)
|
||||
|
||||
const intersection_point_arr = intersection.intersectionPoints[0]
|
||||
const intersection_point = new Point(
|
||||
intersection_point_arr[0], intersection_point_arr[1], 0
|
||||
)
|
||||
|
||||
return intersection_point
|
||||
},
|
||||
}
|
||||
|
||||
const anchor = exports.parse = (raw, name, points={}, start=new Point(), mirror=false) => units => {
|
||||
|
@ -56,7 +91,7 @@ const anchor = exports.parse = (raw, name, points={}, start=new Point(), mirror=
|
|||
//
|
||||
// Reference or aggregate handling
|
||||
//
|
||||
|
||||
|
||||
let point = start.clone()
|
||||
if (raw.ref !== undefined && raw.aggregate !== undefined) {
|
||||
throw new Error(`Fields "ref" and "aggregate" cannot appear together in anchor "${name}"!`)
|
||||
|
|
|
@ -6,6 +6,10 @@ 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})
|
||||
}
|
||||
|
@ -72,6 +76,79 @@ describe('Anchor', function() {
|
|||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue