A plate with a hole written to Genie XML comes back without it, and nothing says so.
The SAT reader handles multi-loop faces, because GeniE-authored files have them: faces.py classifies each loop as periphery or hole via the next_loop chain, and PlateFactory._get_primary_loop (faces.py) picks the periphery over a hole. The writer cannot produce one for an adapy plate: plate_to_sat_entities (src/ada/cadit/sat/write/write_plate.py, the unfused path) authors a single loop per face and never sets Loop.next_loop, and the default imprint path is not given the plate's booleans either -- from_imprint.py does chain hole loops off next_loop, but only for regions the imprint itself encloses. from_brep.py (the path for a Part read from a Genie XML with its topology store) also chains loops. So the asymmetry is specifically adapy-authored plates: the reader understands holes the writer can never emit.
Noted in #406 (the plate-outline fix), where holes were deliberately left uncovered because this writer path cannot express one.
Reproduction
Measured on the #406 branch:
import re
import ada
from ada.cadit.sat.write.writer import part_to_sat_writer
pl = ada.Plate("pl", [(0, 0), (4, 0), (4, 3), (0, 3)], 0.01)
pl.add_boolean(ada.PrimBox("hole", (1.5, 1.0, -0.5), (2.5, 2.0, 0.5)))
a = ada.Assembly("A") / (ada.Part("P") / pl)
for imprint in (True, False):
txt = part_to_sat_writer(a, imprint=imprint).to_str()
print(imprint, len([ln for ln in txt.splitlines() if re.search(r"\bloop\b", ln)]))
# True 1
# False 1 -- one loop, the outline only; no hole loop on either path
a.to_genie_xml("hole.xml")
(rp,) = ada.from_genie_xml("hole.xml").get_all_physical_objects(by_type=ada.Plate)
print(len(pl.booleans), len(rp.booleans))
# 1 0 -- the hole is gone, with no warning or error logged
Expected
Either author the hole as a second loop (Loop.next_loop, marked hole) so it survives the SAT, or refuse by name at export time: a plate whose booleans the writer cannot represent is reported with the reason, not written as a solid plate without comment.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Nej3bWxJevs9GkH6tg1WKv
A plate with a hole written to Genie XML comes back without it, and nothing says so.
The SAT reader handles multi-loop faces, because GeniE-authored files have them:
faces.pyclassifies each loop as periphery orholevia thenext_loopchain, andPlateFactory._get_primary_loop(faces.py) picks the periphery over a hole. The writer cannot produce one for an adapy plate:plate_to_sat_entities(src/ada/cadit/sat/write/write_plate.py, the unfused path) authors a single loop per face and never setsLoop.next_loop, and the default imprint path is not given the plate's booleans either --from_imprint.pydoes chain hole loops offnext_loop, but only for regions the imprint itself encloses.from_brep.py(the path for a Part read from a Genie XML with its topology store) also chains loops. So the asymmetry is specifically adapy-authored plates: the reader understands holes the writer can never emit.Noted in #406 (the plate-outline fix), where holes were deliberately left uncovered because this writer path cannot express one.
Reproduction
Measured on the #406 branch:
Expected
Either author the hole as a second loop (
Loop.next_loop, markedhole) so it survives the SAT, or refuse by name at export time: a plate whose booleans the writer cannot represent is reported with the reason, not written as a solid plate without comment.🤖 Generated with Claude Code
https://claude.ai/code/session_01Nej3bWxJevs9GkH6tg1WKv