Skip to content

Commit 146909c

Browse files
additional solid unit tests
1 parent 156427e commit 146909c

File tree

1 file changed

+281
-13
lines changed

1 file changed

+281
-13
lines changed

packages/dev/occt/lib/services/shapes/solid.test.ts

Lines changed: 281 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,13 @@ describe("OCCT solid unit tests", () => {
163163
const filteredPoints = solid.filterSolidPoints(filterOptions);
164164
expect(filteredPoints.length).toBe(13);
165165
expect(filteredPoints).toEqual([
166-
[ 0, 0, -1 ], [ -0.5, 0, -0.5 ],
167-
[ 0, 0, -0.5 ], [ 0.5, 0, -0.5 ],
168-
[ -1, 0, 0 ], [ -0.5, 0, 0 ],
169-
[ 0, 0, 0 ], [ 0.5, 0, 0 ],
170-
[ 1, 0, 0 ], [ -0.5, 0, 0.5 ],
171-
[ 0, 0, 0.5 ], [ 0.5, 0, 0.5 ],
172-
[ 0, 0, 1 ]
166+
[0, 0, -1], [-0.5, 0, -0.5],
167+
[0, 0, -0.5], [0.5, 0, -0.5],
168+
[-1, 0, 0], [-0.5, 0, 0],
169+
[0, 0, 0], [0.5, 0, 0],
170+
[1, 0, 0], [-0.5, 0, 0.5],
171+
[0, 0, 0.5], [0.5, 0, 0.5],
172+
[0, 0, 1]
173173
]);
174174
sphere.delete();
175175
f1.delete();
@@ -190,12 +190,12 @@ describe("OCCT solid unit tests", () => {
190190
const filteredPoints = solid.filterSolidPoints(filterOptions);
191191
expect(filteredPoints.length).toBe(12);
192192
expect(filteredPoints).toEqual([
193-
[ -1, 0, -1 ], [ -0.5, 0, -1 ],
194-
[ 0.5, 0, -1 ], [ 1, 0, -1 ],
195-
[ -1, 0, -0.5 ], [ 1, 0, -0.5 ],
196-
[ -1, 0, 0.5 ], [ 1, 0, 0.5 ],
197-
[ -1, 0, 1 ], [ -0.5, 0, 1 ],
198-
[ 0.5, 0, 1 ], [ 1, 0, 1 ]
193+
[-1, 0, -1], [-0.5, 0, -1],
194+
[0.5, 0, -1], [1, 0, -1],
195+
[-1, 0, -0.5], [1, 0, -0.5],
196+
[-1, 0, 0.5], [1, 0, 0.5],
197+
[-1, 0, 1], [-0.5, 0, 1],
198+
[0.5, 0, 1], [1, 0, 1]
199199
]);
200200
sphere.delete();
201201
f1.delete();
@@ -229,4 +229,272 @@ describe("OCCT solid unit tests", () => {
229229
expect(filteredPoints.length).toBe(0);
230230
sphere.delete();
231231
});
232+
233+
// I-Beam profile solid tests
234+
it("should create an I-beam profile solid with default values", async () => {
235+
// I-beam area: 2 flanges (width * flangeThickness) + web ((height - 2*flangeThickness) * webThickness)
236+
// width=2, height=3, webThickness=0.2, flangeThickness=0.3, extrusionLengthFront=1
237+
// Area = 2 * (2 * 0.3) + (3 - 2*0.3) * 0.2 = 1.2 + 2.4 * 0.2 = 1.2 + 0.48 = 1.68
238+
// Volume = 1.68 * 1 = 1.68
239+
const opt = new Inputs.OCCT.IBeamProfileSolidDto(2, 3, 0.2, 0.3);
240+
opt.extrusionLengthFront = 1;
241+
opt.extrusionLengthBack = 0;
242+
const ibeam = solid.createIBeamProfileSolid(opt);
243+
const volume = solid.getSolidVolume({ shape: ibeam });
244+
expect(volume).toBeCloseTo(1.68);
245+
ibeam.delete();
246+
});
247+
248+
it("should create an I-beam profile solid with bidirectional extrusion", async () => {
249+
// Same area as above: 1.68
250+
// Volume = 1.68 * (1 + 0.5) = 1.68 * 1.5 = 2.52
251+
const opt = new Inputs.OCCT.IBeamProfileSolidDto(2, 3, 0.2, 0.3);
252+
opt.extrusionLengthFront = 1;
253+
opt.extrusionLengthBack = 0.5;
254+
const ibeam = solid.createIBeamProfileSolid(opt);
255+
const volume = solid.getSolidVolume({ shape: ibeam });
256+
expect(volume).toBeCloseTo(2.52);
257+
ibeam.delete();
258+
});
259+
260+
// H-Beam profile solid tests
261+
it("should create an H-beam profile solid with default values", async () => {
262+
// H-beam area: 2 flanges (height * flangeThickness) + web ((width - 2*flangeThickness) * webThickness)
263+
// width=2, height=3, webThickness=0.2, flangeThickness=0.3, extrusionLengthFront=1
264+
// Area = 2 * (3 * 0.3) + (2 - 2*0.3) * 0.2 = 1.8 + 1.4 * 0.2 = 1.8 + 0.28 = 2.08
265+
// Volume = 2.08 * 1 = 2.08
266+
const opt = new Inputs.OCCT.HBeamProfileSolidDto(2, 3, 0.2, 0.3);
267+
opt.extrusionLengthFront = 1;
268+
opt.extrusionLengthBack = 0;
269+
const hbeam = solid.createHBeamProfileSolid(opt);
270+
const volume = solid.getSolidVolume({ shape: hbeam });
271+
expect(volume).toBeCloseTo(2.08);
272+
hbeam.delete();
273+
});
274+
275+
it("should create an H-beam profile solid with backward extrusion only", async () => {
276+
// Volume = 2.08 * 2 = 4.16
277+
const opt = new Inputs.OCCT.HBeamProfileSolidDto(2, 3, 0.2, 0.3);
278+
opt.extrusionLengthFront = 0;
279+
opt.extrusionLengthBack = 2;
280+
const hbeam = solid.createHBeamProfileSolid(opt);
281+
const volume = solid.getSolidVolume({ shape: hbeam });
282+
expect(volume).toBeCloseTo(4.16);
283+
hbeam.delete();
284+
});
285+
286+
// T-Beam profile solid tests
287+
it("should create a T-beam profile solid with default values", async () => {
288+
// T-beam area: 1 flange (width * flangeThickness) + web ((height - flangeThickness) * webThickness)
289+
// width=2, height=2, webThickness=0.2, flangeThickness=0.3, extrusionLengthFront=1
290+
// Area = (2 * 0.3) + (2 - 0.3) * 0.2 = 0.6 + 1.7 * 0.2 = 0.6 + 0.34 = 0.94
291+
// Volume = 0.94 * 1 = 0.94
292+
const opt = new Inputs.OCCT.TBeamProfileSolidDto(2, 2, 0.2, 0.3);
293+
opt.extrusionLengthFront = 1;
294+
opt.extrusionLengthBack = 0;
295+
const tbeam = solid.createTBeamProfileSolid(opt);
296+
const volume = solid.getSolidVolume({ shape: tbeam });
297+
expect(volume).toBeCloseTo(0.94);
298+
tbeam.delete();
299+
});
300+
301+
// U-Beam profile solid tests
302+
it("should create a U-beam profile solid with default values", async () => {
303+
// U-beam area: 2 vertical flanges + bottom web
304+
// width=2, height=3, webThickness=0.2, flangeThickness=0.3, flangeWidth=0.5, extrusionLengthFront=1
305+
const opt = new Inputs.OCCT.UBeamProfileSolidDto(2, 3, 0.2, 0.3, 0.5);
306+
opt.extrusionLengthFront = 1;
307+
opt.extrusionLengthBack = 0;
308+
const ubeam = solid.createUBeamProfileSolid(opt);
309+
const volume = solid.getSolidVolume({ shape: ubeam });
310+
// Actual computed volume is 2.25
311+
expect(volume).toBeCloseTo(2.25);
312+
ubeam.delete();
313+
});
314+
315+
// Star solid tests
316+
it("should create a star solid with default values", async () => {
317+
const opt = new Inputs.OCCT.StarSolidDto(2, 1, 5);
318+
opt.extrusionLengthFront = 1;
319+
opt.extrusionLengthBack = 0;
320+
const star = solid.createStarSolid(opt);
321+
const volume = solid.getSolidVolume({ shape: star });
322+
// 5-pointed star area ≈ 5 * (0.5 * outerRadius * innerRadius * sin(2π/5)) = 5 * 0.5 * 2 * 1 * sin(72°)
323+
// For a 5-pointed star with outer=2, inner=1:
324+
// Area can be calculated as n * r1 * r2 * sin(π/n) where n=5
325+
// = 5 * 2 * 1 * sin(36°) ≈ 5 * 2 * 0.588 ≈ 5.878
326+
// Volume ≈ 5.878
327+
expect(volume).toBeCloseTo(5.877, 2);
328+
329+
star.delete();
330+
});
331+
332+
it("should create a star solid and verify volume is positive", async () => {
333+
const opt = new Inputs.OCCT.StarSolidDto(2, 1, 6);
334+
opt.half = false;
335+
opt.extrusionLengthFront = 1;
336+
opt.extrusionLengthBack = 0;
337+
const star = solid.createStarSolid(opt);
338+
const volume = solid.getSolidVolume({ shape: star });
339+
// 6-pointed star with outer=2, inner=1
340+
expect(volume).toBe(6);
341+
star.delete();
342+
});
343+
344+
// NGon solid tests
345+
it("should create a hexagon (6-gon) solid", async () => {
346+
// Hexagon area = (3 * sqrt(3) / 2) * r^2 where r is the radius
347+
// For radius = 1: Area = (3 * 1.732 / 2) * 1 = 2.598
348+
// Volume = 2.598 * 1 = 2.598
349+
const opt = new Inputs.OCCT.NGonSolidDto([0, 0, 0], [0, 1, 0], 6, 1);
350+
opt.extrusionLengthFront = 1;
351+
opt.extrusionLengthBack = 0;
352+
const hexagon = solid.createNGonSolid(opt);
353+
const volume = solid.getSolidVolume({ shape: hexagon });
354+
expect(volume).toBeCloseTo(2.598, 2);
355+
hexagon.delete();
356+
});
357+
358+
it("should create a pentagon (5-gon) solid", async () => {
359+
// Pentagon area = (5/4) * r^2 * sqrt(10 + 2*sqrt(5)) / sqrt(5)
360+
// Simplified: (5/2) * r^2 * sin(72°) = 2.5 * 1 * 0.951 = 2.378
361+
const opt = new Inputs.OCCT.NGonSolidDto([0, 0, 0], [0, 1, 0], 5, 1);
362+
opt.extrusionLengthFront = 1;
363+
opt.extrusionLengthBack = 0;
364+
const pentagon = solid.createNGonSolid(opt);
365+
const volume = solid.getSolidVolume({ shape: pentagon });
366+
expect(volume).toBeCloseTo(2.378, 2);
367+
pentagon.delete();
368+
});
369+
370+
it("should create a triangle (3-gon) solid", async () => {
371+
// Equilateral triangle inscribed in circle of radius r
372+
// Area = (3 * sqrt(3) / 4) * (r * sqrt(3))^2 = (3 * sqrt(3) / 4) * 3 * r^2 = (9 * sqrt(3) / 4) * r^2
373+
// For r = 1: Area = 1.299
374+
const opt = new Inputs.OCCT.NGonSolidDto([0, 0, 0], [0, 1, 0], 3, 1);
375+
opt.extrusionLengthFront = 1;
376+
opt.extrusionLengthBack = 0;
377+
const triangle = solid.createNGonSolid(opt);
378+
const volume = solid.getSolidVolume({ shape: triangle });
379+
expect(volume).toBeCloseTo(1.299, 2);
380+
triangle.delete();
381+
});
382+
383+
// Parallelogram solid tests
384+
it("should create a parallelogram solid", async () => {
385+
// Parallelogram area = width * height (base * height for the slanted shape)
386+
// width=2, height=1, angle=15 degrees
387+
// Area = 2 * 1 = 2
388+
// Volume = 2 * 1 = 2
389+
const opt = new Inputs.OCCT.ParallelogramSolidDto([0, 0, 0], [0, 1, 0], true, 2, 1, 15);
390+
opt.extrusionLengthFront = 1;
391+
opt.extrusionLengthBack = 0;
392+
const parallelogram = solid.createParallelogramSolid(opt);
393+
const volume = solid.getSolidVolume({ shape: parallelogram });
394+
expect(volume).toBeCloseTo(2);
395+
parallelogram.delete();
396+
});
397+
398+
it("should create a parallelogram solid with bidirectional extrusion", async () => {
399+
const opt = new Inputs.OCCT.ParallelogramSolidDto([0, 0, 0], [0, 1, 0], true, 2, 1, 30);
400+
opt.extrusionLengthFront = 1;
401+
opt.extrusionLengthBack = 1;
402+
const parallelogram = solid.createParallelogramSolid(opt);
403+
const volume = solid.getSolidVolume({ shape: parallelogram });
404+
// Volume = 2 * 2 = 4
405+
expect(volume).toBeCloseTo(4);
406+
parallelogram.delete();
407+
});
408+
409+
// Heart solid tests
410+
it("should create a heart solid", async () => {
411+
const opt = new Inputs.OCCT.HeartSolidDto([0, 0, 0], [0, 1, 0], 0, 2);
412+
opt.extrusionLengthFront = 1;
413+
opt.extrusionLengthBack = 0;
414+
const heart = solid.createHeartSolid(opt);
415+
const volume = solid.getSolidVolume({ shape: heart });
416+
// Heart shape volume depends on the parametric curve
417+
expect(volume).toBeCloseTo(2.732, 2);
418+
heart.delete();
419+
});
420+
421+
it("should create a rotated heart solid with same volume", async () => {
422+
const opt1 = new Inputs.OCCT.HeartSolidDto([0, 0, 0], [0, 1, 0], 0, 2);
423+
opt1.extrusionLengthFront = 1;
424+
opt1.extrusionLengthBack = 0;
425+
const heart1 = solid.createHeartSolid(opt1);
426+
427+
const opt2 = new Inputs.OCCT.HeartSolidDto([0, 0, 0], [0, 1, 0], 45, 2);
428+
opt2.extrusionLengthFront = 1;
429+
opt2.extrusionLengthBack = 0;
430+
const heart2 = solid.createHeartSolid(opt2);
431+
432+
const volume1 = solid.getSolidVolume({ shape: heart1 });
433+
const volume2 = solid.getSolidVolume({ shape: heart2 });
434+
expect(volume1).toBeCloseTo(volume2);
435+
heart1.delete();
436+
heart2.delete();
437+
});
438+
439+
// Christmas tree solid tests
440+
it("should create a christmas tree solid", async () => {
441+
const opt = new Inputs.OCCT.ChristmasTreeSolidDto(6, 1.5, 3, 5, 1, 1, false, 0, [0, 0, 0], [0, 1, 0]);
442+
opt.extrusionLengthFront = 1;
443+
opt.extrusionLengthBack = 0;
444+
const tree = solid.createChristmasTreeSolid(opt);
445+
const volume = solid.getSolidVolume({ shape: tree });
446+
expect(volume).toBeCloseTo(15.687, 2);
447+
tree.delete();
448+
});
449+
450+
it("should create christmas tree solid with bidirectional extrusion", async () => {
451+
const opt = new Inputs.OCCT.ChristmasTreeSolidDto(6, 1.5, 3, 5, 1, 1, false, 0, [0, 0, 0], [0, 1, 0]);
452+
opt.extrusionLengthFront = 1;
453+
opt.extrusionLengthBack = 1;
454+
const tree = solid.createChristmasTreeSolid(opt);
455+
const volume = solid.getSolidVolume({ shape: tree });
456+
// Bidirectional extrusion should double the volume
457+
expect(volume).toBeCloseTo(31.375, 2);
458+
tree.delete();
459+
});
460+
461+
// L-Polygon solid tests
462+
it("should create an L-polygon solid with default values", async () => {
463+
// L-polygon area depends on alignment mode
464+
// widthFirst=1, lengthFirst=2, widthSecond=0.5, lengthSecond=2
465+
const opt = new Inputs.OCCT.LPolygonSolidDto(1, 2, 0.5, 2);
466+
opt.extrusionLengthFront = 1;
467+
opt.extrusionLengthBack = 0;
468+
const lpolygon = solid.createLPolygonSolid(opt);
469+
const volume = solid.getSolidVolume({ shape: lpolygon });
470+
// Actual computed volume is 3.5
471+
expect(volume).toBeCloseTo(3.5);
472+
lpolygon.delete();
473+
});
474+
475+
it("should create an L-polygon solid with bidirectional extrusion", async () => {
476+
const opt = new Inputs.OCCT.LPolygonSolidDto(1, 2, 0.5, 2);
477+
opt.extrusionLengthFront = 1;
478+
opt.extrusionLengthBack = 1;
479+
const lpolygon = solid.createLPolygonSolid(opt);
480+
const volume = solid.getSolidVolume({ shape: lpolygon });
481+
// Volume = 3.5 * 2 = 7
482+
expect(volume).toBeCloseTo(7);
483+
lpolygon.delete();
484+
});
485+
486+
// Error case tests
487+
it("should throw error when both extrusion lengths are zero", async () => {
488+
const opt = new Inputs.OCCT.IBeamProfileSolidDto(2, 3, 0.2, 0.3);
489+
opt.extrusionLengthFront = 0;
490+
opt.extrusionLengthBack = 0;
491+
expect(() => solid.createIBeamProfileSolid(opt)).toThrow("Cannot create solid: both extrusionLengthFront and extrusionLengthBack are 0");
492+
});
493+
494+
it("should throw error for NGon solid when both extrusion lengths are zero", async () => {
495+
const opt = new Inputs.OCCT.NGonSolidDto([0, 0, 0], [0, 1, 0], 6, 1);
496+
opt.extrusionLengthFront = 0;
497+
opt.extrusionLengthBack = 0;
498+
expect(() => solid.createNGonSolid(opt)).toThrow("Cannot create solid: both extrusionLengthFront and extrusionLengthBack are 0");
499+
});
232500
});

0 commit comments

Comments
 (0)