[READ-ONLY] Mirror of https://github.com/flo-bit/shapecraft. flo-bit.dev/shapecraft/
0

Configure Feed

Select the types of activity you want to include in your feed.

shapecraft / tests / modifiers-ops.test.ts
3.2 kB 88 lines
1import { describe, it, expect } from 'vitest' 2import { box, sphere, cylinder } from '../src/primitives' 3import { weld, mirror, array, radialArray, subtract, union, intersect } from '../src/ops' 4 5describe('weld', () => { 6 it('merges coincident vertices and indexes the mesh', () => { 7 const b = box({ size: 1 }) // non-indexed, 24 verts (4 per face × 6) 8 const w = weld(b) 9 expect(w.geometry.getIndex()).not.toBeNull() 10 expect(w.vertexCount).toBe(8) // a cube has 8 unique corners 11 expect(w.faceCount).toBe(b.faceCount) // same triangles 12 }) 13}) 14 15describe('mirror', () => { 16 it('doubles geometry and spans both sides of the plane', () => { 17 const b = box({ size: 1 }).translate(1, 0, 0) // sits at x∈[0.5,1.5] 18 const m = mirror(b, { axis: 'x', position: 0 }) 19 expect(m.faceCount).toBe(b.faceCount * 2) 20 const bb = m.boundingBox 21 expect(bb.min.x).toBeLessThan(-0.4) // reflected copy on the −x side 22 expect(bb.max.x).toBeGreaterThan(1.4) 23 }) 24 25 it('keepOriginal:false returns just the reflection', () => { 26 const b = box({ size: 1 }).translate(1, 0, 0) 27 const m = mirror(b, { axis: 'x', keepOriginal: false }) 28 expect(m.faceCount).toBe(b.faceCount) 29 expect(m.boundingBox.max.x).toBeLessThan(-0.4) 30 }) 31}) 32 33describe('array', () => { 34 it('repeats count times with an offset', () => { 35 const b = box({ size: 1 }) 36 const a = array(b, { count: 4, offset: [2, 0, 0] }) 37 expect(a.vertexCount).toBe(b.vertexCount * 4) 38 // 4 boxes spaced by 2 along x → spans ~[-0.5, 6.5] 39 expect(a.boundingBox.max.x).toBeGreaterThan(6) 40 }) 41 42 it('count 1 is just the original', () => { 43 const b = box({ size: 1 }) 44 expect(array(b, { count: 1 }).vertexCount).toBe(b.vertexCount) 45 }) 46}) 47 48describe('radialArray', () => { 49 it('places copies around an axis', () => { 50 const s = sphere({ radius: 0.3 }) 51 const r = radialArray(s, { count: 6, radius: 1, axis: 'y' }) 52 expect(r.vertexCount).toBe(s.vertexCount * 6) 53 const bb = r.boundingBox 54 // a ring of radius 1 → spans roughly ±1.3 in x and z 55 expect(bb.max.x).toBeGreaterThan(1) 56 expect(bb.max.z).toBeGreaterThan(1) 57 }) 58}) 59 60describe('boolean (CSG)', () => { 61 it('subtract carves a hole, keeping the outer bounds', () => { 62 const block = box({ size: 2 }) 63 const drill = cylinder({ radius: 0.4, height: 3, segments: 16 }) 64 const result = subtract(block, drill) 65 expect(result.vertexCount).toBeGreaterThan(0) 66 const p = result.positions 67 for (let i = 0; i < p.length; i++) expect(Number.isFinite(p[i])).toBe(true) 68 const bb = result.boundingBox 69 expect(bb.max.x).toBeCloseTo(1, 1) 70 expect(bb.min.x).toBeCloseTo(-1, 1) 71 }) 72 73 it('union spans both volumes', () => { 74 const a = box({ size: 1 }) 75 const b = box({ size: 1 }).translate(1.4, 0, 0) 76 const bb = union(a, b).boundingBox 77 expect(bb.min.x).toBeCloseTo(-0.5, 1) 78 expect(bb.max.x).toBeCloseTo(1.9, 1) 79 }) 80 81 it('intersect keeps only the overlap', () => { 82 const a = box({ size: 2 }) // x∈[-1,1] 83 const b = box({ size: 2 }).translate(1, 0, 0) // x∈[0,2] 84 const bb = intersect(a, b).boundingBox 85 expect(bb.min.x).toBeCloseTo(0, 1) 86 expect(bb.max.x).toBeCloseTo(1, 1) 87 }) 88})