9168d613977909263d6390bc05dfd9ddc8b78bfd
4
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9168d61397 |
feat(task-6): door, window and room schedules read from the drawing
engineering/arch/schedule.py turns the plan records into schedule rows: doors by tag with width, height, swing, hand and wall; windows by tag with width, height, sill and wall; rooms by number with name and the measured area the label carries, plus a total. Tags compare as numbers (D2 before D10). An opening without a tag gets the next free D1 / W1 - K1 / P1 in Turkish - in wall order; an explicit tag is never renumbered and a generated one never repeats it. A value the model does not carry is an empty cell, never a default, and Turkish output writes decimal commas. draw_schedule reads the ACADMCP_ARCH records off the drawing through the one reader rooms.py already has and draws a real TABLE the way the ISO 7573 parts list does - top-left insertion, the table growing down, the parts list's 7 mm rows and 2.5 mm text at the plot scale, the engine's representation reported. Nothing to schedule, an unknown kind or language and more rows than one TABLE takes are refused before anything is drawn. arch_schedule joins arch_room and arch_rooms_detect under SECTION 25's rooms marker (banner 3 tools), shares the TABLE command with entity_create_table and bom_table, and the counts follow: 232 tools in 25 groups. Live fix in com_backend.entity_create_table. MEASURED on AutoCAD 2026: IAcadTable has no TextHeight property. pywin32 raised AttributeError on `table.TextHeight = h`, the old code swallowed it, and every live table kept the Standard style's heights (title 6.0, header and data 4.5), which is 0.1 mm on paper at 1:50. The member that works is SetCellTextHeight(row, col, h), probed on a scratch document: every cell read back 125.0 via GetCellTextHeight. The row heights stayed 350.0 and GetBoundingBox matched the reported bbox (10000,3250)-(15750,5000). Then draw_schedule ran end to end through ComBackend on a scratch document: a native TABLE on A-SYMB-T-N for doors (5 rows) and rooms/tr (6 rows, total 45,00 m²), and the document was closed afterwards. The new fake in tests/test_table_leader.py has only the measured members. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd |
||
|
|
a2996b0c95 |
fix(task-5): skip what the room reader cannot read, and one face carries one room
read_segments trusted any row with `points`. On a live seat an old-style AcDb2dPolyline's Coordinates are x, y, z triples (measured on AutoCAD 2026, 2026-09-23: [200,200,0, 4200,200,0, ...]) which the backend reads two at a time, so three closed ms.AddPolyline outlines on WALLS reported points like [[0,0],[0,8600],[0,0],[8600,5400],...] and rooms_detect answered five faces of 2.6-6.9 m2 for two 20 m2 rooms. Headless, the same POLYLINE arrives with no points and was dropped without a word; so were walls inside a block reference. The reader now reads LINE and the lightweight polyline only (LWPOLYLINE, and the live AcDbPolyline reported POLYLINE), and lists every other entity that could bound a room in `skipped` with its handle, type and reason: arcs and bulged edges as before, old-style polylines (2DPOLYLINE/3DPOLYLINE live, a vertex-less POLYLINE headless), block references (INSERT / BLOCKREFERENCE) and anything else not a line. Text, dimensions, leaders, points and hatches bound nothing and are passed over. Re-run live on AutoCAD 2026 through the real com_backend._entity_info rows: count 0 with the three polylines in skipped (was 5 wrong rooms); with a lightweight pair and a block added, count 1 at 20 000 000 mm2 plus the block reference in skipped. The backend's stride is left alone (shared file, other readers); this reader no longer trusts it. label_room refused a reused id but not a reused face: a second label in a labelled room (a retry after a transport timeout) wrote a second record with the same area, which a schedule total counts twice. It is now refused before anything is drawn, naming the record and label already there. rooms_detect reports `labels` (every record in the face; `label` stays the first) and `label_conflicts` for a face holding more than one. No new ActiveX member is called. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd |
||
|
|
67d578e09a |
feat(task-5): planar faces, measured room labels and the foreign-plan reader
engineering/arch/faces.py finds the closed faces a set of straight segments bounds: endpoints within tol merge, every segment splits where another crosses or touches it (the T-junction a partition makes), dangling edges are pruned, and the half-edge walk turns to the next edge clockwise so every bounded face comes out counter-clockwise. A piece nested inside a face of another piece is a hole in it, so a ring of walls measures its body and a room with a column measures its floor. Areas come from engineering.measure.polygon_area_perimeter, the arithmetic analysis_measure_entity reports. engineering/arch/rooms.py labels a room with the area of the face its point lies in - a 4000 x 5000 room between 200 mm walls reads 20.00 m2, never the axis area - and writes the room record onto the name text. Opening records close door and window gaps along the wall faces, so two rooms either side of a door stay two rooms. rooms_detect reads any plan's lines, drops faces under min_area and thin wall bodies (mean width under 600 mm, a declared heuristic), reports confidence 1.0 for faces enclosed only by our wall layer and 0.6 otherwise, lists arcs as skipped rather than flattening them, and never modifies the drawing. Two hardenings beyond the plan text, each with a test: read_records pages the current space once and filters to the arch layers locally (the plan paged it once per arch layer - twelve full scans, each a cross-process call per entity on a live seat), keeping the same layer-then-drawing order; and an opening record whose offset falls outside its wall (a stale record) is listed in omitted instead of raising out of the read-only detector. No new ActiveX member is called: both tools compose entity_list, entity_get/set_xdata, layer_list and draw_prims, whose COM paths are already live-verified. SECTION 25 opens on this branch with arch_room and arch_rooms_detect under the rooms marker; until Task 9 gives arch its group they file under entity_creation and entity_query. Alias records, a regenerated inventory, the README snapshot at 231 tools in 25 groups and the frozen group-size snapshot follow. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd |
||
|
|
d5c5e90406 |
feat(arch): the plan model and its foundation - layers, materials, EN/TR, two generalisations
Track F starts here; the three group branches are cut from this commit. - engineering/arch/model.py: Wall, Opening, Stair and Room as frozen dataclasses, and every refusal of spec 4 before anything is drawn, by path (walls[2].thickness): finite positive numbers, an axis of at least two distinct points with no zero-length segment, an arc segment refused by name rather than approximated, an opening on an unknown wall, past its wall, across an axis vertex or overlapping another (both ids named), an unknown material, and a typed room area - areas are measured, never typed. The plan travels as ACADMCP_ARCH XDATA; an opening's door/window kind and a stair's straight/l/u kind ride beside the payload kind as opening_kind / stair_kind, because one key cannot hold both. - engineering/arch/layers.py: the arch set - thirteen ISO 13567-style layers with ISO 128 lineweights only (0.05 mm on the construction scratch layer, as every set in this repository) - and ARCH_ROLE_LAYER, the one place a role becomes a layer. Registered in engineering/layers.py last, which is what keeps the engineering.layers <-> engineering.arch import cycle closed. - engineering/arch/materials.py: eight wall materials, one pattern each, every row citing its source: ANSI31 for brick (ISO 128-50 general hatching, acadiso.pat's own "Iron, Brick, Stone masonry"), AAC as ANSI31 at twice the spacing (a repository convention, and it says so), AR-CONC / AR-SAND as AutoCAD patterns, and the JIS A 0150 RC / stone / wood symbols. Reinforced concrete cannot be ANSI31 and AR-CONC in one HATCH, so it takes the one symbol that names it. Periods on a 1:50 sheet are recomputed from ezdxf's own pattern definitions by the tests. normalise_material is the one reading of a material name, shared by the model and wall_hatch, so the model never refuses "Reinforced Concrete" that the hatch table resolves. - engineering/arch/lang.py: EN / TR vocabulary, D/W and K/P tag prefixes, and the decimal comma for lang="tr" (24,50 m2). - draw_prims(role_layer=) and the XDATA codec's app_id= / kinds=: both generalised with the mechanical defaults, and the mechanical suite passes unchanged against them - that is the regression gate. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd |