@jscad/modeling
Version:
Constructive Solid Geometry (CSG) Library for JSCAD
167 lines (151 loc) • 7.49 kB
JavaScript
const test = require('ava')
const { comparePoints } = require('../../../test/helpers')
const { geom2 } = require('../../geometries')
const { circle, rectangle } = require('../../primitives')
const { union } = require('./index')
const { center } = require('../transforms/center')
const { translate } = require('../transforms/translate')
test('union of one or more geom2 objects produces expected geometry', (t) => {
const geometry1 = circle({ radius: 2, segments: 8 })
// union of one object
const result1 = union(geometry1)
let obs = geom2.toPoints(result1)
let exp = [
[2, 0],
[1.4142000000000001, 1.4142000000000001],
[0, 2],
[-1.4142000000000001, 1.4142000000000001],
[-2, 0],
[-1.4142000000000001, -1.4142000000000001],
[0, -2],
[1.4142000000000001, -1.4142000000000001]
]
t.notThrows(() => geom2.validate(result1))
t.true(comparePoints(obs, exp))
// union of two non-overlapping objects
const geometry2 = center({ relativeTo: [10, 10, 0] }, rectangle({ size: [4, 4] }))
const result2 = union(geometry1, geometry2)
obs = geom2.toPoints(result2)
exp = [
[2, 0],
[1.4142000000000001, 1.4142000000000001],
[0, 2],
[-1.4142000000000001, 1.4142000000000001],
[-2, 0],
[-1.4142000000000001, -1.4142000000000001],
[0, -2],
[8, 12],
[8, 8],
[12, 8],
[12, 12],
[1.4142000000000001, -1.4142000000000001]
]
t.notThrows(() => geom2.validate(result2))
t.true(comparePoints(obs, exp))
// union of two partially overlapping objects
const geometry3 = rectangle({ size: [18, 18] })
const result3 = union(geometry2, geometry3)
obs = geom2.toPoints(result3)
exp = [
[11.999973333333333, 11.999973333333333],
[7.999933333333333, 11.999973333333333],
[9.000053333333334, 7.999933333333333],
[-9.000053333333334, 9.000053333333334],
[-9.000053333333334, -9.000053333333334],
[9.000053333333334, -9.000053333333334],
[7.999933333333333, 9.000053333333334],
[11.999973333333333, 7.999933333333333]
]
t.notThrows(() => geom2.validate(result3))
t.true(comparePoints(obs, exp))
// union of two completely overlapping objects
const result4 = union(geometry1, geometry3)
obs = geom2.toPoints(result4)
exp = [
[-9.000046666666666, -9.000046666666666],
[9.000046666666666, -9.000046666666666],
[9.000046666666666, 9.000046666666666],
[-9.000046666666666, 9.000046666666666]
]
t.notThrows(() => geom2.validate(result4))
t.true(comparePoints(obs, exp))
// union of unions of non-overlapping objects (BSP gap from #907)
const circ = circle({ radius: 1, segments: 32 })
const result5 = union(
union(
translate([17, 21], circ),
translate([7, 0], circ)
),
union(
translate([3, 21], circ),
translate([17, 21], circ)
)
)
obs = geom2.toPoints(result5)
t.notThrows.skip(() => geom2.validate(result5))
t.is(obs.length, 112)
})
test('union of geom2 with closing issues #15', (t) => {
const c = geom2.create([
[[-45.82118740347841168159, -16.85726810555620147625], [-49.30331715865012398581, -14.68093629710870118288]],
[[-49.10586702080816223770, -15.27604177352110781385], [-48.16645938811709015681, -15.86317173589183227023]],
[[-49.60419521731581937729, -14.89550781504266296906], [-49.42407001323204696064, -15.67605088949303393520]],
[[-49.05727291218684626983, -15.48661638542171203881], [-49.10586702080816223770, -15.27604177352110781385]],
[[-49.30706235399220815907, -15.81529674600091794900], [-46.00505780290426827150, -17.21108547999804727624]],
[[-46.00505780290426827150, -17.21108547999804727624], [-45.85939703723252591772, -17.21502856394236857795]],
[[-45.85939703723252591772, -17.21502856394236857795], [-45.74972032664388166268, -17.11909303495791334626]],
[[-45.74972032664388166268, -17.11909303495791334626], [-45.73424573227583067592, -16.97420292661295349035]],
[[-45.73424573227583067592, -16.97420292661295349035], [-45.82118740347841168159, -16.85726810555620147625]],
[[-49.30331715865012398581, -14.68093629710870118288], [-49.45428884427643367871, -14.65565769658912387285]],
[[-49.45428884427643367871, -14.65565769658912387285], [-49.57891661679624917269, -14.74453612941635327616]],
[[-49.57891661679624917269, -14.74453612941635327616], [-49.60419521731581937729, -14.89550781504266296906]],
[[-49.42407001323204696064, -15.67605088949303393520], [-49.30706235399220815907, -15.81529674600091794900]],
[[-48.16645938811709015681, -15.86317173589183227023], [-49.05727291218684626983, -15.48661638542171203881]]
])
const d = geom2.create([
[[-49.03431352173912216585, -15.58610714407888764299], [-49.21443872582289458251, -14.80556406962851667686]],
[[-68.31614651314507113966, -3.10790373951434872879], [-49.34036769611472550423, -15.79733157434056778357]],
[[-49.58572929483430868913, -14.97552686612213790340], [-49.53755741140093959984, -15.18427183431472826669]],
[[-49.53755741140093959984, -15.18427183431472826669], [-54.61235529924312714911, -11.79066769321313756791]],
[[-49.30227466841120076424, -14.68159232649114187552], [-68.09792828135776687759, -2.77270756611528668145]],
[[-49.21443872582289458251, -14.80556406962851667686], [-49.30227466841120076424, -14.68159232649114187552]],
[[-49.34036769611472550423, -15.79733157434056778357], [-49.18823337756091262918, -15.82684012194931710837]],
[[-49.18823337756091262918, -15.82684012194931710837], [-49.06069007212390431505, -15.73881563386780157998]],
[[-49.06069007212390431505, -15.73881563386780157998], [-49.03431352173912216585, -15.58610714407888764299]],
[[-68.09792828135776687759, -2.77270756611528668145], [-68.24753735887460948106, -2.74623350179570024920]],
[[-68.24753735887460948106, -2.74623350179570024920], [-68.37258141465594007968, -2.83253376987636329432]],
[[-68.37258141465594007968, -2.83253376987636329432], [-68.40089829889257089235, -2.98180502037078554167]],
[[-68.40089829889257089235, -2.98180502037078554167], [-68.31614651314507113966, -3.10790373951434872879]],
[[-54.61235529924312714911, -11.79066769321313756791], [-49.58572929483430868913, -14.97552686612213790340]]
])
// geom2.toOutlines(c)
// geom2.toOutlines(d)
const obs = union(c, d)
// const outlines = geom2.toOutlines(obs)
const pts = geom2.toPoints(obs)
const exp = [
[-49.10585516965137, -15.276000175919414],
[-49.0573272145917, -15.486679335654257],
[-49.307011370463215, -15.815286644243773],
[-46.00502320253235, -17.211117609669667],
[-45.85943933735334, -17.215031154432545],
[-45.74972963250071, -17.119149307742074],
[-45.734205904941305, -16.974217700023555],
[-48.166473975068946, -15.86316234184296],
[-49.318621553259746, -15.801589237573706],
[-49.585786209072104, -14.975570389622606],
[-68.31614189569036, -3.1078763476921982],
[-49.53751915699663, -15.184292776976012],
[-68.09789654941396, -2.7727464644978874],
[-68.24752441084793, -2.7462648116024244],
[-68.37262739176788, -2.8324932478777995],
[-68.40093536555268, -2.98186020632758],
[-54.61234310251047, -11.79072766159384],
[-49.30335872868453, -14.680880468978017],
[-49.34040695243976, -15.797284338334542],
[-45.82121705016925, -16.857333163105647]
]
t.notThrows(() => geom2.validate(obs))
t.is(pts.length, 20) // number of sides in union
t.true(comparePoints(pts, exp))
})