UNPKG

@bitbybit-dev/base

Version:

Bit By Bit Developers Base CAD Library to Program Geometry

131 lines (130 loc) 5.56 kB
import { GeometryHelper, MathBitByBit, Vector } from "./services"; export const TOLERANCE = 1e-7; export class UnitTestHelper { constructor() { const math = new MathBitByBit(); const geometryHelper = new GeometryHelper(); this.vector = new Vector(math, geometryHelper); } expectPointCloseTo(received, expected) { expect(received).toBeDefined(); if (!received) return; expect(received.length).toEqual(expected.length); expect(received[0]).toBeCloseTo(expected[0], TOLERANCE); expect(received[1]).toBeCloseTo(expected[1], TOLERANCE); if (expected.length > 2 && received.length > 2) { expect(received[2]).toBeCloseTo(expected[2], TOLERANCE); } } expectPointsCloseTo(received, expected) { expect(received.length).toEqual(expected.length); received.forEach((p, i) => this.expectPointCloseTo(p, expected[i])); } expectLineCloseTo(received, expected) { expect(received).toBeDefined(); if (!received) return; this.expectPointCloseTo(received.start, expected.start); this.expectPointCloseTo(received.end, expected.end); } expectLinesCloseTo(received, expected) { expect(received.length).toEqual(expected.length); received.forEach((l, i) => this.expectLineCloseTo(l, expected[i])); } expectSegmentCloseTo(received, expected, precision = TOLERANCE) { expect(received).toBeDefined(); if (!received) return; expect(received).toHaveLength(2); const order1Matches = Math.abs(this.vector.dist({ first: received[0], second: expected[0] })) < precision && Math.abs(this.vector.dist({ first: received[1], second: expected[1] })) < precision; const order2Matches = Math.abs(this.vector.dist({ first: received[0], second: expected[1] })) < precision && Math.abs(this.vector.dist({ first: received[1], second: expected[0] })) < precision; expect(order1Matches || order2Matches).toBe(true); } expectPlaneCloseTo(received, expected, precision = TOLERANCE) { expect(received).toBeDefined(); if (!received) return; const normalDir1 = this.vector.sub({ first: received.normal, second: expected.normal }); const normalDir2 = this.vector.add({ first: received.normal, second: expected.normal }); const dir1Match = this.vector.lengthSq({ vector: normalDir1 }) < precision * precision; const dir2Match = this.vector.lengthSq({ vector: normalDir2 }) < precision * precision; expect(dir1Match || dir2Match).toBe(true); expect(received.d).toBeCloseTo(dir1Match ? expected.d : -expected.d, precision); } expectMatrixCloseTo(received, expected) { expect(received).toBeDefined(); if (!received) return; expect(received).toHaveLength(16); expect(expected).toHaveLength(16); for (let i = 0; i < 16; i++) { expect(received[i]).toBeCloseTo(expected[i], TOLERANCE); } } expectMatrixesCloseTo(received, expected) { expect(received).toBeDefined(); if (!received) return; expect(received.length).toEqual(expected.length); received.forEach((matrix, i) => this.expectMatrixCloseTo(matrix, expected[i])); } /** Helper to compare two arrays of points for near-equality, ignoring order */ expectPointArraysCloseTo(actual, expected, tolerance = 1e-6) { // Use expectPointsClose helper for individual point comparison if needed const expectPointsClose = (act, exp, tol = 1e-6) => { const precision = Math.max(0, Math.ceil(-Math.log10(tol)) - 1); if (exp === undefined) { expect(act).toBeUndefined(); } else { expect(act).toBeDefined(); if (act) { expect(act[0]).toBeCloseTo(exp[0], precision); expect(act[1]).toBeCloseTo(exp[1], precision); expect(act[2]).toBeCloseTo(exp[2], precision); } } }; expect(actual).toBeDefined(); // Proceed only if actual is defined if (actual) { expect(actual.length).toEqual(expected.length); // Sort both arrays to compare independent of order const sortedActual = this.sortPoints(actual); const sortedExpected = this.sortPoints(expected); for (let i = 0; i < sortedExpected.length; i++) { expectPointsClose(sortedActual[i], sortedExpected[i], tolerance); } } } sortPoints(points) { return [...points].sort((a, b) => { if (a[0] !== b[0]) return a[0] - b[0]; if (a[1] !== b[1]) return a[1] - b[1]; return a[2] - b[2]; }); } sortPolylinesForComparison(polylines) { return polylines.sort((a, b) => { const pA = a.points[0]; const pB = b.points[0]; if (pA[0] !== pB[0]) return pA[0] - pB[0]; if (pA[1] !== pB[1]) return pA[1] - pB[1]; return pA[2] - pB[2]; }); } expectFloatArraysClose(actual, expected, precision) { expect(actual.length).toBe(expected.length); actual.forEach((val, index) => { expect(val).toBeCloseTo(expected[index], precision); }); } ; }