Compare commits

...

3 Commits

Author SHA1 Message Date
bherbruck a2eb31816c ops: offset surfaces, each face on its exact offset, joined where they meet (#3138)
SolidCraft's Surface > Offset offsets each face as a sheet and assembles the
records in the app before stitching (surface_offset.rs, surfaces::offset_faces).
offset_surface copies each picked face out on its own (copy_faces_from, its
attributes with it), offsets it with offset_sheet, copies the sheets into one
body and stitches them at the caller's tolerance: neighbours meeting smoothly
keep their shared edge, across a sharp edge they come apart, and faces that
close make a solid. An offset that would fold is the kernel's refusal.
history::recorded_into gives the new body's history against its source, so
each face is the OffsetOf the face it came from.

Tests (exact measures): a cube's top 5 up is area 100 at z = 15, the top's
offset; two faces across a sharp edge come apart (2 faces, 8 edges); a zero
distance copies (area 200); a cylinder side r 10 out 2 is area 2π·12·20 with its
seam kept, and refused at -10.5; a ball r 10 out 2 closes into the ball of
radius 12 (area 4π·144, volume 4π·1728/3), refused at -10.

Fixes #3138.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 15:50:17 -05:00
bherbruck d88a7b1e0d ops: the face at a point, and a pick grown across the edges where one surface continues (#3138)
SolidCraft picks the face under a point by the nearest display-mesh triangle
(offset_backend.rs faces_under) and grows a pick to the faces on the same
surface by comparing the record's numbers with its own tolerances
(offset.rs with_same_surface). Body::face_at classifies the point with the
kernel (Point3DClassify at the caller's reach): the face it lies on, and none
on an edge or a vertex, off the body, or unclassified. Body::faces_on_one_surface
grows the picks across every edge not kept where query::faces_continue proves
the two faces continue one surface definition with the same outward side; an
undecided edge is not crossed.

Tests: a cube halved by x = 5: a point on each top half picks that half, and
none on the split line, a box edge, outside or inside; one top half grows to
the other across the split line, and stays alone with that line kept.

Part of #3138.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 15:48:13 -05:00
bherbruck 3fffb8a9b9 offset: the executive marks how it made each face; faces_continue; ops history (#3138)
SolidCraft decides whether a shell's face is a face or its offset copy by mesh
distance (offset_backend.rs with_offsets), because the tag a copy carries is its
source's. The executive already relates each face it makes to what made it.
mark_offset_roles, called first in piecewise_merge where those relations are
final, marks each such face with ids::OFFSET_ROLE: an offset copy, a face along
an edge (with the closing faces, a sheet's side walls), a face at a vertex.
It adds no relation and changes no decision.

query::faces_continue proves two faces across an edge lie on one surface with
the same outward side only on identical definitions, bit for bit, and is
Undecided otherwise; it never samples. solidcore-ops' history::recorded tags the
operand's faces and edges by record index, runs the call, and reads each result
face's origin and change and each edge's operand edges, in record order. The
tags and roles are removed before it returns.

offset.offset_executive_p2: 30 rows, the attributes block only (the role now on
the offset faces). A/B: 30 with the pass, 0 without. Tests: a shelled box
(424), a thickened sheet (100), a moved face (1200), and #865's plate, whose
crossing-loops-rebuilt top is the top's offset.

Part of #3138.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 15:24:19 -05:00
14 changed files with 1258 additions and 31 deletions
@@ -2,25 +2,25 @@
{"case":"api_box_foreign_face_zero_collision_purity_subset","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.counts":[6,12,8],"foreign.after.evaluation_status":[],"foreign.after.kinds":[1,1,1,1,1,1],"foreign.after.present":[1],"foreign.before.counts":[6,12,8],"foreign.before.evaluation_status":[],"foreign.before.kinds":[1,1,1,1,1,1],"foreign.before.present":[1],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[0,0,0,0,1,0],"selected.before":[0,0,0,0,1,0],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1007]},"topology":null,"values":{"foreign.after.geometry":[1e-6,20.0,0.0,0.0,30.0,10.0,10.0],"foreign.before.geometry":[1e-6,20.0,0.0,0.0,30.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_box_null_then_source_purity_subset","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[2,-1,0,0],"selected.before":[2,-1,0,0],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1007]},"topology":null,"values":{"source.after.geometry":[0.00001,-3.0,4.0,2.0,-1.0,7.0,7.0],"source.before.geometry":[0.00001,-3.0,4.0,2.0,-1.0,7.0,7.0]}}
{"case":"api_offset_box_extend_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[372525,15296207]],"n":76},"doing_boolean":[0,0],"executive.present":[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,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,1.0,1.0,0.9999999999999992,9.0,9.0,9.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_extend_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[372525,15296207]],"n":76},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,1.0,0.9999999999999992,1.0,9.0,9.0,9.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_extend_merge_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[372525,15296207]],"n":76},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-0.9999999999999999,11.0,10.999999999999998,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_extend_merge_out_reference","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[372543,15296939]],"n":76},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-0.9999999999999999,11.0,10.999999999999998,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_extend_merge_out_standalone_copy","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[372525,15296207]],"n":76},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-0.9999999999999999,11.0,10.999999999999998,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_extend_merge_out_standalone_reference","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[372579,15298403]],"n":76},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-0.9999999999999999,11.0,10.999999999999998,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_extend_merge_out_temp","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[39,179]],"n":22},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-0.9999999999999999,11.0,10.999999999999998,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_extend_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[373383,21118328]],"n":94},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,1.0,0.9999999999999992,1.0,9.0,9.0,9.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_extend_merge_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[373383,21118328]],"n":94},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-0.9999999999999999,11.0,10.999999999999998,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_extend_merge_out_reference","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[373401,21119339]],"n":94},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-0.9999999999999999,11.0,10.999999999999998,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_extend_merge_out_standalone_copy","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[373383,21118328]],"n":94},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-0.9999999999999999,11.0,10.999999999999998,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_extend_merge_out_standalone_reference","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[373437,21121361]],"n":94},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-0.9999999999999999,11.0,10.999999999999998,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_extend_merge_out_temp","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[897,13037]],"n":40},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-0.9999999999999999,11.0,10.999999999999998,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_extend_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[372525,15296207]],"n":76},"doing_boolean":[0,0],"executive.present":[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,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[2,2,2,2,2,2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-1.0000000000000033,11.0,11.0,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_round_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[624897,40783559]],"n":124},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[1,6,6,6,24,48,24],"result.edge_kinds":{"blocks":[[24,300]],"n":24},"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_round_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[120177,1922479]],"n":40},"doing_boolean":[0,0],"executive.present":[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,6,6,12,48,8],"result.edge_kinds":[1,1,1,1,1,1,1,1,1,1,1,1],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,1.0,1.0,1.0,9.0,9.0,9.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_round_merge_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[624985,65391195]],"n":168},"doing_boolean":[0,0],"executive.present":[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,26,26,48,192,24],"result.edge_kinds":{"blocks":[[72,2052]],"n":48},"result.face_kinds":{"blocks":[[46,681]],"n":26},"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-1.0,-1.0,-1.0,11.0,11.0,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_round_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[121035,3202984]],"n":58},"doing_boolean":[0,0],"executive.present":[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,6,6,12,48,8],"result.edge_kinds":[1,1,1,1,1,1,1,1,1,1,1,1],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,1.0,1.0,1.0,9.0,9.0,9.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_round_merge_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[628731,113432292]],"n":246},"doing_boolean":[0,0],"executive.present":[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,26,26,48,192,24],"result.edge_kinds":{"blocks":[[72,2052]],"n":48},"result.face_kinds":{"blocks":[[46,681]],"n":26},"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-1.0,-1.0,-1.0,11.0,11.0,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_round_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[624985,65391195]],"n":168},"doing_boolean":[0,0],"executive.present":[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,26,26,48,192,24],"result.edge_kinds":{"blocks":[[72,2052]],"n":48},"result.face_kinds":{"blocks":[[46,681]],"n":26},"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-1.0000000000000018,-1.0000000000000013,-1.0000000000000018,11.000000000000002,11.000000000000002,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_box_upstream","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-0.9999999999999999,11.0,10.999999999999998,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_offset_cylinder_extend_merge_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[123135,2050813]],"n":28},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,3,3,3,12,2],"result.edge_kinds":[2,2,2],"result.face_kinds":[1,1,2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[3,3,2],"source.after.evaluation_status":[],"source.after.kinds":[2,1,1],"source.after.present":[1],"source.before.counts":[3,3,2],"source.before.evaluation_status":[],"source.before.kinds":[2,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,4.5,-2.0,-2.7755575615628914e-17,4.5,-2.0,6.0],"source.after.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5],"source.before.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5]}}
{"case":"api_offset_cylinder_extend_merge_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[123564,2983669]],"n":37},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,3,3,3,12,2],"result.edge_kinds":[2,2,2],"result.face_kinds":[1,1,2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[3,3,2],"source.after.evaluation_status":[],"source.after.kinds":[2,1,1],"source.after.present":[1],"source.before.counts":[3,3,2],"source.before.evaluation_status":[],"source.before.kinds":[2,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,4.5,-2.0,-2.7755575615628914e-17,4.5,-2.0,6.0],"source.after.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5],"source.before.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5]}}
{"case":"api_offset_cylinder_in","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,3,3,3,12,2],"result.edge_kinds":[2,2,2],"result.face_kinds":[1,1,2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[3,3,2],"source.after.evaluation_status":[],"source.after.kinds":[2,1,1],"source.after.present":[1],"source.before.counts":[3,3,2],"source.before.evaluation_status":[],"source.before.kinds":[2,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,3.4999999999999996,-2.0000000000000004,0.9999999999999999,3.4999999999999996,-2.0000000000000004,5.0],"source.after.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5],"source.before.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5]}}
{"case":"api_offset_cylinder_out","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,3,3,3,12,2],"result.edge_kinds":[2,2,2],"result.face_kinds":[1,1,2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[3,3,2],"source.after.evaluation_status":[],"source.after.kinds":[2,1,1],"source.after.present":[1],"source.before.counts":[3,3,2],"source.before.evaluation_status":[],"source.before.kinds":[2,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,4.5,-2.0,-2.7755575615628914e-17,4.5,-2.0,6.0],"source.after.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5],"source.before.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5]}}
{"case":"api_offset_cylinder_round_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[165189,3978567]],"n":40},"doing_boolean":[0,0],"executive.present":[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,5,5,7,28,4],"result.edge_kinds":[1,2,2,2,2,2,2],"result.face_kinds":[1,1,2,2,2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[3,3,2],"source.after.evaluation_status":[],"source.after.kinds":[2,1,1],"source.after.present":[1],"source.before.counts":[3,3,2],"source.before.evaluation_status":[],"source.before.kinds":[2,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,4.0,-2.000000000000001,0.0,4.5,-2.0,6.0],"source.after.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5],"source.before.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5]}}
{"case":"api_offset_null_negative_zero_keeps_foreign_wire","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.counts":[0,0,1,2,2],"foreign.after.evaluation_status":[1000,1000],"foreign.after.kinds":[1],"foreign.after.present":[1],"foreign.before.counts":[0,0,1,2,2],"foreign.before.evaluation_status":[1000,1000],"foreign.before.kinds":[1],"foreign.before.present":[1],"input.pure":[1,1],"ownership":[0,0,0],"result.present":[0],"selected.after":[],"selected.before":[],"source.after.present":[0],"source.before.present":[0],"status":[1007]},"topology":null,"values":{"foreign.after.geometry":{"blocks":[[24.800001,47.20000100000001,269.200001]],"n":17},"foreign.before.geometry":{"blocks":[[24.800001,47.20000100000001,269.200001]],"n":17}}}
{"case":"api_offset_null_raw_negative_offset","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.counts":[1,1,4,8,4],"foreign.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"foreign.after.kinds":[1],"foreign.after.present":[1],"foreign.before.counts":[1,1,4,8,4],"foreign.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"foreign.before.kinds":[1],"foreign.before.present":[1],"input.pure":[1,1],"ownership":[0,0,0],"result.present":[0],"selected.after":[],"selected.before":[],"source.after.present":[0],"source.before.present":[0],"status":[1007]},"topology":null,"values":{"foreign.after.geometry":{"blocks":[[60.500001,82.500001,1093.5000009999999]],"n":27},"foreign.before.geometry":{"blocks":[[60.500001,82.500001,1093.5000009999999]],"n":27}}}
{"case":"api_offset_sphere_extend_merge_out","deferred":null,"error":null,"ints":{"attributes":[1,10,1,1,10007,0,10007,1,1,10507,0,10507],"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,1,1,1,4,2],"result.edge_kinds":[2],"result.face_kinds":[2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[1,1,2],"source.after.evaluation_status":[],"source.after.kinds":[2],"source.after.present":[1],"source.before.counts":[1,1,2],"source.before.evaluation_status":[],"source.before.kinds":[2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.4999999999999995,0.5,-2.0,0.5000000000000009,0.5,3.0],"source.after.geometry":[1e-6,0.4999999999999996,0.5,-1.5,0.5000000000000007,0.5,2.5],"source.before.geometry":[1e-6,0.4999999999999996,0.5,-1.5,0.5000000000000007,0.5,2.5]}}
{"case":"api_offset_sphere_extend_merge_out","deferred":null,"error":null,"ints":{"attributes":[1,13,1,2,138,0,1,10007,0,10007,1,1,10507,0,10507],"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,1,1,1,4,2],"result.edge_kinds":[2],"result.face_kinds":[2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[1,1,2],"source.after.evaluation_status":[],"source.after.kinds":[2],"source.after.present":[1],"source.before.counts":[1,1,2],"source.before.evaluation_status":[],"source.before.kinds":[2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.4999999999999995,0.5,-2.0,0.5000000000000009,0.5,3.0],"source.after.geometry":[1e-6,0.4999999999999996,0.5,-1.5,0.5000000000000007,0.5,2.5],"source.before.geometry":[1e-6,0.4999999999999996,0.5,-1.5,0.5000000000000007,0.5,2.5]}}
{"case":"api_offset_sphere_in","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,1,1,1,4,2],"result.edge_kinds":[2],"result.face_kinds":[2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[1,1,2],"source.after.evaluation_status":[],"source.after.kinds":[2],"source.after.present":[1],"source.before.counts":[1,1,2],"source.before.evaluation_status":[],"source.before.kinds":[2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.49999999999999967,1.0,-3.0,0.5000000000000007,1.0,1.0],"source.after.geometry":[1e-6,0.49999999999999956,1.0,-3.5,0.5000000000000008,1.0,1.5],"source.before.geometry":[1e-6,0.49999999999999956,1.0,-3.5,0.5000000000000008,1.0,1.5]}}
{"case":"api_offset_sphere_out","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,1,1,1,4,2],"result.edge_kinds":[2],"result.face_kinds":[2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[1,1,2],"source.after.evaluation_status":[],"source.after.kinds":[2],"source.after.present":[1],"source.before.counts":[1,1,2],"source.before.evaluation_status":[],"source.before.kinds":[2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.49999999999999944,1.0,-4.0,0.5000000000000009,1.0,2.0],"source.after.geometry":[1e-6,0.49999999999999956,1.0,-3.5,0.5000000000000008,1.0,1.5],"source.before.geometry":[1e-6,0.49999999999999956,1.0,-3.5,0.5000000000000008,1.0,1.5]}}
{"case":"api_offset_sphere_round_out","deferred":null,"error":null,"ints":{"attributes":[1,10,1,1,10007,0,10007,1,1,10507,0,10507],"doing_boolean":[0,0],"executive.present":[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,1,1,1,4,2],"result.edge_kinds":[2],"result.face_kinds":[2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[1,1,2],"source.after.evaluation_status":[],"source.after.kinds":[2],"source.after.present":[1],"source.before.counts":[1,1,2],"source.before.evaluation_status":[],"source.before.kinds":[2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.4999999999999995,0.5,-2.0,0.5000000000000009,0.5,3.0],"source.after.geometry":[1e-6,0.4999999999999996,0.5,-1.5,0.5000000000000007,0.5,2.5],"source.before.geometry":[1e-6,0.4999999999999996,0.5,-1.5,0.5000000000000007,0.5,2.5]}}
@@ -29,40 +29,40 @@
{"case":"api_sheet_duplicate_source_then_null","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[0,0,0,0,2,-1],"selected.before":[0,0,0,0,2,-1],"source.after.counts":[1,1,4,8,4],"source.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.after.kinds":[1],"source.after.present":[1],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1007]},"topology":null,"values":{"source.after.geometry":{"blocks":[[24.500999999999998,48.501,487.501]],"n":27},"source.before.geometry":{"blocks":[[24.500999999999998,48.501,487.501]],"n":27}}}
{"case":"api_sheet_foreign_null_source_order","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.counts":[1,1,4,8,4],"foreign.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"foreign.after.kinds":[1],"foreign.after.present":[1],"foreign.before.counts":[1,1,4,8,4],"foreign.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"foreign.before.kinds":[1],"foreign.before.present":[1],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[1,0,2,-1,0,0],"selected.before":[1,0,2,-1,0,0],"source.after.counts":[1,1,4,8,4],"source.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.after.kinds":[1],"source.after.present":[1],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1007]},"topology":null,"values":{"foreign.after.geometry":{"blocks":[[63.500000000001,77.500000000001,1095.000000000001]],"n":27},"foreign.before.geometry":{"blocks":[[63.500000000001,77.500000000001,1095.000000000001]],"n":27},"source.after.geometry":{"blocks":[[25.000000000001002,25.000000000001002,378.000000000001]],"n":27},"source.before.geometry":{"blocks":[[25.000000000001002,25.000000000001002,378.000000000001]],"n":27}}}
{"case":"api_sheet_null_foreign_source_order","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.counts":[1,1,4,8,4],"foreign.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"foreign.after.kinds":[1],"foreign.after.present":[1],"foreign.before.counts":[1,1,4,8,4],"foreign.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"foreign.before.kinds":[1],"foreign.before.present":[1],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[2,-1,1,0,0,0],"selected.before":[2,-1,1,0,0,0],"source.after.counts":[1,1,4,8,4],"source.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.after.kinds":[1],"source.after.present":[1],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1007]},"topology":null,"values":{"foreign.after.geometry":{"blocks":[[63.500000000001,77.500000000001,1095.000000000001]],"n":27},"foreign.before.geometry":{"blocks":[[63.500000000001,77.500000000001,1095.000000000001]],"n":27},"source.after.geometry":{"blocks":[[25.000000000001002,25.000000000001002,378.000000000001]],"n":27},"source.before.geometry":{"blocks":[[25.000000000001002,25.000000000001002,378.000000000001]],"n":27}}}
{"case":"api_shell_box_closed_extend_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[745047,57700385]],"n":148},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[3,4,12,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_closed_extend_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[745905,68084218]],"n":166},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[3,4,12,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_closed_round_in","deferred":null,"error":null,"ints":{"attributes":[0],"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1001]},"topology":null,"values":{"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_duplicate_face_upstream","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,0,0,0],"selected.before":[0,0,0,0],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,0.0,11.0,11.0,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_selected_face_upstream","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,0],"selected.before":[0,0],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,0.0,11.0,11.0,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_extend_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[725025,54680774]],"n":144},"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_extend_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[725025,54680774]],"n":144},"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_extend_merge_in_reference","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[725060,54683388]],"n":144},"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_extend_merge_in_standalone_copy","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[725025,54680774]],"n":144},"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_extend_merge_in_standalone_reference","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[725130,54688616]],"n":144},"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_extend_merge_in_temp","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[73,468]],"n":39},"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_extend_merge_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[725025,54680774]],"n":144},"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-0.9999999999999999,11.0,11.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_extend_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[725740,63181413]],"n":159},"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_extend_merge_in_reference","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[725775,63184432]],"n":159},"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_extend_merge_in_standalone_copy","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[725740,63181413]],"n":159},"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_extend_merge_in_standalone_reference","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[725845,63190470]],"n":159},"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_extend_merge_in_temp","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[788,14163]],"n":54},"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_extend_merge_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[725883,65061255]],"n":162},"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-0.9999999999999999,11.0,11.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_extend_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[725025,54680774]],"n":144},"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,2,2,2,2,2,2],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.000000000000003,-1.0000000000000038,11.0,11.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_round_in","deferred":null,"error":null,"ints":{"attributes":[0],"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1001]},"topology":null,"values":{"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_round_in_reference","deferred":null,"error":null,"ints":{"attributes":[0],"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1001]},"topology":null,"values":{"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_round_in_standalone_copy","deferred":null,"error":null,"ints":{"attributes":[0],"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1001]},"topology":null,"values":{"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_round_in_standalone_reference","deferred":null,"error":null,"ints":{"attributes":[0],"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1001]},"topology":null,"values":{"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_round_in_temp","deferred":null,"error":null,"ints":{"attributes":[0],"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1001]},"topology":null,"values":{"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_round_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[556775,35669168]],"n":120},"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[24,300]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_round_merge_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[873357,111767385]],"n":216},"doing_boolean":[0,0],"executive.present":[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,30,30,56,224,28],"result.edge_kinds":{"blocks":[[72,2372]],"n":56},"result.face_kinds":{"blocks":[[42,759]],"n":30},"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-1.0,-1.0,-1.0,11.0,11.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_round_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[557490,41646417]],"n":135},"doing_boolean":[0,0],"executive.present":[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,11,12,24,96,16],"result.edge_kinds":{"blocks":[[24,300]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_round_merge_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[687648,123482150],[189312,3407792]],"n":291},"doing_boolean":[0,0],"executive.present":[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,30,30,56,224,28],"result.edge_kinds":{"blocks":[[72,2372]],"n":56},"result.face_kinds":{"blocks":[[42,759]],"n":30},"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-1.0,-1.0,-1.0,11.0,11.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_top_round_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[873357,111767385]],"n":216},"doing_boolean":[0,0],"executive.present":[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,30,30,56,224,28],"result.edge_kinds":{"blocks":[[78,2597]],"n":56},"result.face_kinds":{"blocks":[[46,825]],"n":30},"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-1.0000000000000018,-1.0000000000000013,-1.0000000000000018,11.0,11.000000000000002,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_two_faces_extend_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[705005,51741251]],"n":140},"doing_boolean":[0,0],"executive.present":[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,10,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,0,0,1],"selected.before":[0,0,0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_two_faces_extend_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[705577,58419773]],"n":152},"doing_boolean":[0,0],"executive.present":[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,10,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,0,0,1],"selected.before":[0,0,0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_two_faces_round_in","deferred":null,"error":null,"ints":{"attributes":[0],"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[0,0,0,1],"selected.before":[0,0,0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1001]},"topology":null,"values":{"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_unselected_inset_upstream","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[3,4,12,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_box_unselected_outset_upstream","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[3,4,12,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-0.9999999999999999,11.0,10.999999999999998,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"api_shell_cylinder_r5_top_open_tol_1e6","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[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,5,6,6,24,4],"result.edge_kinds":[1,2,2,2,2,2],"result.face_kinds":[1,1,1,2,2],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[3,3,2],"source.after.evaluation_status":[],"source.after.kinds":[2,1,1],"source.after.present":[1],"source.before.counts":[3,3,2],"source.before.evaluation_status":[],"source.before.kinds":[2,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,4.0,0.0,0.0,5.0,1.1102230246251565e-16,10.0],"source.after.geometry":[1e-6,5.0,0.0,0.0,5.0,0.0,10.0],"source.before.geometry":[1e-6,5.0,0.0,0.0,5.0,0.0,10.0]}}
{"case":"api_shell_cylinder_top_extend_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[226245,6067306]],"n":48},"doing_boolean":[0,0],"executive.present":[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,5,6,6,24,4],"result.edge_kinds":[1,2,2,2,2,2],"result.face_kinds":[1,1,1,2,2],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[3,3,2],"source.after.evaluation_status":[],"source.after.kinds":[2,1,1],"source.after.present":[1],"source.before.counts":[3,3,2],"source.before.evaluation_status":[],"source.before.kinds":[2,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,3.4999999999999996,-2.0000000000000004,0.49999999999999994,4.0,-2.0,5.5],"source.after.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5],"source.before.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5]}}
{"case":"api_shell_cylinder_top_extend_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[226531,7009837]],"n":54},"doing_boolean":[0,0],"executive.present":[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,5,6,6,24,4],"result.edge_kinds":[1,2,2,2,2,2],"result.face_kinds":[1,1,1,2,2],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[3,3,2],"source.after.evaluation_status":[],"source.after.kinds":[2,1,1],"source.after.present":[1],"source.before.counts":[3,3,2],"source.before.evaluation_status":[],"source.before.kinds":[2,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,3.4999999999999996,-2.0000000000000004,0.49999999999999994,4.0,-2.0,5.5],"source.after.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5],"source.before.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5]}}
{"case":"api_shell_cylinder_top_face","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[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,5,6,6,24,4],"result.edge_kinds":[1,2,2,2,2,2],"result.face_kinds":[1,1,1,2,2],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[3,3,2],"source.after.evaluation_status":[],"source.after.kinds":[2,1,1],"source.after.present":[1],"source.before.counts":[3,3,2],"source.before.evaluation_status":[],"source.before.kinds":[2,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,3.4999999999999996,-2.0000000000000004,0.49999999999999994,4.0,-2.0,5.5],"source.after.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5],"source.before.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5]}}
{"case":"api_shell_cylinder_top_round_in","deferred":null,"error":null,"ints":{"attributes":[0],"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[3,3,2],"source.after.evaluation_status":[],"source.after.kinds":[2,1,1],"source.after.present":[1],"source.before.counts":[3,3,2],"source.before.evaluation_status":[],"source.before.kinds":[2,1,1],"source.before.present":[1],"status":[1001]},"topology":null,"values":{"source.after.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5],"source.before.geometry":[1e-6,4.0,-2.0,0.5,4.0,-2.0,5.5]}}
{"case":"api_shell_negative_zero_with_valid_face_copy_first","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[0,0],"selected.before":[0,0],"source.after.counts":[1,1,4,8,4],"source.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.after.kinds":[1],"source.after.present":[1],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1007]},"topology":null,"values":{"source.after.geometry":{"blocks":[[20.500001,20.500001,283.500001]],"n":27},"source.before.geometry":{"blocks":[[20.500001,20.500001,283.500001]],"n":27}}}
{"case":"api_shell_null_source_with_real_foreign_face","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.counts":[1,1,4,8,4],"foreign.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"foreign.after.kinds":[1],"foreign.after.present":[1],"foreign.before.counts":[1,1,4,8,4],"foreign.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"foreign.before.kinds":[1],"foreign.before.present":[1],"input.pure":[1,1],"ownership":[0,0,0],"result.present":[0],"selected.after":[1,0,2,-1],"selected.before":[1,0,2,-1],"source.after.present":[0],"source.before.present":[0],"status":[1007]},"topology":null,"values":{"foreign.after.geometry":{"blocks":[[133.000001,133.000001,1898.0000009999999]],"n":27},"foreign.before.geometry":{"blocks":[[133.000001,133.000001,1898.0000009999999]],"n":27}}}
{"case":"api_shell_sheet_duplicate_valid_copy_path","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[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,1,1,4,8,4],"result.edge_kinds":[1,1,1,1],"result.face_kinds":[1],"result.present":[1],"selected.after":[0,0,0,0],"selected.before":[0,0,0,0],"source.after.counts":[1,1,4,8,4],"source.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.after.kinds":[1],"source.after.present":[1],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-2.0,-6.0,1.0,8.0,15.0,1.0],"source.after.geometry":{"blocks":[[40.500001,68.500001,766.500001]],"n":27},"source.before.geometry":{"blocks":[[40.500001,68.500001,766.500001]],"n":27}}}
{"case":"api_shell_sphere_extend_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[82083,1034809]],"n":20},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[3,4,2,2,2,8,4],"result.edge_kinds":[2,2],"result.face_kinds":[2,2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[1,1,2],"source.after.evaluation_status":[],"source.after.kinds":[2],"source.after.present":[1],"source.before.counts":[1,1,2],"source.before.evaluation_status":[],"source.before.kinds":[2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.4999999999999996,0.5,-1.5,0.5000000000000007,0.5,2.5],"source.after.geometry":[1e-6,0.4999999999999996,0.5,-1.5,0.5000000000000007,0.5,2.5],"source.before.geometry":[1e-6,0.4999999999999996,0.5,-1.5,0.5000000000000007,0.5,2.5]}}
{"case":"api_shell_sphere_extend_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[82226,1222214]],"n":23},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[3,4,2,2,2,8,4],"result.edge_kinds":[2,2],"result.face_kinds":[2,2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[1,1,2],"source.after.evaluation_status":[],"source.after.kinds":[2],"source.after.present":[1],"source.before.counts":[1,1,2],"source.before.evaluation_status":[],"source.before.kinds":[2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.4999999999999996,0.5,-1.5,0.5000000000000007,0.5,2.5],"source.after.geometry":[1e-6,0.4999999999999996,0.5,-1.5,0.5000000000000007,0.5,2.5],"source.before.geometry":[1e-6,0.4999999999999996,0.5,-1.5,0.5000000000000007,0.5,2.5]}}
{"case":"api_shell_sphere_round_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[82083,1034809]],"n":20},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,1],"result.counts":[3,4,2,2,2,8,4],"result.edge_kinds":[2,2],"result.face_kinds":[2,2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[1,1,2],"source.after.evaluation_status":[],"source.after.kinds":[2],"source.after.present":[1],"source.before.counts":[1,1,2],"source.before.evaluation_status":[],"source.before.kinds":[2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.4999999999999996,0.5,-1.5,0.5000000000000007,0.5,2.5],"source.after.geometry":[1e-6,0.4999999999999996,0.5,-1.5,0.5000000000000007,0.5,2.5],"source.before.geometry":[1e-6,0.4999999999999996,0.5,-1.5,0.5000000000000007,0.5,2.5]}}
{"case":"api_shell_thicken_plane_sheet_attributed_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[208243,6702139]],"n":52},"doing_boolean":[0,0],"executive.present":[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,6,6,12,48,8],"result.edge_kinds":[1,1,1,1,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[1,1,4,8,4],"source.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.after.kinds":[1],"source.after.present":[1],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,20.0,10.0,2.0],"source.after.geometry":{"blocks":[[108.000001,108.000001,1358.0000009999999]],"n":27},"source.before.geometry":{"blocks":[[108.000001,108.000001,1358.0000009999999]],"n":27}}}
{"case":"api_shell_thicken_plane_sheet_attributed_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[208962,9774628]],"n":67},"doing_boolean":[0,0],"executive.present":[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,6,6,12,48,8],"result.edge_kinds":[1,1,1,1,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[1,1,4,8,4],"source.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.after.kinds":[1],"source.after.present":[1],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,20.0,10.0,2.0],"source.after.geometry":{"blocks":[[108.000001,108.000001,1358.0000009999999]],"n":27},"source.before.geometry":{"blocks":[[108.000001,108.000001,1358.0000009999999]],"n":27}}}
{"case":"api_shell_valid_duplicates_above_boundary_copy_first","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[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,1,1,4,8,4],"result.edge_kinds":[1,1,1,1],"result.face_kinds":[1],"result.present":[1],"selected.after":[0,0,0,0],"selected.before":[0,0,0,0],"source.after.counts":[1,1,4,8,4],"source.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.after.kinds":[1],"source.after.present":[1],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,1.0,1.0,-3.0,4.0,7.0,-3.0],"source.after.geometry":{"blocks":[[21.500001,43.500001,337.000001]],"n":27},"source.before.geometry":{"blocks":[[21.500001,43.500001,337.000001]],"n":27}}}
{"case":"api_shell_valid_duplicates_below_boundary_copy_first","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[0,0,0,0],"selected.before":[0,0,0,0],"source.after.counts":[1,1,4,8,4],"source.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.after.kinds":[1],"source.after.present":[1],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1007]},"topology":null,"values":{"source.after.geometry":{"blocks":[[21.500001,43.500001,337.000001]],"n":27},"source.before.geometry":{"blocks":[[21.500001,43.500001,337.000001]],"n":27}}}
{"case":"api_shell_valid_duplicates_exact_boundary_copy_first","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[0,0,0,0],"selected.before":[0,0,0,0],"source.after.counts":[1,1,4,8,4],"source.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.after.kinds":[1],"source.after.present":[1],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1001]},"topology":null,"values":{"source.after.geometry":{"blocks":[[21.500001,43.500001,337.000001]],"n":27},"source.before.geometry":{"blocks":[[21.500001,43.500001,337.000001]],"n":27}}}
@@ -542,27 +542,27 @@
{"case":"shell_file_problemShell5_face5_round","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,32,32,76,280,44],"result.edge_kinds":{"blocks":[[80,3224]],"n":76},"result.face_kinds":{"blocks":[[35,621]],"n":32},"result.present":[1],"selected.after":[0,5],"selected.before":[0,5],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,2],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[5.08,0.001599204352952,2.0],"result.geometry":[0.00001,-50.800000000000026,-120.65000000000008,0.0,38.10000000000003,-34.924999999999926,53.56785130816937],"source.after.geometry":[0.00001,-50.8,-120.64999999999999,0.0,38.099999999999994,-34.925,53.567851308169374],"source.before.geometry":[0.00001,-50.8,-120.64999999999999,0.0,38.099999999999994,-34.925,53.567851308169374]}}
{"case":"shell_file_problemShell_face1_extend","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,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,2,3,3,3],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[2,2,2,2,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[2,2,2,2,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[2.54,0.002020058662515,2.0],"result.geometry":[0.002020058662515,-70.18978819404049,-58.82130665004825,-73.66,70.18978809486802,61.834888888888905,73.66],"source.after.geometry":[0.00001,-76.19999999999999,-63.5,-76.19999999999999,76.19999999999999,63.5,76.19999999999999],"source.before.geometry":[0.00001,-76.19999999999999,-63.5,-76.19999999999999,76.19999999999999,63.5,76.19999999999999]}}
{"case":"shell_file_problemShell_face1_round","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,22,28,68,268,50],"result.edge_kinds":{"blocks":[[126,4637]],"n":68},"result.face_kinds":{"blocks":[[59,741]],"n":22},"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[2,2,2,2,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[2,2,2,2,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"executive.geometry_parameters":[2.54,0.002020058662515,2.0],"result.geometry":[0.00001,-76.19999999999999,-63.5,-77.99605122421382,76.20000000000007,63.5,77.99605122421382],"source.after.geometry":[0.00001,-76.19999999999999,-63.5,-76.19999999999999,76.19999999999999,63.5,76.19999999999999],"source.before.geometry":[0.00001,-76.19999999999999,-63.5,-76.19999999999999,76.19999999999999,63.5,76.19999999999999]}}
{"case":"static_offset_box_extend_merge_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[372525,15296207]],"n":76},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-0.9999999999999999,11.0,10.999999999999998,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"static_offset_box_extend_merge_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[373383,21118328]],"n":94},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[0,1,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-0.9999999999999999,11.0,10.999999999999998,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"static_offset_box_extend_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[372525,15296207]],"n":76},"doing_boolean":[0,0],"executive.present":[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,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[2,2,2,2,2,2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-0.9999999999999999,-1.0000000000000033,-1.0000000000000033,11.0,11.0,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"static_offset_box_round_merge_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[624985,65391195]],"n":168},"doing_boolean":[0,0],"executive.present":[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,26,26,48,192,24],"result.edge_kinds":{"blocks":[[72,2052]],"n":48},"result.face_kinds":{"blocks":[[46,681]],"n":26},"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-1.0,-1.0,-1.0,11.0,11.0,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"static_offset_box_round_merge_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[628731,113432292]],"n":246},"doing_boolean":[0,0],"executive.present":[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,26,26,48,192,24],"result.edge_kinds":{"blocks":[[72,2052]],"n":48},"result.face_kinds":{"blocks":[[46,681]],"n":26},"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-1.0,-1.0,-1.0,11.0,11.0,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"static_offset_box_round_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[624985,65391195]],"n":168},"doing_boolean":[0,0],"executive.present":[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,26,26,48,192,24],"result.edge_kinds":{"blocks":[[72,2052]],"n":48},"result.face_kinds":{"blocks":[[46,681]],"n":26},"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-1.0000000000000018,-1.0000000000000013,-1.0000000000000018,11.000000000000002,11.000000000000002,11.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"static_offset_box_round_outset","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[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,26,26,48,192,24],"result.edge_kinds":{"blocks":[[72,2052]],"n":48},"result.face_kinds":{"blocks":[[46,681]],"n":26},"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.875,-2.125,2.875,5.125,4.125,11.125],"source.after.geometry":[1e-6,1.0,-2.0,3.0,5.0,4.0,11.0],"source.before.geometry":[1e-6,1.0,-2.0,3.0,5.0,4.0,11.0]}}
{"case":"static_offset_real_plane_sheet_extended","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[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,1,1,4,8,4],"result.edge_kinds":[1,1,1,1],"result.face_kinds":[1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[1,1,4,8,4],"source.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.after.kinds":[1],"source.after.present":[1],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,2.25,1.0,-4.0,2.25,6.999999999999999,-1.0],"source.after.geometry":{"blocks":[[21.500001,40.500001,330.000001]],"n":27},"source.before.geometry":{"blocks":[[21.500001,40.500001,330.000001]],"n":27}}}
{"case":"static_offset_real_plane_sheet_round","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[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,1,1,4,8,4],"result.edge_kinds":[1,1,1,1],"result.face_kinds":[1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.counts":[1,1,4,8,4],"source.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.after.kinds":[1],"source.after.present":[1],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-7,-2.0,-6.0,2.75,4.0,12.0,2.75],"source.after.geometry":{"blocks":[[30.0000001,58.0000001,622.0000001]],"n":27},"source.before.geometry":{"blocks":[[30.0000001,58.0000001,622.0000001]],"n":27}}}
{"case":"static_shell_box_inset_duplicate_selected_face","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,2,2],"result.counts":[2,2,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,0,0,0],"selected.before":[0,0,0,0],"source.after.counts":[11,24,16],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"static_shell_box_top_extend_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[725025,54680774]],"n":144},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,2,2],"result.counts":[2,2,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[11,24,16],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"static_shell_box_top_extend_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[725025,54680774]],"n":144},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,2,2],"result.counts":[2,2,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[11,24,16],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"static_shell_box_top_extend_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[725740,63181413]],"n":159},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,2,2],"result.counts":[2,2,11,12,24,96,16],"result.edge_kinds":{"blocks":[[36,522]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[11,24,16],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"static_shell_box_top_round_in","deferred":null,"error":null,"ints":{"attributes":[0],"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[6,12,8],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1001]},"topology":null,"values":{"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"static_shell_box_top_round_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[556775,35669168]],"n":120},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,2,2],"result.counts":[2,2,11,12,24,96,16],"result.edge_kinds":{"blocks":[[24,300]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[11,24,16],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"static_shell_box_top_round_merge_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[557490,41646417]],"n":135},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,2,2],"result.counts":[2,2,11,12,24,96,16],"result.edge_kinds":{"blocks":[[24,300]],"n":24},"result.face_kinds":[1,1,1,1,1,1,1,1,1,1,1],"result.present":[1],"selected.after":[0,1],"selected.before":[0,1],"source.after.counts":[11,24,16],"source.after.evaluation_status":[],"source.after.kinds":[1,1,1,1,1,1,1,1,1,1,1],"source.after.present":[1],"source.before.counts":[6,12,8],"source.before.evaluation_status":[],"source.before.kinds":[1,1,1,1,1,1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.after.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0],"source.before.geometry":[1e-6,0.0,0.0,0.0,10.0,10.0,10.0]}}
{"case":"static_shell_sheet_sidewalls","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,3,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,2,2,2,2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.present":[0],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,-1.0,0.9999999999999998,3.0,4.0,6.000000000000001,3.125],"source.before.geometry":{"blocks":[[35.000001,49.000001,601.500001]],"n":27}}}
{"case":"static_shell_thicken_cylinder_sheet_in","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,3,1],"result.counts":[2,2,4,4,8,32,4],"result.edge_kinds":[1,1,2,2,2,2,2,2],"result.face_kinds":[2,2,2,2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.present":[0],"source.before.counts":[1,3,2],"source.before.evaluation_status":[],"source.before.kinds":[2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,8.0,0.0,0.0,10.0,0.0,20.0],"source.before.geometry":[1e-6,10.0,0.0,0.0,10.0,0.0,20.0]}}
{"case":"static_shell_thicken_cylinder_sheet_out","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,3,1],"result.counts":[2,2,4,4,8,32,4],"result.edge_kinds":[1,1,2,2,2,2,2,2],"result.face_kinds":[2,2,2,2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.present":[0],"source.before.counts":[1,3,2],"source.before.evaluation_status":[],"source.before.kinds":[2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,10.0,0.0,0.0,12.0,0.0,20.0],"source.before.geometry":[1e-6,10.0,0.0,0.0,10.0,0.0,20.0]}}
{"case":"static_shell_thicken_cylinder_sheet_small_in","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,3,1],"result.counts":[2,2,4,4,8,32,4],"result.edge_kinds":[1,1,2,2,2,2,2,2],"result.face_kinds":[2,2,2,2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.present":[0],"source.before.counts":[1,3,2],"source.before.evaluation_status":[],"source.before.kinds":[2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,1.4,-1.0,2.0,1.5,-1.0,4.0],"source.before.geometry":[1e-6,1.5,-1.0,2.0,1.5,-1.0,4.0]}}
{"case":"static_shell_thicken_cylinder_sheet_small_out","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,3,1],"result.counts":[2,2,4,4,8,32,4],"result.edge_kinds":[1,1,2,2,2,2,2,2],"result.face_kinds":[2,2,2,2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.present":[0],"source.before.counts":[1,3,2],"source.before.evaluation_status":[],"source.before.kinds":[2],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,1.5,-1.0,2.0,1.6,-1.0,4.0],"source.before.geometry":[1e-6,1.5,-1.0,2.0,1.5,-1.0,4.0]}}
{"case":"static_shell_thicken_plane_sheet_attributed_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[208243,6702139]],"n":52},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,3,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[1,1,1,1,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.present":[0],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,-2.0,20.0,10.0,0.0],"source.before.geometry":{"blocks":[[108.000001,108.000001,1358.0000009999999]],"n":27}}}
{"case":"static_shell_thicken_plane_sheet_attributed_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[208243,6702139]],"n":52},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,3,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[1,1,1,1,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.present":[0],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,20.0,10.0,2.0],"source.before.geometry":{"blocks":[[108.000001,108.000001,1358.0000009999999]],"n":27}}}
{"case":"static_shell_thicken_plane_sheet_attributed_in","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[208962,9774628]],"n":67},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,3,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[1,1,1,1,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.present":[0],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,-2.0,20.0,10.0,0.0],"source.before.geometry":{"blocks":[[108.000001,108.000001,1358.0000009999999]],"n":27}}}
{"case":"static_shell_thicken_plane_sheet_attributed_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[208962,9774628]],"n":67},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,3,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[1,1,1,1,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.present":[0],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,20.0,10.0,2.0],"source.before.geometry":{"blocks":[[108.000001,108.000001,1358.0000009999999]],"n":27}}}
{"case":"static_shell_thicken_plane_sheet_attributed_out_nomerge","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[208243,6702139]],"n":52},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,3,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[2,2,2,2,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,2,2,2,2],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.present":[0],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,20.0,10.0,2.0],"source.before.geometry":{"blocks":[[108.000001,108.000001,1358.0000009999999]],"n":27}}}
{"case":"static_shell_thicken_plane_sheet_attributed_small_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[208243,6702139]],"n":52},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,3,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[1,1,1,1,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.present":[0],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,20.0,10.0,0.25],"source.before.geometry":{"blocks":[[108.000001,108.000001,1358.0000009999999]],"n":27}}}
{"case":"static_shell_thicken_plane_sheet_attributed_small_out","deferred":null,"error":null,"ints":{"attributes":{"blocks":[[208962,9774628]],"n":67},"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[0,1],"ownership":[1,3,1],"result.counts":[2,2,6,6,12,48,8],"result.edge_kinds":[1,1,1,1,2,2,2,2,2,2,2,2],"result.face_kinds":[1,1,1,1,1,1],"result.present":[1],"selected.after":[],"selected.before":[],"source.after.present":[0],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1000]},"topology":null,"values":{"result.geometry":[1e-6,0.0,0.0,0.0,20.0,10.0,0.25],"source.before.geometry":{"blocks":[[108.000001,108.000001,1358.0000009999999]],"n":27}}}
{"case":"static_shell_wire_manifold_query_before_distance","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[],"selected.before":[],"source.after.counts":[0,0,1,2,2],"source.after.evaluation_status":[1000,1000],"source.after.kinds":[1],"source.after.present":[1],"source.before.counts":[0,0,1,2,2],"source.before.evaluation_status":[1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1007]},"topology":null,"values":{"source.after.geometry":{"blocks":[[22.000001,22.000001,251.750001]],"n":17},"source.before.geometry":{"blocks":[[22.000001,22.000001,251.750001]],"n":17}}}
{"case":"tiny_tolerance_sheet_above_boundary","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[],"selected.before":[],"source.after.counts":[1,1,4,8,4],"source.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.after.kinds":[1],"source.after.present":[1],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1007]},"topology":null,"values":{"source.after.geometry":{"blocks":[[13.014999999999999,13.014999999999999,129.303]],"n":27},"source.before.geometry":{"blocks":[[13.014999999999999,13.014999999999999,129.303]],"n":27}}}
{"case":"tiny_tolerance_sheet_below_boundary","deferred":null,"error":null,"ints":{"doing_boolean":[0,0],"executive.present":[0],"executive_offset.present":[0],"foreign.after.present":[0],"foreign.before.present":[0],"input.pure":[1,1],"ownership":[0,1,0],"result.present":[0],"selected.after":[],"selected.before":[],"source.after.counts":[1,1,4,8,4],"source.after.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.after.kinds":[1],"source.after.present":[1],"source.before.counts":[1,1,4,8,4],"source.before.evaluation_status":[1000,1000,1000,1000,1000,1000],"source.before.kinds":[1],"source.before.present":[1],"status":[1007]},"topology":null,"values":{"source.after.geometry":{"blocks":[[13.014999999999999,13.014999999999999,129.303]],"n":27},"source.before.geometry":{"blocks":[[13.014999999999999,13.014999999999999,129.303]],"n":27}}}
+298
View File
@@ -0,0 +1,298 @@
//! Where each face and edge of an operation's result came from, relative to its operand, in
//! the records' order: the identity the kernel carries through its edits, read for one call.
//!
//! Before the call every face and edge of the operand is tagged with its record index (an ops
//! attribute, [`ids::OPS_HISTORY`], which the kernel's splits, merges and copies carry as they
//! carry an application's [`crate::provenance`] data). After it, each result face and edge is
//! read for the tags it carries, and each face for how an offset made it
//! ([`ids::OFFSET_ROLE`]: the offset executive's own relation of the face to what it was made
//! from). Both are removed before the call returns. Nothing is measured or sampled: a face is
//! an offset copy because the kernel made it as one, never because of where it lies.
//!
//! Built for the offset family ([`Made::Offset`], [`Made::Local`]) and usable as it is for any
//! call that edits one body in place ([`Made::Plain`]).
use std::collections::{BTreeMap, BTreeSet};
use solidcore::geom::attribute::{ids, Attribute, Behavior};
use solidcore::topology::face;
use solidcore::{Brep, EntityRef};
use crate::body::Body;
use crate::error::status;
use crate::provenance::{self, Carried, Provenance};
use crate::{Order, Result};
/// The operand faces or edges (record indices) an entity came from: the ops tag.
#[derive(Clone, Debug, PartialEq)]
struct Operand(Vec<usize>);
impl Operand {
fn joined(&self, other: &Self) -> Self {
let mut v = self.0.clone();
v.extend(&other.0);
v.sort_unstable();
v.dedup();
Operand(v)
}
}
impl Provenance for Operand {
// ops' own id, below the applications' (`ids::USER_1`): it never goes through
// `provenance::attach`, whose check is for application data.
const ID: u64 = ids::OPS_HISTORY;
fn split(&self, child: Option<&Self>) -> Option<Self> {
Some(child.map_or_else(|| self.clone(), |c| self.joined(c)))
}
fn merge(&self, result: Option<&Self>) -> Option<Self> {
Some(result.map_or_else(|| self.clone(), |r| self.joined(r)))
}
fn coincident(&self, onto: Option<&Self>) -> Option<Self> {
Some(onto.map_or_else(|| self.clone(), |o| self.joined(o)))
}
}
/// How the call made its faces, which says how the offset roles are read.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Made<'a> {
/// A shell, a thickened sheet or a sheet's offset: a face the offset made as a copy of
/// an operand face is its offset ([`FaceOrigin::OffsetOf`]), one it made along an
/// operand edge stands in that edge's place ([`FaceOrigin::AlongEdge`]).
Offset,
/// A local operation (faces moved, drafted): every face is rebuilt as a copy of its own,
/// so the roles say nothing; the operand faces `moved` (record indices) are
/// [`Change::Modified`].
Local {
/// The faces the call moves.
moved: &'a [usize],
},
/// Any other edit of one body: tags only.
Plain,
}
/// Where a result face came from (operand record indices).
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum FaceOrigin {
/// It lies on operand face `0` (kept, split from it, merged from it, or moved as it).
Face(usize),
/// It is the offset of operand face `0`.
OffsetOf(usize),
/// It was made along operand edge `0` (a thickened sheet's wall).
AlongEdge(usize),
}
/// What became of a result face.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Change {
/// The one face of its operand face.
Kept,
/// Its operand face, moved ([`Made::Local`]).
Modified,
/// One of several faces of one operand face.
Split,
/// One face of several operand faces.
Merged,
/// Made by the call: an offset copy, a wall along an edge, a face at a vertex (with no
/// origin), or a face no operand face carries over (with no origin).
Generated,
}
/// One result face's history.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FaceHistory {
/// What became of it.
pub change: Change,
/// Where it came from, sorted; empty for a face made from nothing the operand names.
pub origins: Vec<FaceOrigin>,
}
/// A result's history, in its record's order ([`Body::to_record`] after the call).
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct History {
/// Each result face's.
pub faces: Vec<FaceHistory>,
/// Each result edge's operand edges (record indices), sorted; empty for an edge the call
/// made (where faces it made meet).
pub edges: Vec<Vec<usize>>,
}
/// `op`, an edit of `body` in place, run with `body`'s faces and edges tagged by their record
/// indices (`order`: the operand's record order), and the result's [`History`]. The tags and
/// the offset roles are removed before this returns, whether `op` succeeds or not.
///
/// # Errors
/// `op`'s error; the kernel's, from the tags (an `order` that names entities the body does not
/// have) or the result's record.
pub fn recorded(
body: &Body,
order: &Order,
made: Made<'_>,
op: impl FnOnce() -> Result<()>,
) -> Result<History> {
tag(body, order)?;
let done = op().and_then(|()| {
let (_, out) = body.to_record()?;
read(&body.lock(), &out, made)
});
let cleared = clear(&mut body.lock());
let history = done?;
cleared?;
Ok(history)
}
/// `op`, a call that makes a new body from `body` (and leaves `body` as it was, such as
/// [`crate::offset_surface`]), run with `body`'s faces and edges tagged by their record indices
/// (`order`), and the new body with its [`History`] relative to `body`, in the new body's record
/// order. The tags and the offset roles are removed from both bodies before this returns,
/// whether `op` succeeds or not.
///
/// # Errors
/// `op`'s error; the kernel's, from the tags or the new body's record.
pub fn recorded_into(
body: &Body,
order: &Order,
made: Made<'_>,
op: impl FnOnce() -> Result<Body>,
) -> Result<(Body, History)> {
tag(body, order)?;
let done = op().and_then(|new| {
let (_, out) = new.to_record()?;
let history = read(&new.lock(), &out, made);
let cleared = clear(&mut new.lock());
let history = history?;
cleared?;
Ok((new, history))
});
let cleared = clear(&mut body.lock());
let result = done?;
cleared?;
Ok(result)
}
/// Every face and edge of `order` tagged with its index, after every ops tag the body carried
/// is gone.
fn tag(body: &Body, order: &Order) -> Result<()> {
let mut b = body.lock();
clear(&mut b)?;
let faces = order.faces.iter().map(|&f| EntityRef::Face(f)).enumerate();
let edges = order.edges.iter().map(|&e| EntityRef::Edge(e)).enumerate();
for (i, e) in faces.chain(edges) {
b.add_attribute(
e,
Attribute::application(ids::OPS_HISTORY, Behavior::Copy, Carried(Operand(vec![i]))),
)
.map_err(status)?;
}
Ok(())
}
/// Every ops tag and offset role on `b`'s faces and edges removed.
fn clear(b: &mut Brep) -> Result<()> {
let entities: Vec<EntityRef> = b
.face_list()
.iter()
.map(|&f| EntityRef::Face(f))
.chain(b.edge_list().iter().map(|&e| EntityRef::Edge(e)))
.collect();
for e in entities {
let marks: Vec<_> = b
.entity_attributes(e)
.into_iter()
.filter(|(_, a)| matches!(a.attribute_id(), ids::OPS_HISTORY | ids::OFFSET_ROLE))
.map(|(h, _)| h)
.collect();
for h in marks {
b.remove_attribute(e, h).map_err(status)?;
}
}
Ok(())
}
/// The operand indices `e` carries.
fn tags(b: &Brep, e: EntityRef) -> Vec<usize> {
provenance::read::<Operand>(b, e).map_or_else(Vec::new, |o| o.0)
}
/// The offset role face `e` carries, if any.
fn role(b: &Brep, e: EntityRef) -> Option<i64> {
b.entity_attributes(e)
.into_iter()
.find(|(_, a)| a.attribute_id() == ids::OFFSET_ROLE)
.and_then(|(_, a)| a.long_value())
}
/// The result's history, read off its tags and roles (`out`: the result's record order).
fn read(b: &Brep, out: &Order, made: Made<'_>) -> Result<History> {
let roles = matches!(made, Made::Offset);
// each face's tags and role; how many result faces without a role carry each tag
let mut faces: Vec<(Vec<usize>, Option<i64>)> = Vec::new();
let mut on: BTreeMap<usize, usize> = BTreeMap::new();
for &f in &out.faces {
let e = EntityRef::Face(f);
let role = if roles { role(b, e) } else { None };
let t = tags(b, e);
if role.is_none() {
for &i in &t {
*on.entry(i).or_default() += 1;
}
}
faces.push((t, role));
}
let mut history = Vec::new();
for (&f, (t, role)) in out.faces.iter().zip(&faces) {
history.push(match *role {
Some(ids::OFFSET_ROLE_COPY) => FaceHistory {
change: Change::Generated,
origins: t.iter().map(|&i| FaceOrigin::OffsetOf(i)).collect(),
},
Some(ids::OFFSET_ROLE_EDGE) => FaceHistory {
change: Change::Generated,
origins: along(b, f)?,
},
Some(_) => FaceHistory {
change: Change::Generated,
origins: Vec::new(),
},
None => FaceHistory {
change: change(t, &on, made),
origins: t.iter().map(|&i| FaceOrigin::Face(i)).collect(),
},
});
}
let edges = out
.edges
.iter()
.map(|&e| tags(b, EntityRef::Edge(e)))
.collect();
Ok(History {
faces: history,
edges,
})
}
/// What became of a face that lies on its operand faces `t`.
fn change(t: &[usize], on: &BTreeMap<usize, usize>, made: Made<'_>) -> Change {
match t {
[] => Change::Generated,
[i] if on.get(i).copied().unwrap_or(0) > 1 => Change::Split,
[i] => match made {
Made::Local { moved } if moved.contains(i) => Change::Modified,
_ => Change::Kept,
},
_ => Change::Merged,
}
}
/// The operand edge a face made along an edge stands on: the one operand edge its edges carry
/// (a thickened sheet's wall: that edge and its copy), or none where they carry none or
/// several.
fn along(b: &Brep, f: solidcore::topology::FaceId) -> Result<Vec<FaceOrigin>> {
let mut found: BTreeSet<usize> = BTreeSet::new();
for e in face::edges(b, f, None, false, None).map_err(status)? {
found.extend(tags(b, EntityRef::Edge(e)));
}
Ok(match found.iter().copied().collect::<Vec<_>>()[..] {
[e] => vec![FaceOrigin::AlongEdge(e)],
_ => Vec::new(),
})
}
+3 -1
View File
@@ -39,11 +39,13 @@ pub mod continuity;
pub mod error;
pub mod extend;
pub mod file;
pub mod history;
pub mod label;
pub mod measure;
pub mod offset;
pub mod order;
pub mod pcurve;
pub mod pick;
pub mod prism;
pub mod provenance;
pub mod record_check;
@@ -69,7 +71,7 @@ pub use measure::{
point_distance, Distance, EdgePoint, FaceCentroid, GapSample, MassPropertiesEstimate, Normal,
PointClass,
};
pub use offset::{draft, offset_faces, offset_sheet, shell, thicken};
pub use offset::{draft, offset_faces, offset_sheet, offset_surface, shell, thicken};
pub use order::Order;
pub use step_assembly::{placed_bodies, PlacedBody};
+3
View File
@@ -419,5 +419,8 @@ pub fn draft(
})?
}
mod surface;
pub use surface::offset_surface;
#[cfg(test)]
mod tests;
+142
View File
@@ -0,0 +1,142 @@
//! Offset surfaces: faces of a body copied out at a signed distance along their normals, as a
//! new body. Each face goes onto its surface's offset on its own, the kernel's offset of the face
//! as a sheet ([`super::offset_sheet`]); the offsets are then joined and stitched where they meet
//! within the caller's tolerance, so neighbours moved to the same place along their shared edge
//! (meeting smoothly) keep sharing it, and across a sharp edge they come apart. Faces that close
//! up make a solid. An offset the kernel cannot make (one that would fold a face over) is its
//! refusal, never a fitted surface. Ops sequences: every face, offset and stitch is the
//! kernel's.
use solidcore::geom::tol::USE_DEFAULT;
use solidcore::topology::brep::p2::{copy_source_ref, CopyNotifyState};
use solidcore::topology::brep::p3::{brep_copy_mapped, new_brep};
use solidcore::topology::brep::p7::copy_faces_from;
use solidcore::topology::loopuse::notify_ref;
use solidcore::topology::{Brep, FaceId};
use solidcore::EntityRef;
use super::{offset_sheet, MAX_DISTANCE};
use crate::body::Body;
use crate::error::status;
use crate::order::{self, Order};
use crate::session::run_on;
use crate::split::copies_of;
use crate::stitch::stitch;
use crate::{Error, Result};
/// Record faces `faces` of `body` (through `order`, each once) offset by `distance` along their
/// outward normals (negative: against them) into one new body, joined where their offsets'
/// edges lie within `tolerance` of each other; with whether the result closes into a solid
/// ([`stitch`]'s). A distance of zero copies the faces. `body` is unchanged; the faces and edges
/// of the result carry what their sources carry (an application's provenance,
/// [`crate::history::recorded_into`]).
///
/// # Errors
/// [`Error::Argument`] for no face, an index past the faces or repeated, a distance not finite
/// or past [`MAX_DISTANCE`], a tolerance not finite and positive; the kernel's refusals (an
/// offset that would fold a face, [`Error::Empty`] for one that leaves nothing); those of
/// [`stitch`].
pub fn offset_surface(
body: &Body,
order: &Order,
faces: &[usize],
distance: f64,
tolerance: f64,
) -> Result<(Body, bool)> {
if faces.is_empty()
|| !(distance.is_finite() && distance.abs() <= MAX_DISTANCE)
|| !(tolerance.is_finite() && tolerance > 0.0)
{
return Err(Error::Argument);
}
let mut picked: Vec<FaceId> = Vec::new();
for &i in faces {
let f = order::face(order, i)?;
if picked.contains(&f) {
return Err(Error::Argument);
}
picked.push(f);
}
let mut sheets = Vec::new();
for f in picked {
let sheet = face_sheet(body, f)?;
if distance != 0.0 {
offset_sheet(&sheet, distance)?;
}
sheets.push(sheet);
}
stitch(joined(&sheets)?, tolerance)
}
/// Face `f` of `body` copied out as a sheet of its own, with what it and its edges carry.
fn face_sheet(body: &Body, f: FaceId) -> Result<Body> {
run_on("offset_surface", &[("brep", body)], |k| {
let (mut whole, src) = {
let g = body.lock();
if !g.face_list().contains(&f) {
return Ok(Err(Error::Argument));
}
let (whole, map) = brep_copy_mapped(k, &g)?;
let face = |e| match e {
EntityRef::Face(x) => Some(x),
_ => None,
};
let Some([src]) = copies_of(&map, &[f], EntityRef::Face, face)
.and_then(|v| <[FaceId; 1]>::try_from(v).ok())
else {
return Ok(Err(Error::Argument));
};
(whole, src)
};
let mut w = new_brep(k, USE_DEFAULT, USE_DEFAULT)?;
w.set_tolerance(whole.tolerance());
match copied_into(k, &mut whole, &[src], &mut w) {
Ok(1) => {}
Ok(_) => return Ok(Err(Error::Empty)),
Err(e) => return Ok(Err(status(e))),
}
Ok(Ok(Body::new(w)))
})?
}
/// The faces of `sheets` copied into one body, each sheet's topology kept.
fn joined(sheets: &[Body]) -> Result<Body> {
let inputs: Vec<(&'static str, &Body)> = sheets.iter().map(|s| ("sheet", s)).collect();
run_on("offset_surface", &inputs, |k| {
let mut dest = new_brep(k, USE_DEFAULT, USE_DEFAULT)?;
for s in sheets {
let mut g = s.lock();
let faces = g.face_list().to_vec();
if let Err(e) = copied_into(k, &mut g, &faces, &mut dest) {
return Ok(Err(status(e)));
}
}
Ok(Ok(Body::new(dest)))
})?
}
/// `faces` of `src` copied into `dest` through the merge, with both bodies' attributes in the
/// copy's notifications so each copy carries what its source carries; how many faces it made.
fn copied_into(
k: &mut solidcore::Kernel,
src: &mut Brep,
faces: &[FaceId],
dest: &mut Brep,
) -> solidcore::Result<usize> {
let mut state = CopyNotifyState::with_attributes_of(src, dest)?;
let this_face = |x: FaceId| notify_ref(EntityRef::Face(x));
let copied = copy_faces_from(
k,
src,
faces,
dest,
true,
&copy_source_ref,
&this_face,
&mut state.env(None),
);
state.restore_attributes(src, dest)?;
let (made, _) = copied?;
dest.refresh_cached_topology();
Ok(made.len())
}
+113
View File
@@ -0,0 +1,113 @@
//! Picks on a body: the face a point lies on, and the faces a pick grows to across the edges
//! where the kernel proves the faces on both sides continue one surface (a hole's wall stored
//! in pieces opens whole). Every decision is the kernel's: the point classification
//! (`SmBrep::Point3DClassify`) and [`solidcore::query::faces_continue`]. Ops chooses and
//! sequences.
use std::collections::BTreeMap;
use solidcore::error::EntityRef;
use solidcore::intersect::point_class::PointClassType;
use solidcore::query::brep::BrepClassifier;
use solidcore::query::faces_continue::{faces_continue, Continues};
use solidcore::topology::{edge, face, EdgeId, FaceId};
use solidcore::Point3;
use crate::body::Body;
use crate::order::{self, Order};
use crate::session::{with_body, Answer};
use crate::{Error, Result};
impl Answer for Vec<FaceId> {}
impl Body {
/// The record face (through `order`) point `p` lies on, within `reach` of it, or `None`:
/// the kernel's classification of the point against the body at that tolerance
/// (`SmBrep::Point3DClassify`, with boundary intersections). A point the kernel puts on an
/// edge or a vertex is on more than one face and picks none; so does a point off the body or
/// one the kernel does not classify. Never a face guessed by nearness.
///
/// # Errors
/// [`Error::Argument`] for a coordinate or a reach that is not finite and positive; the
/// kernel's status (its classification may add trim curves to the body).
pub fn face_at(&self, order: &Order, p: [f64; 3], reach: f64) -> Result<Option<usize>> {
if !(p.iter().all(|x| x.is_finite()) && reach.is_finite() && reach > 0.0) {
return Err(Error::Argument);
}
let point = Point3::new(p[0], p[1], p[2]);
let found = with_body("face_at", self, |k, b| {
let mut classifier = BrepClassifier::of_brep(b);
let pc = match classifier.point_3d_classify(k, point, reach, true) {
Ok(pc) => pc,
Err(e) if e.sm_status().is_some() => return Ok(None),
Err(e) => return Err(e),
};
Ok(match (pc.point_class(), pc.object()) {
(PointClassType::Face, Some(EntityRef::Face(f))) => Some(f),
_ => None,
})
})?;
Ok(found.and_then(|f| order.faces.iter().position(|&x| x == f)))
}
/// Record faces `faces` (through `order`) and every face joined to them, across an edge not
/// in `keep_edges` (record edge indices: the edges that stay apart, such as a split face's
/// line), where the kernel proves the two faces continue one surface with the same outward
/// side ([`faces_continue`]). An edge the kernel leaves undecided is not crossed. The picks
/// first, in their order, then each face as it is reached.
///
/// # Errors
/// [`Error::Argument`] for an index past the faces or the edges; the kernel's (a side it is
/// unsure is material, a dangling id).
pub fn faces_on_one_surface(
&self,
order: &Order,
faces: &[usize],
keep_edges: &[usize],
) -> Result<Vec<usize>> {
let seeds: Vec<FaceId> = faces
.iter()
.map(|&i| order::face(order, i))
.collect::<Result<_>>()?;
let keep: Vec<EdgeId> = keep_edges
.iter()
.map(|&i| order::edge(order, i))
.collect::<Result<_>>()?;
let index: BTreeMap<FaceId, usize> = order
.faces
.iter()
.enumerate()
.map(|(i, &f)| (f, i))
.collect();
let grown = with_body("faces_on_one_surface", self, |_, b| {
let mut out: Vec<FaceId> = Vec::new();
for f in seeds {
if !out.contains(&f) {
out.push(f);
}
}
let mut next = 0;
while let Some(&f) = out.get(next) {
next += 1;
for e in face::edges(b, f, None, false, None)? {
if keep.contains(&e) {
continue;
}
for g in edge::faces(b, e, None)? {
if g != f
&& !out.contains(&g)
&& faces_continue(b, f, g, e)? == Continues::Proved
{
out.push(g);
}
}
}
}
Ok(out)
})?;
grown
.into_iter()
.map(|f| index.get(&f).copied().ok_or(Error::Argument))
.collect()
}
}
+179
View File
@@ -0,0 +1,179 @@
//! History of the offset family (tangency-labs/solidcore#3138): a face the offset made as a
//! copy is that face's offset because the kernel says so, never by where it lies; a wall
//! made along a sheet's edge stands on that edge; a moved face is modified.
#![allow(
clippy::unwrap_used,
clippy::indexing_slicing,
clippy::disallowed_methods // the closed form's oracle, not ops geometry
)]
use std::f64::consts::PI;
use solidcore_ops::boolean::boolean;
use solidcore_ops::history::{recorded, Change, FaceOrigin, History, Made};
use solidcore_ops::sweep::{planar_faces, Curve};
use solidcore_ops::{
make_box, make_cylinder, offset_faces, offset_sheet, session, shell, thicken, Body, BooleanOp,
Order,
};
fn all_fixes() {
session::set_thread_fixes(solidcore::kernel::UpstreamFixes::NAMES.iter().copied()).unwrap();
}
fn near(a: f64, b: f64, tol: f64) -> bool {
(a - b).abs() <= tol * b.abs().max(1.0)
}
/// The record face whose centroid is `at`.
fn face_at(b: &Body, o: &Order, at: [f64; 3]) -> usize {
(0..o.faces.len())
.find(|&f| {
let c = b.face_centroid(o, f, 1e-8).unwrap().centroid;
c.iter().zip(at).all(|(x, y)| (x - y).abs() < 1e-9)
})
.unwrap()
}
fn origins(h: &History, change: Change) -> Vec<FaceOrigin> {
let mut v: Vec<FaceOrigin> = h
.faces
.iter()
.filter(|f| f.change == change)
.flat_map(|f| f.origins.iter().copied())
.collect();
v.sort_unstable();
v
}
/// A 10 cube shelled 1 inward, open at its top: volume 1000 − 8·8·9 = 424. The five inner
/// walls are the offsets of the five faces left closed, which are kept; the top is kept as its
/// rim; every edge of the cube is carried somewhere.
#[test]
fn a_shelled_box_s_inner_walls_are_its_faces_offsets() {
all_fixes();
let b = make_box([0.0; 3], [10.0; 3]).unwrap();
let (_, o) = b.to_record().unwrap();
let top = face_at(&b, &o, [5.0, 5.0, 10.0]);
let h = recorded(&b, &o, Made::Offset, || shell(&b, &o, &[top], -1.0)).unwrap();
assert!(near(b.volume(1e-8).unwrap(), 424.0, 1e-9));
assert_eq!(h.faces.len(), 11);
let closed: Vec<usize> = (0..6).filter(|&f| f != top).collect();
let offsets: Vec<FaceOrigin> = closed.iter().map(|&f| FaceOrigin::OffsetOf(f)).collect();
assert_eq!(origins(&h, Change::Generated), offsets, "{h:?}");
let kept: Vec<FaceOrigin> = (0..6).map(FaceOrigin::Face).collect();
assert_eq!(origins(&h, Change::Kept), kept, "{h:?}");
let mut carried: Vec<usize> = h.edges.iter().flatten().copied().collect();
carried.sort_unstable();
carried.dedup();
assert_eq!(carried, (0..12).collect::<Vec<_>>(), "{h:?}");
// the tags and roles are gone: read again as an offset, nothing is an offset copy
let (_, o2) = b.to_record().unwrap();
let again = recorded(&b, &o2, Made::Offset, || Ok(())).unwrap();
assert!(
again.faces.iter().all(|f| f.change == Change::Kept),
"{again:?}"
);
}
/// A 10 × 10 square sheet thickened 1: volume 100. The sheet stays, its copy is its offset,
/// and each of the four walls stands on its own edge of the square.
#[test]
fn a_thickened_sheet_s_walls_stand_on_its_edges() {
all_fixes();
let p = [
[0.0, 0.0, 0.0],
[10.0, 0.0, 0.0],
[10.0, 10.0, 0.0],
[0.0, 10.0, 0.0],
];
let sides: Vec<Curve> = (0..4)
.map(|i| Curve::Line {
start: p[i],
end: p[(i + 1) % 4],
})
.collect();
let s = planar_faces(&sides).unwrap();
let (_, o) = s.to_record().unwrap();
assert_eq!((o.faces.len(), o.edges.len()), (1, 4));
let h = recorded(&s, &o, Made::Offset, || thicken(&s, 1.0, false)).unwrap();
assert!(near(s.volume(1e-8).unwrap(), 100.0, 1e-9));
assert_eq!(
origins(&h, Change::Kept),
vec![FaceOrigin::Face(0)],
"{h:?}"
);
let made = origins(&h, Change::Generated);
let mut want = vec![FaceOrigin::OffsetOf(0)];
want.extend((0..4).map(FaceOrigin::AlongEdge));
want.sort_unstable();
assert_eq!(made, want, "{h:?}");
}
/// A 10 cube's top moved up 2: volume 1200; the top is modified, the other five kept.
#[test]
fn a_moved_face_is_modified() {
all_fixes();
let b = make_box([0.0; 3], [10.0; 3]).unwrap();
let (_, o) = b.to_record().unwrap();
let top = face_at(&b, &o, [5.0, 5.0, 10.0]);
let h = recorded(&b, &o, Made::Local { moved: &[top] }, || {
offset_faces(&b, &o, &[top], 2.0)
})
.unwrap();
assert!(near(b.volume(1e-8).unwrap(), 1200.0, 1e-9));
assert_eq!(
origins(&h, Change::Modified),
vec![FaceOrigin::Face(top)],
"{h:?}"
);
assert_eq!(origins(&h, Change::Kept).len(), 5, "{h:?}");
}
/// #865's plate (30 × 20 × 6 less an r 1.5 hole 1 from its front) offset 1.5 inward: the
/// hole's offset (r 3) crosses the front's, so the kernel rebuilds the top and bottom offsets
/// whose loops cross and relates the rebuilt faces in place of the old ones. The volume is
/// (27 · 17 − (πr² − segment)) · 3. Every face is an offset copy, the rebuilt top's of the top
/// too: the roles are read where the relations are final.
#[test]
fn an_offset_whose_loops_cross_keeps_the_rebuilt_faces_roles() {
all_fixes();
let plate = make_box([0.0; 3], [30.0, 20.0, 6.0]).unwrap();
let hole = make_cylinder([15.0, 2.5, -1.0], 1.5, 8.0).unwrap();
let b = boolean(plate, hole, BooleanOp::Subtract).unwrap().unwrap();
let (_, o) = b.to_record().unwrap();
let top = face_at_z(&b, &o, 6.0);
let h = recorded(&b, &o, Made::Offset, || offset_sheet(&b, -1.5)).unwrap();
let (t, r) = (1.5_f64, 3.0_f64);
let d = 2.5 - t;
let segment = r * r * (d / r).acos() - d * (r * r - d * d).sqrt();
let want = (27.0 * 17.0 - (PI * r * r - segment)) * 3.0;
assert!(near(b.volume(1e-8).unwrap(), want, 1e-6), "{}", want);
assert!(
h.faces.iter().all(|f| f.change == Change::Generated
&& !f.origins.is_empty()
&& f.origins
.iter()
.all(|o| matches!(o, FaceOrigin::OffsetOf(_)))),
"{h:?}"
);
let (_, after) = b.to_record().unwrap();
let new_top = face_at_z(&b, &after, 4.5);
assert_eq!(
h.faces[new_top].origins,
vec![FaceOrigin::OffsetOf(top)],
"{h:?}"
);
}
/// The one planar face at height `z` facing +z.
fn face_at_z(b: &Body, o: &Order, z: f64) -> usize {
(0..o.faces.len())
.find(|&f| {
b.face_plane_normal(o, f)
.unwrap()
.is_some_and(|n| n.value[2] > 0.5)
&& (b.face_centroid(o, f, 1e-8).unwrap().centroid[2] - z).abs() < 1e-9
})
.unwrap()
}
+116
View File
@@ -0,0 +1,116 @@
//! Offset surfaces (tangency-labs/solidcore#3138): faces copied out at a distance, each on its
//! surface's exact offset, joined where they meet; the cases of SolidCraft's
//! `surface_offset.rs`, on closed forms measured on the exact B-rep.
#![allow(
clippy::unwrap_used,
clippy::disallowed_methods // the closed forms' oracle, not ops geometry
)]
use std::f64::consts::PI;
use solidcore_ops::history::{recorded_into, Change, FaceOrigin, Made};
use solidcore_ops::{make_box, make_cylinder, make_sphere, offset_surface, session, Body, Order};
fn all_fixes() {
session::set_thread_fixes(solidcore::kernel::UpstreamFixes::NAMES.iter().copied()).unwrap();
}
fn rel(a: f64, b: f64) -> f64 {
(a - b).abs() / b.abs().max(1e-9)
}
fn face_at(b: &Body, o: &Order, p: [f64; 3]) -> usize {
b.face_at(o, p, 1e-6).unwrap().unwrap()
}
fn edges(b: &Body) -> usize {
b.to_record().unwrap().1.edges.len()
}
/// Planes move exactly: a 10 cube's top 5 up is a 10 × 10 square at z = 15, the offset of the
/// top. Two faces across a sharp edge come apart (8 edges, none shared); a zero distance copies.
#[test]
fn planes_move_and_sharp_edges_come_apart() {
all_fixes();
let b = make_box([0.0; 3], [10.0; 3]).unwrap();
let (_, o) = b.to_record().unwrap();
let top = face_at(&b, &o, [5.0, 5.0, 10.0]);
let (up, h) = recorded_into(&b, &o, Made::Offset, || {
offset_surface(&b, &o, &[top], 5.0, 0.01).map(|(r, _)| r)
})
.unwrap();
assert!(rel(up.area(1e-8).unwrap(), 100.0) < 1e-9);
let (lo, hi) = up.bounds().unwrap();
assert!(
(lo[2] - 15.0).abs() < 1e-9 && (hi[2] - 15.0).abs() < 1e-9,
"{lo:?} {hi:?}"
);
assert_eq!(h.faces.len(), 1);
assert_eq!(h.faces[0].change, Change::Generated);
assert_eq!(h.faces[0].origins, vec![FaceOrigin::OffsetOf(top)]);
let side = face_at(&b, &o, [5.0, 0.0, 5.0]);
let (two, closed) = offset_surface(&b, &o, &[top, side], 1.0, 0.01).unwrap();
assert!(!closed);
assert_eq!(
(two.to_record().unwrap().1.faces.len(), edges(&two)),
(2, 8)
);
let (copy, _) = offset_surface(&b, &o, &[top, side], 0.0, 0.01).unwrap();
assert!(rel(copy.area(1e-8).unwrap(), 200.0) < 1e-9);
// the body itself is unchanged
assert!(rel(b.volume(1e-8).unwrap(), 1000.0) < 1e-9);
}
/// A cylinder's side (r 10, h 20, one face closed round its seam) moved out by 2 keeps its seam
/// joined, with radius 12: area 2π·12·20. Moved in past its axis: refused.
#[test]
fn a_cylinder_side_changes_radius() {
all_fixes();
let c = make_cylinder([0.0; 3], 10.0, 20.0).unwrap();
let (_, o) = c.to_record().unwrap();
let d = 10.0 / 2f64.sqrt();
let side = face_at(&c, &o, [d, d, 10.0]);
assert_eq!(
face_at(&c, &o, [-d, -d, 10.0]),
side,
"the side is one face"
);
let (out, _) = offset_surface(&c, &o, &[side], 2.0, 0.01).unwrap();
assert!(rel(out.area(1e-8).unwrap(), 2.0 * PI * 12.0 * 20.0) < 1e-7);
let (joined, _) = offset_surface(&c, &o, &[side], 0.0, 0.01).unwrap();
assert_eq!(
edges(&out),
edges(&joined),
"the side still closes on its seam"
);
assert!(offset_surface(&c, &o, &[side], -10.5, 0.01).is_err());
}
/// A ball (r 10) moved out by 2: its faces meet smoothly, so their offsets share every edge and
/// close into the ball of radius 12 (area 4π·144, volume 4π·1728/3); moved in to its centre:
/// refused.
#[test]
fn a_ball_closes_and_is_refused_at_its_centre() {
all_fixes();
let s = make_sphere([0.0; 3], 10.0).unwrap();
let (_, o) = s.to_record().unwrap();
let all: Vec<usize> = (0..o.faces.len()).collect();
let (out, closed) = offset_surface(&s, &o, &all, 2.0, 0.01).unwrap();
assert!(closed, "the offset ball closes into a solid");
assert_eq!(edges(&out), edges(&s));
assert!(rel(out.area(1e-8).unwrap(), 4.0 * PI * 144.0) < 1e-7);
assert!(rel(out.volume(1e-8).unwrap(), 4.0 / 3.0 * PI * 1728.0) < 1e-7);
assert!(offset_surface(&s, &o, &all, -10.0, 0.01).is_err());
}
/// Arguments: no face, a face twice, an index past the faces, a tolerance of 0.
#[test]
fn bad_arguments_are_refused() {
all_fixes();
let b = make_box([0.0; 3], [10.0; 3]).unwrap();
let (_, o) = b.to_record().unwrap();
assert!(offset_surface(&b, &o, &[], 1.0, 0.01).is_err());
assert!(offset_surface(&b, &o, &[0, 0], 1.0, 0.01).is_err());
assert!(offset_surface(&b, &o, &[6], 1.0, 0.01).is_err());
assert!(offset_surface(&b, &o, &[0], 1.0, 0.0).is_err());
}
+95
View File
@@ -0,0 +1,95 @@
//! Picks (tangency-labs/solidcore#3138): the face at a point, by the kernel's classification,
//! none on an edge or off the body; and a pick grown across the edges where the kernel proves
//! the two faces continue one surface.
#![allow(clippy::unwrap_used)]
use solidcore_ops::split::{split_faces, Tool};
use solidcore_ops::{make_box, session, Body, Order};
use solidcore_record::brep::Surface;
fn all_fixes() {
session::set_thread_fixes(solidcore::kernel::UpstreamFixes::NAMES.iter().copied()).unwrap();
}
/// A 10 cube's faces cut by the plane x = 5: the top is two halves on one plane definition.
fn halved_cube() -> (Body, Order) {
let b = make_box([0.0; 3], [10.0; 3]).unwrap();
let (_, o) = b.to_record().unwrap();
let tool = Tool {
surface: Surface::Plane {
origin: [5.0, 0.0, 0.0],
u_axis: [0.0, 1.0, 0.0],
v_axis: [0.0, 0.0, 1.0],
},
domain: [[-1.0, 11.0], [-1.0, 11.0]],
};
let all: Vec<usize> = (0..6).collect();
let (r, _) = split_faces(&b, &o, &all, &[tool]).unwrap().unwrap();
let (_, ro) = r.to_record().unwrap();
(r, ro)
}
/// The face at a point inside each top half is that half; a point on the line between them
/// (an edge), on a box edge, or off the body picks no face.
#[test]
fn a_point_picks_the_face_it_lies_on_and_no_other() {
all_fixes();
let (b, o) = halved_cube();
assert_eq!(o.faces.len(), 10);
let left = b.face_at(&o, [2.5, 5.0, 10.0], 1e-6).unwrap().unwrap();
let right = b.face_at(&o, [7.5, 5.0, 10.0], 1e-6).unwrap().unwrap();
assert_ne!(left, right);
let c = b.face_centroid(&o, left, 1e-8).unwrap().centroid;
assert!(
(c[0] - 2.5).abs() < 1e-9 && (c[2] - 10.0).abs() < 1e-9,
"{c:?}"
);
assert_eq!(
b.face_at(&o, [5.0, 5.0, 10.0], 1e-6).unwrap(),
None,
"on the split line"
);
assert_eq!(
b.face_at(&o, [0.0, 5.0, 10.0], 1e-6).unwrap(),
None,
"on a box edge"
);
assert_eq!(
b.face_at(&o, [5.0, 5.0, 20.0], 1e-6).unwrap(),
None,
"off the body"
);
assert_eq!(
b.face_at(&o, [5.0, 5.0, 5.0], 1e-6).unwrap(),
None,
"inside the body"
);
assert!(b.face_at(&o, [5.0, 5.0, 10.0], 0.0).is_err());
}
/// One top half grows to the other across the split line (one plane definition, the same
/// outward side: proved) and to nothing across the box's edges (another plane); with the
/// split line kept, it stays alone.
#[test]
fn a_pick_grows_across_a_split_line_but_not_a_kept_one() {
all_fixes();
let (b, o) = halved_cube();
let left = b.face_at(&o, [2.5, 5.0, 10.0], 1e-6).unwrap().unwrap();
let right = b.face_at(&o, [7.5, 5.0, 10.0], 1e-6).unwrap().unwrap();
assert_eq!(
b.faces_on_one_surface(&o, &[left], &[]).unwrap(),
vec![left, right]
);
let line: Vec<usize> = (0..o.edges.len())
.filter(|&e| {
let m = b.edge_middle(&o, e).unwrap();
(m[0] - 5.0).abs() < 1e-9 && (m[2] - 10.0).abs() < 1e-9
})
.collect();
assert_eq!(line.len(), 1, "the split line on the top");
assert_eq!(
b.faces_on_one_surface(&o, &[left], &line).unwrap(),
vec![left]
);
assert!(b.faces_on_one_surface(&o, &[99], &[]).is_err());
}
+21
View File
@@ -177,6 +177,27 @@ pub mod ids {
/// id: the attribute carried to a replacement face is an entity's first of its id, so a
/// mark sharing an id with one the face already carries would not travel.
pub const DRAFT_MOVED: u64 = 136;
/// Not upstream (tangency-labs/solidcore#3138): how an offset made a face, set by the
/// offset executive on every face it relates to what it was made from, where those
/// relations are final (`OffsetExecutive::piecewise_merge`), with `Behavior::Copy` so a
/// split or merge after that carries it. Its value: [`OFFSET_ROLE_COPY`] (a face use's
/// offset copy), [`OFFSET_ROLE_EDGE`] (a face made along an edge: a sheet's wall, a
/// round about a convex edge) or [`OFFSET_ROLE_VERTEX`] (a face made at a vertex: a
/// ball). Every face of the original and of the offset loses the role an earlier offset
/// left on it first, so the role a face carries afterwards is this offset's.
pub const OFFSET_ROLE: u64 = 138;
/// [`OFFSET_ROLE`]'s value for a face use's offset copy.
pub const OFFSET_ROLE_COPY: i64 = 1;
/// [`OFFSET_ROLE`]'s value for a face made along an edge.
pub const OFFSET_ROLE_EDGE: i64 = 2;
/// [`OFFSET_ROLE`]'s value for a face made at a vertex.
pub const OFFSET_ROLE_VERTEX: i64 = 3;
/// Not upstream (tangency-labs/solidcore#3138): solidcore-ops' own operand tag, an
/// application attribute naming the operand faces and edges a result face or edge came
/// from, set before one ops call and read and removed after it (`solidcore_ops::history`).
/// Its own id below the applications' (`USER_1` and up), so no application's data is read
/// as it.
pub const OPS_HISTORY: u64 = 140;
/// `SM_AI_METRIC_BASE`: first of the ids used by metric attributes (150-199).
pub const METRIC_BASE: u64 = 150;
/// `SM_AI_MASS_PROPERTIES`.
@@ -81,6 +81,7 @@ use std::collections::{BTreeMap, BTreeSet};
use crate::boolean::merge::p4::KernelManifoldIntersector;
use crate::curve::curve::{Curve, CurveKind};
use crate::error::{ignore_status, ignored, EntityRef, Result, SolidError};
use crate::geom::attribute::{ids, Attribute, Behavior};
use crate::geom::context::{Context, MarkType};
use crate::geom::extent1d::Extent1d;
use crate::geom::extent2d::Extent2d;
@@ -1829,6 +1830,57 @@ impl OffsetExecutive {
}
impl OffsetExecutive {
/// Not upstream (tangency-labs/solidcore#3138): marks every face of the offset with how
/// it was made ([`ids::OFFSET_ROLE`]), from the executive's relations as they stand
/// before the merge, once every face that replaced another (the crossing loops' rebuilt
/// faces) has taken its place in them: a face use's offset copy, a face along an edge,
/// a face at a vertex; a closing face (a sheet's side wall, made along a lamina edge) is
/// a face along an edge too. Every face of `original` and of the offset first loses the
/// role an earlier offset left on it. A related face no longer in the offset is passed
/// over; a face related twice keeps its first role (copies, then edges, then vertices,
/// then closing faces).
///
/// # Errors
///
/// A null-pointer error without an offset B-rep; those of the attribute store.
fn mark_offset_roles(&mut self, original: &mut Brep) -> Result<()> {
let mut roles: Vec<(FaceId, i64)> = Vec::new();
for fu in self.faceuse_to_faces.all_firsts() {
for f in self.faceuse_to_faces.seconds(fu) {
roles.push((f, ids::OFFSET_ROLE_COPY));
}
}
for e in self.edge_to_faces.all_firsts() {
for f in self.edge_to_faces.seconds(e) {
roles.push((f, ids::OFFSET_ROLE_EDGE));
}
}
for v in self.vertex_to_faces.all_firsts() {
for f in self.vertex_to_faces.seconds(v) {
roles.push((f, ids::OFFSET_ROLE_VERTEX));
}
}
// a sheet's side walls are not related to their edges (`build_side_wall_of_edgeuse`
// records them as closing faces only): each stands on one lamina edge
for &f in &self.closing_faces {
roles.push((f, ids::OFFSET_ROLE_EDGE));
}
clear_offset_roles(original)?;
let offset = required(self.offset_brep.as_mut())?;
clear_offset_roles(offset)?;
let mut marked: BTreeSet<FaceId> = BTreeSet::new();
let faces: BTreeSet<FaceId> = offset.face_list().iter().copied().collect();
for (f, role) in roles {
if faces.contains(&f) && marked.insert(f) {
offset.add_attribute(
EntityRef::Face(f),
Attribute::long(ids::OFFSET_ROLE, role, Behavior::Copy),
)?;
}
}
Ok(())
}
/// Stitches or merges the assembled offset (`PiecewiseMerge`).
///
/// On the non-merge path the B-rep is taken and relations are cleared *before*
@@ -1847,6 +1899,7 @@ impl OffsetExecutive {
original: &mut Brep,
notifications: Option<&mut OffsetNotifications<'_>>,
) -> Result<Brep> {
self.mark_offset_roles(original)?;
if !self.merge_results {
self.clear_relations();
let mut result = required(self.offset_brep.take())?;
@@ -3380,6 +3433,27 @@ fn removed_faces_edgeuses(result: &Brep, faces: &[FaceId]) -> Result<BTreeSet<Ed
Ok(gone)
}
/// Every [`ids::OFFSET_ROLE`] on the faces of `b` removed.
///
/// # Errors
///
/// Those of the attribute store.
fn clear_offset_roles(b: &mut Brep) -> Result<()> {
for f in b.face_list().to_vec() {
let e = EntityRef::Face(f);
let marks: Vec<_> = b
.entity_attributes(e)
.into_iter()
.filter(|(_, a)| a.attribute_id() == ids::OFFSET_ROLE)
.map(|(h, _)| h)
.collect();
for h in marks {
b.remove_attribute(e, h)?;
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
+1
View File
@@ -15,6 +15,7 @@ pub mod edge_turn;
pub(crate) mod exact;
pub mod face;
mod face_surface;
pub mod faces_continue;
pub mod r#loop;
pub mod normal;
pub mod poly;
+129
View File
@@ -0,0 +1,129 @@
//! Whether two faces across an edge lie on one surface with the same outward side, proved on
//! the surfaces' definitions: the test an application grows a pick across (a hole's wall
//! stored in two halves opens whole in a shell).
//!
//! Upstream: none (not in SMLib; `SmSurface::CoincidenceCheck` samples a grid of point
//! drops, [`crate::surface::surface::Surface::coincidence_check`], so it proves nothing).
//!
//! | Rust | Upstream |
//! |--------------------|----------|
//! | [`faces_continue`] | (none) |
//! | [`Continues`] | (none) |
//!
//! **The proof.** Two surfaces are one surface when their definitions are identical: two
//! planes with the same placement (origin and axes), two cones or cylinders with the same
//! axis placement, radius at the origin, semi-angle and parameterisation flags, two spheres
//! or two tori with the same placement, radii and flags. Every number is compared bit for
//! bit, so no tolerance enters. Equal definitions have equal natural normals everywhere, so
//! the faces' outward sides agree exactly when the uses of the two faces that face out of
//! their material (for a sheet, its upward use) are both the same way round or both the
//! opposite way round to their surfaces. Anything else (other kinds, definitions that differ
//! in any number, a face with material on both sides) is [`Continues::Undecided`], never a
//! guess.
//!
//! Deviations: not upstream (tangency-labs/solidcore#3138). No recursion.
use crate::error::{Result, SolidError};
use crate::mass::integrator::properties::region_material;
use crate::nurbs::b_spline_surface_n_lib::p2::OrientType;
use crate::surface::surface::{Surface, SurfaceKind};
use crate::topology::edgeuse::p1 as eu;
use crate::topology::face::p2::{face_side_regions, faceuses, surface};
use crate::topology::{edge, Brep, EdgeId, FaceId, RegionId};
const OP: &str = "query::faces_continue";
/// What [`faces_continue`] proves.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Continues {
/// The two faces lie on one surface, their outward sides the same: proved.
Proved,
/// Not proved either way: the surfaces' definitions differ in some number or kind (they
/// may still be one surface), or a face has no side that faces out.
Undecided,
}
/// Whether faces `f` and `g`, both bounded by edge `e`, lie on one surface with the same
/// outward side (see the module's proof).
///
/// # Errors
///
/// [`SolidError::InvalidInput`] for `f` and `g` the same face or an edge that does not bound
/// both; `UnsureRegion` for a side the kernel is unsure is material; `NotFound` for a dangling
/// id.
pub fn faces_continue(b: &Brep, f: FaceId, g: FaceId, e: EdgeId) -> Result<Continues> {
if f == g {
return Err(SolidError::invalid_input(OP, "one face"));
}
for face in [f, g] {
if edge::edgeuse_of_face(b, e, Some(face))?.is_none() {
return Err(SolidError::invalid_input(
OP,
"the edge does not bound the face",
));
}
}
let (Some(sf), Some(sg)) = (surface(b, f)?, surface(b, g)?) else {
return Ok(Continues::Undecided);
};
if !same_definition(sf, sg) {
return Ok(Continues::Undecided);
}
Ok(
match (outward_orientation(b, f)?, outward_orientation(b, g)?) {
(Some(a), Some(c)) if a == c && a != OrientType::Unknown => Continues::Proved,
_ => Continues::Undecided,
},
)
}
/// Whether `a` and `b` have identical definitions, every number bit for bit.
fn same_definition(a: &Surface, b: &Surface) -> bool {
let bits = |x: f64, y: f64| x.to_bits() == y.to_bits();
match (a.kind(), b.kind()) {
(SurfaceKind::Plane(p), SurfaceKind::Plane(q)) => p.position() == q.position(),
(SurfaceKind::Cone(c), SurfaceKind::Cone(d)) => {
c.rev.position == d.rev.position
&& c.rev.swap_uv == d.rev.swap_uv
&& bits(c.base_radius, d.base_radius)
&& bits(c.semi_angle_deg, d.semi_angle_deg)
&& c.inside_out == d.inside_out
&& c.cylinder == d.cylinder
}
(SurfaceKind::Sphere(s), SurfaceKind::Sphere(t)) => {
s.base.position == t.base.position
&& s.base.swap_uv == t.base.swap_uv
&& bits(s.radius, t.radius)
&& s.inside_out == t.inside_out
}
(SurfaceKind::Torus(s), SurfaceKind::Torus(t)) => {
s.base.position == t.base.position
&& s.base.swap_uv == t.base.swap_uv
&& bits(s.major_radius, t.major_radius)
&& bits(s.minor_radius, t.minor_radius)
&& s.inside_out == t.inside_out
}
_ => false,
}
}
/// The orientation, to its surface, of face `f`'s use that faces out of its material: the
/// use on the void side where material is on one side only; for a sheet (material on
/// neither side) its primary use, the upward one; `None` with material on both sides or a
/// use missing.
fn outward_orientation(b: &Brep, f: FaceId) -> Result<Option<OrientType>> {
let (Some(x), Some(y)) = faceuses(b, f)? else {
return Ok(None);
};
let material = |r: Option<RegionId>| match r {
Some(r) => region_material(b, r),
None => Ok(false),
};
let [rx, ry] = face_side_regions(b, f)?;
let out = match (material(rx)?, material(ry)?) {
(true, false) => y,
(false, _) => x,
(true, true) => return Ok(None),
};
eu::faceuse_orientation(b, out).map(Some)
}
+54
View File
@@ -0,0 +1,54 @@
//! `query::faces_continue` (tangency-labs/solidcore#3138): two faces across an edge are proved
//! to continue one another only on identical surface definitions with the same outward side;
//! anything else is undecided, never a guess.
#![allow(clippy::unwrap_used, clippy::indexing_slicing)]
use solidcore::boolean::api_brep::boolean_difference;
use solidcore::math::Point3;
use solidcore::primitive::api_primitives::{create_box, create_cylinder};
use solidcore::query::faces_continue::{faces_continue, Continues};
use solidcore::surface::surface::{Surface, SurfaceKind};
use solidcore::topology::{edge, face, Brep, FaceId};
use solidcore::Kernel;
fn on_cylinder(b: &Brep, f: FaceId) -> bool {
matches!(
face::surface(b, f).unwrap().map(Surface::kind),
Some(SurfaceKind::Cone(_))
)
}
/// A plate drilled through: across every edge, the two faces continue one another exactly
/// when both are the hole's (its wall stored in pieces on one cylinder); a plane beside a
/// plane or the cylinder is undecided. Measured: how many hole edges are proved.
#[test]
fn a_hole_s_pieces_continue_and_nothing_else_does() {
let mut k = Kernel {
fixes: solidcore::kernel::UpstreamFixes::all(),
..Kernel::default()
};
let plate = create_box(&mut k, Point3::new(0.0, 0.0, 0.0), 30.0, 20.0, 6.0).unwrap();
let hole = create_cylinder(&mut k, Point3::new(15.0, 10.0, -1.0), 3.0, 8.0).unwrap();
let b = boolean_difference(&mut k, plate, hole).unwrap();
let (mut proved, mut undecided) = (0, 0);
for e in b.edge_list().to_vec() {
let faces = edge::faces(&b, e, None).unwrap();
let [f, g] = faces[..] else { continue };
if f == g {
continue;
}
let r = faces_continue(&b, f, g, e).unwrap();
let both = on_cylinder(&b, f) && on_cylinder(&b, g);
assert_eq!(r == Continues::Proved, both, "edge {e:?}: {r:?}");
if both {
proved += 1;
} else {
undecided += 1;
}
}
eprintln!("faces_continue: {proved} hole edges proved, {undecided} edges undecided");
assert!(undecided >= 12, "the plate's own edges and the hole's rims");
// an edge that bounds neither face, and one face twice, are the caller's error
let f = b.face_list()[0];
assert!(faces_continue(&b, f, f, b.edge_list()[0]).is_err());
}