draftwright 0.3.6__tar.gz → 0.3.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {draftwright-0.3.6 → draftwright-0.3.8}/.gitignore +3 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/CHANGELOG.md +60 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/PKG-INFO +3 -1
- {draftwright-0.3.6 → draftwright-0.3.8}/README.md +1 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/pyproject.toml +12 -1
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/_core.py +21 -5
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/annotations/_common.py +25 -2
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/annotations/balloons.py +1 -1
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/annotations/from_model.py +252 -44
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/annotations/holes.py +25 -13
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/annotations/orchestrator.py +7 -6
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/annotations/sections.py +33 -29
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/builder.py +30 -30
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/cli.py +9 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/drawing.py +287 -56
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/linting/coverage.py +7 -1
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/linting/structural.py +128 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/linting/suggest.py +9 -9
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/make_drawing.py +5 -4
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/model/detect.py +240 -133
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/model/planner.py +10 -4
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/projection.py +9 -5
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/recognition/slots.py +126 -1
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/recognition/turned.py +8 -2
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/sheet.py +78 -12
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/sheet_emit.py +169 -2
- draftwright-0.3.8/tests/test_agents_guide.py +113 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_declare.py +1 -1
- draftwright-0.3.8/tests/test_detect_registry.py +166 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_drawing_encapsulation.py +26 -1
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_e2e_standards.py +3 -3
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_export_dxf_zoom.py +2 -2
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_gdt_placement.py +3 -1
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_import_boundaries.py +4 -5
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_lint_structural.py +79 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_make_drawing.py +560 -100
- draftwright-0.3.8/tests/test_note_verb.py +59 -0
- draftwright-0.3.8/tests/test_private_test_attr_reads.py +298 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_private_test_imports.py +8 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_render_seam.py +13 -2
- draftwright-0.3.8/tests/test_script_detail_parity.py +400 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_sheet_emit.py +45 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_strip_layout.py +24 -16
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_tolerances.py +118 -7
- draftwright-0.3.6/tests/test_script_detail_parity.py +0 -185
- {draftwright-0.3.6 → draftwright-0.3.8}/LICENSE +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/docs/adr/README.md +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/skills/SKILL.md +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/__init__.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/_geometry.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/analysis.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/annotate.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/annotations/__init__.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/compose.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/export.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/fits.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/fonts/IBMPlexMono-Regular.ttf +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/fonts/IBMPlexSansCondensed-Regular.ttf +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/fonts/LICENSE-IBMPlexMono-OFL.txt +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/fonts/LICENSE-IBMPlexSansCondensed-OFL.txt +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/fonts/__init__.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/intents.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/layout.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/linting/__init__.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/linting/issues.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/model/__init__.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/model/declare.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/model/ir.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/pmi.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/recognition/__init__.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/recognition/_features.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/recognition/_record.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/recognition/chamfers.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/recognition/countersinks.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/recognition/fillets.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/recognition/flats.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/recognition/grooves.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/recognition/levels.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/recognition/plates.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/registry.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/repair.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/score.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/src/draftwright/sheet_dsl.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/_kernel.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/_layout_sig.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/fixtures/grm03_thumbwheel_drive_screw.step +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/fixtures/nist_ctc_01_asme1_ap203.stp +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/fixtures/nist_ctc_01_asme1_ap242.stp +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/fixtures/nist_ctc_02_asme1_ap203.stp +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/fixtures/nist_ctc_02_asme1_ap242.stp +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/fixtures/nist_ctc_03_asme1_ap203.stp +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/fixtures/nist_ctc_03_asme1_ap242.stp +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/fixtures/nist_ctc_04_asme1_ap203.stp +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/fixtures/nist_ctc_04_asme1_ap242.stp +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/fixtures/nist_ctc_05_asme1_ap203.stp +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/fixtures/nist_ctc_05_asme1_ap242.stp +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/refactor_golden/bracket_section.json +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/refactor_golden/centered_rebate.json +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/refactor_golden/chamfered.json +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/refactor_golden/filleted.json +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/refactor_golden/flange_dense.json +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/refactor_golden/grid_plate.json +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/refactor_golden/grooved_shaft.json +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/refactor_golden/hex_bar.json +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/refactor_golden/holed_slot.json +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/refactor_golden/pocketed.json +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/refactor_golden/prismatic_ladder.json +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/refactor_golden/scattered_plate.json +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/refactor_golden/side_drilled.json +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/refactor_golden/turned_stepped.json +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_architecture_docs.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_carve_free_position_callers.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_dense_sheet_canary.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_detect_once.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_e2e_slice.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_fillets_adjacency.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_fits.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_layout.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_layout_cleanliness.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_layout_hypothesis.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_layout_property.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_lint_box_cache.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_lint_reconciliation.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_linting.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_object_aspects.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_occupancy_boxes.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_part_model.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_pitch_dim_footprint.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_pmi.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_recogniser_contract.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_recognition.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_refactor_golden.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_registry.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_score.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_sheet_gdt.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_sheet_notes.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_sheet_of.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_sheet_tables.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_solve_trace.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_turned_steps.py +0 -0
- {draftwright-0.3.6 → draftwright-0.3.8}/tests/test_witness_label_reconciliation.py +0 -0
|
@@ -1,5 +1,65 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.3.8 — 2026-07-23
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`Drawing.note()` — a public free-text note verb** (#817/#820): place a free-form
|
|
8
|
+
`Note` at a page point without reaching for the low-level placement primitive —
|
|
9
|
+
`dwg.note("SEE NOTE 1", at=(x, y))`. This is the safe door for free text that the
|
|
10
|
+
privatisation below needs.
|
|
11
|
+
- **Obround (racetrack) through-slot recognition** (#816): a part whose only features
|
|
12
|
+
are obround through-slots is now recognised, dimensioned, and referenceable for GD&T.
|
|
13
|
+
Previously such slots were silently undetected — and lint falsely reported the drawing
|
|
14
|
+
complete. Stubby obrounds, whose straight side walls are too short to pair, are recovered
|
|
15
|
+
from their two semicircular end caps (a round hole is never mistaken for a slot end).
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- **The generated Sheet script is now self-describing** (#833): `--script --style sheet`
|
|
20
|
+
emits a feature-census header, section sub-headers with repeat tallies (`8× R50`), and a
|
|
21
|
+
plain-language comment on each verb line (`# ⌀8 THRU ×4`, `# slot 40 × 120`, `# R50`).
|
|
22
|
+
All additions are comment-only, so re-run fidelity is unchanged.
|
|
23
|
+
|
|
24
|
+
### Deprecated
|
|
25
|
+
|
|
26
|
+
- **The low-level `Drawing` placement API is now private — the public surface is
|
|
27
|
+
safe-by-default** (#817): `add`, `place_dim`, and the view-coordinate / build-state
|
|
28
|
+
plumbing (`set_view_coordinates`, `drop_view_coordinates`, `attach_part_model`,
|
|
29
|
+
`attach_solve_trace`, `add_view`, `clear_annotations`) are deprecated in favour of the
|
|
30
|
+
feature-backed verbs (`callout` / `dimension` / `locate` / `note` / …), which route
|
|
31
|
+
through the layout solve. Each keeps a `@deprecated` (PEP 702) shim for one release —
|
|
32
|
+
so type-checkers and IDEs flag call sites, not just a runtime warning — and is slated
|
|
33
|
+
for removal in ~0.5.0.
|
|
34
|
+
|
|
35
|
+
### Internal
|
|
36
|
+
|
|
37
|
+
- **`AGENTS.md` — an AI-agent usage guide** (#818) with an executable check, steering
|
|
38
|
+
agents toward the safe declarative surface rather than the low-level primitives.
|
|
39
|
+
- **Coverage reporting is governed and a Codecov badge added** (#825/#832).
|
|
40
|
+
|
|
41
|
+
## v0.3.7 — 2026-07-21
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- **Turned ⌀ leaders point at the feature, not a corner or across the body**
|
|
46
|
+
(#794/#798): the diameter callouts on a turned part now centre on the step's
|
|
47
|
+
mid-length (a boss keeps its frame origin; a ⌀ shared by disjoint steps centres
|
|
48
|
+
on the longest run), so the arrow lands on the middle of the feature's edge
|
|
49
|
+
rather than a step corner. A leader that would otherwise cut diagonally through
|
|
50
|
+
the body — a nested or end feature such as a ⌀6 boss stub — is re-routed out to
|
|
51
|
+
the nearest clear margin (axis-aware: X-turned → left/right, Z-turned → top/
|
|
52
|
+
bottom), pointing straight at the feature instead of clipping the silhouette. A
|
|
53
|
+
re-route that can't be placed clear-and-safe is restored and flagged, and a
|
|
54
|
+
pinned leader is never moved.
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- **`leader_crosses_silhouette` lint notice** (#796): an info-level structural
|
|
59
|
+
notice when a leader shaft passes *through* the projected part body (as opposed
|
|
60
|
+
to a hole callout legitimately exiting an internal hole), so the gap is
|
|
61
|
+
observable even where routing cannot clear it.
|
|
62
|
+
|
|
3
63
|
## v0.3.6 — 2026-07-21
|
|
4
64
|
|
|
5
65
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: draftwright
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.8
|
|
4
4
|
Summary: Automated technical-drawing generation for build123d
|
|
5
5
|
Project-URL: Homepage, https://github.com/pzfreo/draftwright
|
|
6
6
|
Project-URL: Repository, https://github.com/pzfreo/draftwright
|
|
@@ -691,11 +691,13 @@ Requires-Dist: pypdfium2>=4
|
|
|
691
691
|
Requires-Dist: reportlab>=4.0
|
|
692
692
|
Requires-Dist: svglib>=1.5
|
|
693
693
|
Requires-Dist: typer>=0.12
|
|
694
|
+
Requires-Dist: typing-extensions>=4.5; python_full_version < '3.13'
|
|
694
695
|
Description-Content-Type: text/markdown
|
|
695
696
|
|
|
696
697
|
# draftwright
|
|
697
698
|
|
|
698
699
|
[](https://github.com/pzfreo/draftwright/actions/workflows/ci.yml)
|
|
700
|
+
[](https://codecov.io/gh/pzfreo/draftwright)
|
|
699
701
|
[](https://pypi.org/project/draftwright/)
|
|
700
702
|
[](https://pypi.org/project/draftwright/)
|
|
701
703
|
[](LICENSE)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# draftwright
|
|
2
2
|
|
|
3
3
|
[](https://github.com/pzfreo/draftwright/actions/workflows/ci.yml)
|
|
4
|
+
[](https://codecov.io/gh/pzfreo/draftwright)
|
|
4
5
|
[](https://pypi.org/project/draftwright/)
|
|
5
6
|
[](https://pypi.org/project/draftwright/)
|
|
6
7
|
[](LICENSE)
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "draftwright"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.8"
|
|
8
8
|
description = "Automated technical-drawing generation for build123d"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -27,6 +27,8 @@ dependencies = [
|
|
|
27
27
|
"reportlab>=4.0",
|
|
28
28
|
"svglib>=1.5",
|
|
29
29
|
"typer>=0.12",
|
|
30
|
+
# PEP 702 @deprecated: stdlib `warnings.deprecated` lands in 3.13; backport for 3.10–3.12.
|
|
31
|
+
"typing_extensions>=4.5 ; python_full_version < '3.13'",
|
|
30
32
|
]
|
|
31
33
|
keywords = ["build123d", "cad", "drafting", "engineering-drawing", "technical-drawing", "automation"]
|
|
32
34
|
classifiers = [
|
|
@@ -85,8 +87,17 @@ addopts = "--tb=short -m 'not slow'"
|
|
|
85
87
|
[tool.coverage.run]
|
|
86
88
|
source = ["src/draftwright"]
|
|
87
89
|
omit = ["src/draftwright/__init__.py"]
|
|
90
|
+
# Branch coverage makes the regression gate sensitive to untested decision paths,
|
|
91
|
+
# which matter more than raw statement execution in the recognition/layout code.
|
|
92
|
+
branch = true
|
|
88
93
|
|
|
89
94
|
[tool.coverage.report]
|
|
95
|
+
# Baseline measured on the full fast tier on Linux/Python 3.13 (#825):
|
|
96
|
+
# 92.05% combined line+branch coverage (93.90% statements, 86.89% branches).
|
|
97
|
+
# Keep two points of cross-platform/kernel headroom; ratchet upward only after the
|
|
98
|
+
# lowest CI matrix result has stayed above the proposed floor.
|
|
99
|
+
fail_under = 90
|
|
100
|
+
precision = 1
|
|
90
101
|
exclude_lines = [
|
|
91
102
|
"pragma: no cover",
|
|
92
103
|
"if TYPE_CHECKING:",
|
|
@@ -32,6 +32,7 @@ from build123d import Align, BoundBox, Compound, Edge, Location, Mode, Shape, Te
|
|
|
32
32
|
from build123d_drafting.helpers import (
|
|
33
33
|
Dimension,
|
|
34
34
|
TitleBlock,
|
|
35
|
+
annotate,
|
|
35
36
|
draft_preset,
|
|
36
37
|
format_drawing_scale,
|
|
37
38
|
)
|
|
@@ -48,6 +49,21 @@ from draftwright.layout import _greedy_strip_1d, _solve_strip_1d
|
|
|
48
49
|
_log = logging.getLogger(__name__)
|
|
49
50
|
|
|
50
51
|
|
|
52
|
+
def place_annotation(registry, items, obj, name=None, view=None, feature=None):
|
|
53
|
+
"""The annotation-placement primitive (#817): register *obj* under *name* — replacing any
|
|
54
|
+
prior object of that name (dropped from the render list *items*) so a name maps to one
|
|
55
|
+
object — append it to *items*, and record its owning *view* + source *feature* in *registry*.
|
|
56
|
+
Shared by :meth:`Drawing._add` and :meth:`PlacementContext.place` so the render passes place
|
|
57
|
+
annotations without reaching into the ``Drawing``. Returns *obj*."""
|
|
58
|
+
displaced = registry.named(name) if name is not None else None
|
|
59
|
+
if displaced is not None:
|
|
60
|
+
items.remove(displaced)
|
|
61
|
+
annotate(obj, name)
|
|
62
|
+
items.append(obj)
|
|
63
|
+
registry.add(obj, name, view, feature)
|
|
64
|
+
return obj
|
|
65
|
+
|
|
66
|
+
|
|
51
67
|
_MARGIN = 10.0
|
|
52
68
|
|
|
53
69
|
# When a sheet frame is drawn (#767), content reserves this extra band inside the border so
|
|
@@ -841,7 +857,7 @@ def _add_title_block(dwg, a: Analysis):
|
|
|
841
857
|
bx + cell["max_x"],
|
|
842
858
|
_TB_CLEAR + cell["max_y"],
|
|
843
859
|
)
|
|
844
|
-
dwg.
|
|
860
|
+
place_annotation(dwg.registry, dwg.items, tb, "title_block")
|
|
845
861
|
|
|
846
862
|
|
|
847
863
|
def _make_sheet_frame(a: Analysis) -> Compound:
|
|
@@ -866,7 +882,7 @@ def _make_sheet_frame(a: Analysis) -> Compound:
|
|
|
866
882
|
def _add_sheet_frame(dwg, a: Analysis):
|
|
867
883
|
"""Add the sheet border (#767), drawn last like the title block. No-op is the caller's
|
|
868
884
|
(gated on ``a.frame``)."""
|
|
869
|
-
dwg.
|
|
885
|
+
place_annotation(dwg.registry, dwg.items, _make_sheet_frame(a), "sheet_frame")
|
|
870
886
|
|
|
871
887
|
|
|
872
888
|
def _add_projection_symbol(dwg, a: Analysis):
|
|
@@ -893,7 +909,7 @@ def _add_projection_symbol(dwg, a: Analysis):
|
|
|
893
909
|
cy = _TB_CLEAR + _TB_H - h / 2 - 2
|
|
894
910
|
sym = sym.locate(Location((cx - bx, cy - by, 0)))
|
|
895
911
|
sym.is_projection_symbol = True
|
|
896
|
-
dwg.
|
|
912
|
+
place_annotation(dwg.registry, dwg.items, sym, "projection_symbol")
|
|
897
913
|
|
|
898
914
|
|
|
899
915
|
def _add_zone_grid(dwg, a: Analysis):
|
|
@@ -926,12 +942,12 @@ def _add_zone_grid(dwg, a: Analysis):
|
|
|
926
942
|
ticks.append(Edge.make_line(Vector(x1, yb, 0), Vector(x1 + tick, yb, 0)))
|
|
927
943
|
grid = Compound(children=ticks)
|
|
928
944
|
grid.is_zone_grid = True
|
|
929
|
-
dwg.
|
|
945
|
+
place_annotation(dwg.registry, dwg.items, grid, "zone_grid")
|
|
930
946
|
|
|
931
947
|
def _label(text, cx, cy, name):
|
|
932
948
|
note = Note(text, (cx, cy), draft, align=(Align.CENTER, Align.CENTER))
|
|
933
949
|
note.is_zone_label = True
|
|
934
|
-
dwg.
|
|
950
|
+
place_annotation(dwg.registry, dwg.items, note, name)
|
|
935
951
|
|
|
936
952
|
for i in range(cols): # numbers 1.. left→right, in the bottom + top bands
|
|
937
953
|
cx = x0 + (i + 0.5) * cw
|
|
@@ -18,7 +18,11 @@ from typing import Any
|
|
|
18
18
|
|
|
19
19
|
from build123d_drafting.helpers import DEFAULT_FONT_PATH, Dimension, SafeDimension
|
|
20
20
|
|
|
21
|
-
from draftwright._core import
|
|
21
|
+
from draftwright._core import ( # noqa: F401 — _anno_box re-exported (#700)
|
|
22
|
+
_anno_box,
|
|
23
|
+
_text_size,
|
|
24
|
+
place_annotation,
|
|
25
|
+
)
|
|
22
26
|
from draftwright._geometry import _boxes_overlap, _segment_crosses_box # noqa: F401
|
|
23
27
|
from draftwright.layout import StripCandidate, plan_strip
|
|
24
28
|
from draftwright.linting.issues import LintIssue
|
|
@@ -908,6 +912,7 @@ def solve_corridor(dwg, strip, view, axis, cands, tier, corner_reserves=(), *, k
|
|
|
908
912
|
axis,
|
|
909
913
|
pairs,
|
|
910
914
|
tier,
|
|
915
|
+
ctx=ctx,
|
|
911
916
|
features=feats,
|
|
912
917
|
sizes=sizes,
|
|
913
918
|
forbid=forbid,
|
|
@@ -930,6 +935,7 @@ def solve_corridor(dwg, strip, view, axis, cands, tier, corner_reserves=(), *, k
|
|
|
930
935
|
axis,
|
|
931
936
|
force_pairs,
|
|
932
937
|
tier,
|
|
938
|
+
ctx=ctx,
|
|
933
939
|
force=True,
|
|
934
940
|
footprints=foots,
|
|
935
941
|
corner_reserves=corner_reserves,
|
|
@@ -996,6 +1002,9 @@ class PlacementContext:
|
|
|
996
1002
|
# so mypy does not reject the delegating calls below.
|
|
997
1003
|
registry: Any = None # the drawing's AnnotationRegistry: build-issue sink + names
|
|
998
1004
|
coverage: Any = None # the drawing's CoverageState
|
|
1005
|
+
# The drawing's render list (#817): :meth:`place` appends here, so a render pass places an
|
|
1006
|
+
# annotation through the ctx seam (``ctx.place(...)``) instead of reaching into the drawing.
|
|
1007
|
+
items: Any = None
|
|
999
1008
|
# The ensured PartModel (ADR 0008 IR) the run's passes read, threaded off the drawing so
|
|
1000
1009
|
# they no longer reach into ``dwg._part_model`` (#639). Both entry paths set it from the
|
|
1001
1010
|
# PUBLIC ``dwg.model()`` after the model is ensured/attached.
|
|
@@ -1007,6 +1016,19 @@ class PlacementContext:
|
|
|
1007
1016
|
# per-ctx (per-run) index is correct (mirrors the old ``Drawing._hole_feature_index``).
|
|
1008
1017
|
_hole_feature_index: Any = field(default=None, repr=False)
|
|
1009
1018
|
|
|
1019
|
+
def place(self, obj, name=None, view=None, feature=None):
|
|
1020
|
+
"""Place an annotation onto the drawing through this context (#817) — the render passes'
|
|
1021
|
+
door to the placement primitive, so a pass never reaches into the ``Drawing`` (ADR 0005
|
|
1022
|
+
§2). Registers *obj* under *name* (owning *view* + source *feature*) and appends it to the
|
|
1023
|
+
render list. Returns *obj*."""
|
|
1024
|
+
if self.items is None:
|
|
1025
|
+
raise ValueError(
|
|
1026
|
+
"PlacementContext.place() needs the drawing's render list — construct the context "
|
|
1027
|
+
"with items=dwg.items (the orchestrator and Drawing verbs already do; a unit test "
|
|
1028
|
+
"calling a render helper must pass it too)."
|
|
1029
|
+
)
|
|
1030
|
+
return place_annotation(self.registry, self.items, obj, name, view, feature)
|
|
1031
|
+
|
|
1010
1032
|
def feature_of_hole_at(self, location):
|
|
1011
1033
|
"""The IR hole/pattern feature whose member sits at model-space *location*, or ``None``
|
|
1012
1034
|
(#408/#639). Attributes a balloon (which carries a recognition hole, not the IR feature)
|
|
@@ -1107,6 +1129,7 @@ def place_strip_candidates(
|
|
|
1107
1129
|
cands,
|
|
1108
1130
|
tier,
|
|
1109
1131
|
*,
|
|
1132
|
+
ctx,
|
|
1110
1133
|
force=False,
|
|
1111
1134
|
features=None,
|
|
1112
1135
|
sizes=None,
|
|
@@ -1416,7 +1439,7 @@ def place_strip_candidates(
|
|
|
1416
1439
|
for name, dim in placed:
|
|
1417
1440
|
# Record feature provenance (ADR 0010): the drain-time seam for corridor-placed
|
|
1418
1441
|
# dims — `features` maps this batch's names to their source IR feature.
|
|
1419
|
-
|
|
1442
|
+
ctx.place(dim, name, view=view, feature=(features or {}).get(name))
|
|
1420
1443
|
if tp is not None:
|
|
1421
1444
|
tp["unplaced"] = [n for n, _ in todo]
|
|
1422
1445
|
trace.end_pass(tp) # folds a standalone pass's items; no-op when corridor-nested
|
|
@@ -234,7 +234,7 @@ def _render_balloon(dwg, view, tag, j, hole, cx, cy, bx, by, fs, r, ctx):
|
|
|
234
234
|
# Furniture that legitimately sits on the view geometry — exempt from the
|
|
235
235
|
# annotation-overlap / centreline lint, as the section arrows do.
|
|
236
236
|
balloon.is_centerline = True
|
|
237
|
-
|
|
237
|
+
ctx.place(
|
|
238
238
|
balloon,
|
|
239
239
|
f"balloon_{view}_{tag}_{j}",
|
|
240
240
|
view=view,
|