Merge pull request #3067 from tangency-labs/fix/2908-basin-shell-reach

offset: a surface extended where its rows narrow holds the margin along its side (#2908)
This commit is contained in:
bherbruck
2026-11-06 23:35:55 -05:00
committed by GitHub
6 changed files with 283 additions and 43 deletions
File diff suppressed because one or more lines are too long
@@ -102,15 +102,15 @@
{"case":"fill_gap_extrudeHoles1_face0_round_d13","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,0,0,1,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[1,2,29,30,62,216,36],"result.edge_kinds":{"blocks":[[118,3885]],"n":62},"result.face_kinds":{"blocks":[[53,855]],"n":29},"result.present":[1],"selected.after":[0,0],"selected.before":[0,0],"source.after.counts":[6,12,11],"source.after.evaluation_status":[],"source.after.kinds":[2,2,1,2,1,2],"source.after.present":[1],"source.before.counts":[6,12,11],"source.before.evaluation_status":[],"source.before.kinds":[2,2,1,2,1,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[13.0,0.0059574935488984,2.0],"result.geometry":[0.00001,-12.999999999999996,-10.618380290797655,-65.0,65.0,77.93548347273091,13.0],"source.after.geometry":[0.00001,1e-16,0.0,-65.0,65.0,65.0,2e-16],"source.before.geometry":[0.00001,1e-16,0.0,-65.0,65.0,65.0,2e-16]}}
{"case":"fill_gap_extrudeHoles1_face0_round_d14_3","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,0,0,1,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[2,2,2,2,1,4,1],"result.edge_kinds":[2],"result.face_kinds":[2,2],"result.present":[1],"selected.after":[0,0],"selected.before":[0,0],"source.after.counts":[6,12,11],"source.after.evaluation_status":[],"source.after.kinds":[2,2,1,2,1,2],"source.after.present":[1],"source.before.counts":[6,12,11],"source.before.evaluation_status":[],"source.before.kinds":[2,2,1,2,1,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[14.3,0.0059574935488984,2.0],"result.geometry":[0.00001,17.220900132165276,11.646819499941582,-32.18218704109765,17.220900132165276,11.646819499941582,-32.18218704109765],"source.after.geometry":[0.00001,1e-16,0.0,-65.0,65.0,65.0,2e-16],"source.before.geometry":[0.00001,1e-16,0.0,-65.0,65.0,65.0,2e-16]}}
{"case":"fill_gap_open_shell_face0_extend_outset","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,0,1,0,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[1,1,6,6,26,64,17],"result.edge_kinds":{"blocks":[[51,701]],"n":26},"result.face_kinds":[2,3,3,3,3,3],"result.present":[1],"selected.after":[0,0],"selected.before":[0,0],"source.after.counts":[6,21,16],"source.after.evaluation_status":[],"source.after.kinds":[1,2,2,2,2,2],"source.after.present":[1],"source.before.counts":[6,21,16],"source.before.evaluation_status":[],"source.before.kinds":[1,2,2,2,2,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[9.11171,0.001946671479763,2.0],"result.geometry":[0.001946671479763,43.13823030257027,-224.17800387499807,29.242302548847142,226.00704477585487,-170.55910381937016,80.7559887478782],"source.after.geometry":[0.00001,43.13823030257018,-224.17800387499824,29.242302548847178,225.37238910170362,-170.43712294846034,71.6442787413281],"source.before.geometry":[0.00001,43.13823030257018,-224.17800387499824,29.242302548847178,225.37238910170362,-170.43712294846034,71.6442787413281]}}
{"case":"fillet2_f0_d0_in_ext","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,1,1,0,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[2,2,7,7,15,60,10],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,3,3,3,3,3],"result.present":[1],"selected.after":[0,0],"selected.before":[0,0],"source.after.counts":[7,15,10],"source.after.evaluation_status":[],"source.after.kinds":[1,1,2,2,2,2,2],"source.after.present":[1],"source.before.counts":[7,15,10],"source.before.evaluation_status":[],"source.before.kinds":[1,1,2,2,2,2,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[1.4,0.00001,2.0],"result.geometry":[0.00001,-2.6000000000000503,0.9603220413019788,-2.1551546134260437e-15,10.600000000000001,12.710803859986838,25.513374917037073],"source.after.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0],"source.before.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0]}}
{"case":"fillet2_f0_d0_in_ext","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,1,1,0,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[2,2,7,7,15,60,10],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,3,3,3,3,3],"result.present":[1],"selected.after":[0,0],"selected.before":[0,0],"source.after.counts":[7,15,10],"source.after.evaluation_status":[],"source.after.kinds":[1,1,2,2,2,2,2],"source.after.present":[1],"source.before.counts":[7,15,10],"source.before.evaluation_status":[],"source.before.kinds":[1,1,2,2,2,2,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[1.4,0.00001,2.0],"result.geometry":[0.00001,-2.6000000000000494,0.9603220414208608,-1.3341093994433115e-18,10.599999999999998,12.710803859777222,25.513374916628095],"source.after.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0],"source.before.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0]}}
{"case":"fillet2_f0_d0_in_rnd","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,1,0,1,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[1,1,5,10,24,68,23],"result.edge_kinds":{"blocks":[[48,600]],"n":24},"result.face_kinds":[1,1,3,3,3],"result.present":[1],"selected.after":[0,0],"selected.before":[0,0],"source.after.counts":[7,15,10],"source.after.evaluation_status":[],"source.after.kinds":[1,1,2,2,2,2,2],"source.after.present":[1],"source.before.counts":[7,15,10],"source.before.evaluation_status":[],"source.before.kinds":[1,1,2,2,2,2,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[5.6,0.00001,2.0],"result.geometry":[0.00001,-4.0,0.0,0.0,12.0,13.999999999999975,28.000000000000014],"source.after.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0],"source.before.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0]}}
{"case":"fillet2_f0_d0_out_ext","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,0,1,0,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[2,2,7,7,15,60,10],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,3,3,3,3,3],"result.present":[1],"selected.after":[0,0],"selected.before":[0,0],"source.after.counts":[7,15,10],"source.after.evaluation_status":[],"source.after.kinds":[1,1,2,2,2,2,2],"source.after.present":[1],"source.before.counts":[7,15,10],"source.before.evaluation_status":[],"source.before.kinds":[1,1,2,2,2,2,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[1.4,0.00001,2.0],"result.geometry":[0.00001,-5.4,-1.878297101099824,-7.585972018467942e-16,13.399999999999999,15.878297101099822,31.130495168499706],"source.after.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0],"source.before.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0]}}
{"case":"fillet2_f0_d0_out_ext","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,0,1,0,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[2,2,7,7,15,60,10],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,3,3,3,3,3],"result.present":[1],"selected.after":[0,0],"selected.before":[0,0],"source.after.counts":[7,15,10],"source.after.evaluation_status":[],"source.after.kinds":[1,1,2,2,2,2,2],"source.after.present":[1],"source.before.counts":[7,15,10],"source.before.evaluation_status":[],"source.before.kinds":[1,1,2,2,2,2,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[1.4,0.00001,2.0],"result.geometry":[0.00001,-5.4,-1.878297101099824,-2.9102696814942153e-16,13.400000000000002,15.878297101099825,31.1304951684997],"source.after.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0],"source.before.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0]}}
{"case":"fillet2_f0_d0_out_rnd","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,0,0,1,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[1,1,20,20,46,152,27],"result.edge_kinds":{"blocks":[[89,2156]],"n":46},"result.face_kinds":{"blocks":[[33,414]],"n":20},"result.present":[1],"selected.after":[0,0],"selected.before":[0,0],"source.after.counts":[7,15,10],"source.after.evaluation_status":[],"source.after.kinds":[1,1,2,2,2,2,2],"source.after.present":[1],"source.before.counts":[7,15,10],"source.before.evaluation_status":[],"source.before.kinds":[1,1,2,2,2,2,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[5.6,0.00001,2.0],"result.geometry":[0.00001,-9.6,-5.008792269599528,0.0,17.6,19.008792269599528,30.504396134799766],"source.after.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0],"source.before.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0]}}
{"case":"fillet2_f0_d0_out_rnd_unmerged","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,0,0,1,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[1,20,20,20,76,152,76],"result.edge_kinds":{"blocks":[[144,5816]],"n":76},"result.face_kinds":{"blocks":[[35,431]],"n":20},"result.present":[1],"selected.after":[0,0],"selected.before":[0,0],"source.after.counts":[7,15,10],"source.after.evaluation_status":[],"source.after.kinds":[1,1,2,2,2,2,2],"source.after.present":[1],"source.before.counts":[7,15,10],"source.before.evaluation_status":[],"source.before.kinds":[1,1,2,2,2,2,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[5.6,0.00001,2.0],"result.geometry":[0.00001,-9.6,-5.008792269599528,0.0,17.6,19.008792269599528,30.504396134799766],"source.after.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0],"source.before.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0]}}
{"case":"fillet2_f0_d1_in_rnd","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,1,0,1,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[1,1,4,6,17,44,16],"result.edge_kinds":{"blocks":[[34,306]],"n":17},"result.face_kinds":[1,1,3,3],"result.present":[1],"selected.after":[0,0],"selected.before":[0,0],"source.after.counts":[7,15,10],"source.after.evaluation_status":[],"source.after.kinds":[1,1,2,2,2,2,2],"source.after.present":[1],"source.before.counts":[7,15,10],"source.before.evaluation_status":[],"source.before.kinds":[1,1,2,2,2,2,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[11.2,0.00001,2.0],"result.geometry":[0.00001,-4.0,0.0,0.0,12.0,13.999999999999975,28.000000000000014],"source.after.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0],"source.before.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0]}}
{"case":"fillet2_f0_d1_out_rnd","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,0,0,1,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[1,1,13,14,40,112,29],"result.edge_kinds":{"blocks":[[75,1625]],"n":40},"result.face_kinds":[1,1,1,1,1,1,1,1,2,2,2,2,2],"result.present":[1],"selected.after":[0,0],"selected.before":[0,0],"source.after.counts":[7,15,10],"source.after.evaluation_status":[],"source.after.kinds":[1,1,2,2,2,2,2],"source.after.present":[1],"source.before.counts":[7,15,10],"source.before.evaluation_status":[],"source.before.kinds":[1,1,2,2,2,2,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[11.2,0.00001,2.0],"result.geometry":[0.00001,-15.2,-10.017584539199056,-0.017584539199058113,23.2,24.017584539199056,33.00879226959953],"source.after.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0],"source.before.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0]}}
{"case":"fillet2_f0_d1_out_rnd_unmerged","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,0,0,1,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[1,12,12,12,50,100,50],"result.edge_kinds":{"blocks":[[92,2514]],"n":50},"result.face_kinds":[1,1,1,1,1,1,1,2,2,2,2,2],"result.present":[1],"selected.after":[0,0],"selected.before":[0,0],"source.after.counts":[7,15,10],"source.after.evaluation_status":[],"source.after.kinds":[1,1,2,2,2,2,2],"source.after.present":[1],"source.before.counts":[7,15,10],"source.before.evaluation_status":[],"source.before.kinds":[1,1,2,2,2,2,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[11.2,0.00001,2.0],"result.geometry":[0.00001,-15.2,-10.017584539199056,-0.017584539199058113,23.2,24.017584539199056,33.00879226959953],"source.after.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0],"source.before.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0]}}
{"case":"fillet2_f1_d0_in_ext","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,1,1,0,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[2,2,7,7,15,60,10],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,3,3,3,3,3],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[7,15,10],"source.after.evaluation_status":[],"source.after.kinds":[1,1,2,2,2,2,2],"source.after.present":[1],"source.before.counts":[7,15,10],"source.before.evaluation_status":[],"source.before.kinds":[1,1,2,2,2,2,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[1.4,0.00001,2.0],"result.geometry":[0.00001,-4.000000000000001,0.9693975857145739,1.3999999999999333,10.585804781696549,12.74780344530283,25.590387728710024],"source.after.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0],"source.before.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0]}}
{"case":"fillet2_f1_d0_in_ext","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,1,1,0,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[2,2,7,7,15,60,10],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,3,3,3,3,3],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[7,15,10],"source.after.evaluation_status":[],"source.after.kinds":[1,1,2,2,2,2,2],"source.after.present":[1],"source.before.counts":[7,15,10],"source.before.evaluation_status":[],"source.before.kinds":[1,1,2,2,2,2,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[1.4,0.00001,2.0],"result.geometry":[0.00001,-4.0,0.9693975854011403,1.3999999999999997,10.585804800872111,12.74780259056018,25.590387728548066],"source.after.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0],"source.before.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0]}}
{"case":"fillet2_f1_d0_in_rnd","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,1,0,1,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[1,1,6,9,26,72,23],"result.edge_kinds":{"blocks":[[52,702]],"n":26},"result.face_kinds":[1,1,3,3,3,3],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[7,15,10],"source.after.evaluation_status":[],"source.after.kinds":[1,1,2,2,2,2,2],"source.after.present":[1],"source.before.counts":[7,15,10],"source.before.evaluation_status":[],"source.before.kinds":[1,1,2,2,2,2,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[5.6,0.00001,2.0],"result.geometry":[0.00001,-4.0,-3.552713678800501e-15,0.0,12.000000000000004,14.0,28.0],"source.after.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0],"source.before.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0]}}
{"case":"fillet2_f1_d0_out_ext","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,0,1,0,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[1,1,7,7,17,60,11],"result.edge_kinds":{"blocks":[[34,306]],"n":17},"result.face_kinds":[1,1,3,3,3,3,3],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[7,15,10],"source.after.evaluation_status":[],"source.after.kinds":[1,1,2,2,2,2,2],"source.after.present":[1],"source.before.counts":[7,15,10],"source.before.evaluation_status":[],"source.before.kinds":[1,1,2,2,2,2,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[1.4,0.00001,2.0],"result.geometry":[0.00001,-4.0,-1.8782971010998226,-1.4000000000000001,13.400000000000002,15.878297101099824,31.130495168499706],"source.after.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0],"source.before.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0]}}
{"case":"fillet2_f1_d0_out_rnd","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.flags":[0,0,0,1,0],"executive.present":[1],"executive.signed_zero":[0,0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[1,1,20,20,46,152,27],"result.edge_kinds":{"blocks":[[92,2162]],"n":46},"result.face_kinds":{"blocks":[[34,423]],"n":20},"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[7,15,10],"source.after.evaluation_status":[],"source.after.kinds":[1,1,2,2,2,2,2],"source.after.present":[1],"source.before.counts":[7,15,10],"source.before.evaluation_status":[],"source.before.kinds":[1,1,2,2,2,2,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[5.6,0.00001,2.0],"result.geometry":[0.00001,-5.008792269599528,-5.008792269599528,-5.6,17.6,19.008792269599528,30.504396134799766],"source.after.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0],"source.before.geometry":[0.00001,-4.0,0.0,0.0,12.0,14.0,28.0]}}
+86
View File
@@ -85,6 +85,92 @@ fn a_cylinder_shells_open_at_its_top() {
assert!(rel(volume(&c), PI * 25.0 * 10.0 - PI * 16.0 * 9.0) < 1e-9);
}
/// A basin: a 100 x 60 x 30 slab less a ruled pocket (60 x 46 at the top, 4 from the front, 40 x
/// 20 at its floor 20 down), shelled open at its bottom, each wall moved in by t with sharp
/// edges. The cavity is the slab shrunk by t (open at z = 0) less the pocket grown by t, each
/// sloped side moved out along its normal; the volume, slab - pocket - cavity, is a cubic in z
/// integrated by hand. From t ~ 2.70 the front side's offset passes the front wall's below the
/// 4 mm rim, and the rim stays solid: the cavity's front stops at y = t (from
/// z = (28 - (1 + sqrt 1.64) t) / 0.8 up).
#[test]
#[allow(clippy::disallowed_methods)] // closed-form oracle, not ops geometry
fn a_basin_shells_past_its_rim_to_its_closed_form() {
session::set_fixes(
solidcore::kernel::UpstreamFixes::NAMES
.iter()
.copied()
.filter(|n| {
!matches!(
*n,
"fillet_refuse_rounds_breaking_through" | "fillet_round_ends_on_outline"
)
}),
)
.unwrap();
let rect = |x0: f64, y0: f64, x1: f64, y1: f64, z: f64| {
let p = [[x0, y0, z], [x1, y0, z], [x1, y1, z], [x0, y1, z]];
(0..4)
.map(|i| crate::sweep::Curve::Line {
start: p[i],
end: p[(i + 1) % 4],
})
.collect::<Vec<_>>()
};
let pocket = crate::sweep::loft(
&[
rect(20.0, 4.0, 80.0, 50.0, 30.0),
rect(30.0, 20.0, 70.0, 40.0, 10.0),
],
1,
true,
)
.unwrap();
let slab = make_box([0.0; 3], [100.0, 60.0, 30.0]).unwrap();
let basin = crate::boolean::boolean(slab, pocket, crate::BooleanOp::Subtract)
.unwrap()
.unwrap();
// The pocket grown by t at height z: x from 35 - z/2 - t sqrt5/2 to 65 + z/2 + t sqrt5/2, y
// from 28 - 0.8 z - t sqrt1.64 (or y = t, where that is less) to 35 + z/2 + t sqrt5/2, for
// z = 10 - t ... 30 - t; its sides stay inside the shrunk slab in x and at the back for t <= 6.
let (r5, r164) = (5f64.sqrt(), 1.64f64.sqrt());
let integral = |c: [f64; 3], lo: f64, hi: f64| {
c[0] * (hi - lo) + c[1] * (hi * hi - lo * lo) / 2.0 + c[2] * (hi.powi(3) - lo.powi(3)) / 3.0
};
// (w0 + z)(h0 + h1 z) as coefficients in z.
let product = |w0: f64, h0: f64, h1: f64| [w0 * h0, w0 * h1 + h0, h1];
let grown = |t: f64| {
let (lo, hi, w0) = (10.0 - t, 30.0 - t, 30.0 + r5 * t);
let full = product(w0, 7.0 + t * (r5 / 2.0 + r164), 1.3);
let z0 = ((28.0 - r164 * t - t) / 0.8).clamp(lo, hi);
integral(full, lo, z0) + integral(product(w0, 35.0 + (r5 / 2.0 - 1.0) * t, 0.5), z0, hi)
};
let closed = |t: f64| {
100.0 * 60.0 * 30.0 - grown(0.0) - (100.0 - 2.0 * t) * (60.0 - 2.0 * t) * (30.0 - t)
+ grown(t)
};
assert!(rel(volume(&basin), 180_000.0 - grown(0.0)) < 1e-9);
for (t, want) in [
(1.0, 17_105.624_041_5),
(4.0, 63_560.249_228_4),
(6.0, 90_113.920_210_1),
] {
assert!(rel(closed(t), want) < 1e-12, "the closed form at {t}");
let b = basin.copy().unwrap();
let o = order(&b);
let bottom = face(&b, &o, |bx| {
bx.min().z.abs() < 1e-9 && bx.max().z.abs() < 1e-9
});
shell(&b, &o, &[bottom], -t).unwrap_or_else(|e| panic!("t {t}: {e:?}"));
assert!(
rel(volume(&b), want) < 1e-6,
"t {t}: {} vs {want}",
volume(&b)
);
let report = b.check(crate::CheckLevel::All).unwrap();
assert!(report.is_valid(), "t {t}: {}", report.text);
}
}
#[test]
fn a_wall_with_no_room_is_refused_before_the_kernel() {
all_fixes();
@@ -767,13 +767,31 @@ impl OffsetExecutive {
let extension = if margin == 0.0 {
base.clone()
} else {
base.extended_sides_keeping_parameters(
kernel,
&BoxSide::ALL,
Continuity::Ruled,
margin,
)?
.surface
let extend = |asked: f64| {
base.extended_sides_keeping_parameters(
kernel,
&BoxSide::ALL,
Continuity::Ruled,
asked,
)
};
// An extension meets its distance at the middle of each side; a margin is
// needed at every station of it (#2908): where the rows narrow along a side
// it is asked again, scaled by the shortest length across (Ruled: the
// lengths at a station grow together).
let mut made = extend(margin)?;
if let Some(shortest) = super::reach::shortest_across(kernel, base, &made)? {
if shortest < margin * (1.0 - 1.0e-9) {
// a surface that cannot go that far keeps what it has: the extension
// above is what its faces have always had
match extend(margin * margin / shortest) {
Ok(grown) => made = grown,
Err(SolidError::ExtendRefused { .. }) => {}
Err(e) => return Err(e),
}
}
}
made.surface
};
Ok(entry.insert(extension))
}
@@ -26,12 +26,24 @@
//! edge (its sector angle varies) and at each corner. Faces whose offsets never meet, a knife
//! edge's (`c = −1` for equal offsets) or tangent faces offset apart (`c = 1`, `dF ≠ dG`),
//! add nothing: no extension makes them meet.
//!
//! An extension meets its distance at the middle of each side, and a reach is needed at every
//! station. [`shortest_across`] bounds the length across a B-spline's sides from below, for
//! the executive to ask again where the rows narrow along a side (#2908; the measurements and
//! the choice of asking again are `MarkusReichart`'s on #2926). Analytic faces are left as
//! they were.
use crate::error::{Result, SolidError};
use crate::geom::extent2d::Extent2d;
use crate::geom::vector3d::{sqrt, Vec3};
use crate::kernel::Kernel;
use crate::math::EFF_ZERO;
use crate::math::{Point2, EFF_ZERO};
use crate::nurbs::b_spline_surface::p1::SurfParamType;
use crate::nurbs::b_spline_surface::p2::IsoCurveOptions;
use crate::nurbs::b_spline_surface_n_lib::p2::OrientType;
use crate::surface::extend::{ExtendedSides, SideExtension};
use crate::surface::side::BoxSide;
use crate::surface::surface::{Surface, SurfaceKind};
use crate::topology::edgeuse::{p1 as eu, p3 as eu3};
use crate::topology::{edge, loopuse, Brep, EdgeuseId, FaceId, FaceuseId};
@@ -207,12 +219,131 @@ pub fn extension_reach(
Ok(met.then_some(reach))
}
/// A lower bound of the distance from each extended side of `base`'s B-spline to the same
/// side of `extended`, over the side's stations on `base`'s box: `None` where `base` is no
/// B-spline or the offset of one, a side's two rows differ in weights, or the bound is not positive. Each row is a
/// curve in the same parameter and basis, with the same weights, so the difference at a
/// station is a convex combination of the differences of their control points, and its length
/// is at least the least of those along their mean direction. Past the box's corners the
/// rows go on narrowing, to nothing at a ruled face's apex; the margin's one offset past the
/// reach is what stands for them.
///
/// # Errors
///
/// Those of the domains and the iso curves.
pub(super) fn shortest_across(
k: &Kernel,
base: &Surface,
extended: &ExtendedSides,
) -> Result<Option<f64>> {
// an offset surface is the offset of its base extended: the rows are its base's
let (near_surface, far_surface) = match (base.kind(), extended.surface.kind()) {
(SurfaceKind::OffsetSurface(a), SurfaceKind::OffsetSurface(b)) => {
(a.base_surface(), b.base_surface())
}
_ => (base, &extended.surface),
};
let (SurfaceKind::BSpline(_), SurfaceKind::BSpline(net)) =
(near_surface.kind(), far_surface.kind())
else {
return Ok(None);
};
let from = near_surface.natural_uv_domain_with_nurb(k)?;
let to = far_surface.natural_uv_domain_with_nurb(k)?;
let mut shortest = f64::INFINITY;
for (&side, done) in BoxSide::ALL.iter().zip(&extended.sides) {
if !matches!(done, SideExtension::Extended(_)) {
continue;
}
let along = if side.is_u() {
SurfParamType::U
} else {
SurfParamType::V
};
// the side's stations on the source's box, the row wherever it lies
let box_of_row = if side.is_u() {
Extent2d::from_points(
Point2::new(to.min().x, from.min().y),
Point2::new(to.max().x, from.max().y),
)
} else {
Extent2d::from_points(
Point2::new(from.min().x, to.min().y),
Point2::new(from.max().x, to.max().y),
)
};
let row = |at: f64| {
let options = IsoCurveOptions {
domain: Some(box_of_row),
uv_iso_curve: false,
};
net.create_iso_parametric_curve(k, along, at, options)?
.curve
.canonical()
};
let (near, far) = (row(side.at(&from))?, row(side.at(&to))?);
if near.control_points.len() != far.control_points.len() || near.weights != far.weights {
return Ok(None);
}
let mut mean = Vec3::ZERO;
for (a, b) in near.control_points.iter().zip(&far.control_points) {
mean += *b - *a;
}
let Ok(direction) = mean.unitize() else {
return Ok(None);
};
for (a, b) in near.control_points.iter().zip(&far.control_points) {
shortest = shortest.min((*b - *a).dot(direction));
}
}
Ok((shortest.is_finite() && shortest > 0.0).then_some(shortest))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::math::Point3;
use crate::topology::brep::p1 as bp1;
/// The basin's ruled side: rows 46 long at its rim and 20 at its floor.
#[test]
fn a_narrowing_side_is_short_of_its_distance_where_it_narrows() {
use crate::nurbs::b_spline_curve::KnotType;
use crate::nurbs::b_spline_surface::{
BSplineSurface, BSplineSurfaceForm, CanonicalSurfaceData,
};
use crate::surface::extend::Continuity;
let k = Kernel::default();
let base = Surface::from(
BSplineSurface::create_canonical(&CanonicalSurfaceData {
u_degree: 1,
v_degree: 1,
control_points: &[
Point3::new(20.0, 4.0, 30.0),
Point3::new(20.0, 50.0, 30.0),
Point3::new(30.0, 20.0, 10.0),
Point3::new(30.0, 40.0, 10.0),
],
form: BSplineSurfaceForm::Unspecified,
u_multiplicities: &[2, 2],
v_multiplicities: &[2, 2],
u_knots: &[0.0, 1.0],
v_knots: &[0.0, 1.0],
knot_type: KnotType::Unspecified,
weights: None,
uv_domain: None,
})
.unwrap(),
);
let made = base
.extended_sides_keeping_parameters(&k, &BoxSide::ALL, Continuity::Ruled, 11.24)
.unwrap();
// the rows are 33 at the side's middle, where the extension meets its distance, and
// 20 at the floor, so the v sides reach 11.24 * 20 / 33 at the floor's end
let shortest = shortest_across(&k, &base, &made).unwrap().unwrap();
assert!((shortest - 11.24 * 20.0 / 33.0).abs() <= 1e-6, "{shortest}");
}
fn box_faceuses(k: &mut Kernel, inset: bool) -> (Brep, Vec<(FaceId, FaceuseId)>) {
let brep = crate::primitive::api_primitives::create_box(
k,
+6 -1
View File
@@ -250,7 +250,12 @@ face's surface and intersects neighbouring offsets instead of filling convex edg
- **The extension** (`get_create_extended_surface`, `p1.rs`) is the exact extension
`extended_sides_keeping_parameters` with `Continuity::Ruled` on every side
(definitions-and-certificates.md §6.5): analytic kinds and ball patches as themselves, a
procedural blend by its definition, an offset surface as the offset of its extended base.
procedural blend by its definition, an offset surface as the offset of its extended base. It
meets its distance at the middle of each side, so where a B-spline's rows narrow along a side
(`shortest_across`, `reach.rs`: a bound from the two rows' control points, over the side's
stations on the face's box) it is asked again, scaled by the shortest length. Past the box's
corners, where the rows go on narrowing, it stays the first-order margin above, not a
certificate of the reach. A surface that refuses the longer ask keeps the first extension.
- **The mitre** (`OffsetGeometryCreation::mate_edges`, `offset_geometry_creation.rs`) intersects
the two extended offsets at a quarter of the body's tolerance and 20°, keeps the intersection
curve whose trimmed midpoint is nearest the original edge's, trims it and gives it to both offset