@@ -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