draftwright 0.4.14__tar.gz → 0.4.16__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.4.14 → draftwright-0.4.16}/CHANGELOG.md +28 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/PKG-INFO +21 -3
- {draftwright-0.4.14 → draftwright-0.4.16}/README.md +18 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/docs/reference/recogniser-capabilities.md +23 -22
- draftwright-0.4.16/docs/reference/sheet.md +174 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/pyproject.toml +3 -3
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/_core.py +107 -14
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/_geometry.py +28 -3
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/annotations/_common.py +75 -19
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/annotations/from_model.py +358 -111
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/annotations/holes.py +67 -27
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/annotations/sections.py +5 -2
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/builder.py +475 -64
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/compose.py +117 -34
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/drawing.py +733 -17
- draftwright-0.4.16/src/draftwright/export.py +748 -0
- draftwright-0.4.16/src/draftwright/inspection_contract.py +243 -0
- draftwright-0.4.16/src/draftwright/linting/_registry.py +32 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/linting/channel_coverage.py +19 -4
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/linting/coverage.py +200 -34
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/linting/flat_coverage.py +21 -3
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/linting/hole_coverage.py +41 -2
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/linting/polygonal_stock_coverage.py +16 -2
- draftwright-0.4.16/src/draftwright/linting/profiled_bore_coverage.py +238 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/linting/quality.py +13 -3
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/linting/slot_coverage.py +19 -4
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/model/__init__.py +2 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/model/callout.py +75 -8
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/model/compiled.py +73 -11
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/model/declare.py +50 -24
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/model/detect.py +7 -2
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/model/ir.py +214 -3
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/model/planner.py +151 -5
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/projection.py +7 -2
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/recogniser_contract.py +13 -6
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/registry.py +32 -1
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/sheet.py +333 -38
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/sheet_emit.py +288 -31
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/conftest.py +26 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/refactor_golden/flange_dense.json +70 -89
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/refactor_golden/turned_stepped.json +7 -26
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_add_dimension.py +2 -1
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_adr0018_view_selection.py +3 -4
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_audit_differential.py +4 -1
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_compiled_plan_boundary.py +2 -1
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_declared_recognition_gate.py +2 -5
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_detect_once.py +12 -11
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_e2e_standards.py +6 -3
- draftwright-0.4.16/tests/test_export_reproducible.py +699 -0
- draftwright-0.4.16/tests/test_geometry_graph_spike.py +68 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_import_boundaries.py +3 -0
- draftwright-0.4.16/tests/test_inspection_contract.py +158 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1058_wheel_profile.py +5 -1
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1130_view_planning_evidence.py +8 -9
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1217_the_facility_is_shared.py +16 -3
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1260_view_constraints.py +20 -4
- draftwright-0.4.16/tests/test_issue_1262_automatic_turned_views.py +85 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1298_manufacturing_requirements.py +3 -1
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1299_page_escalation.py +22 -9
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1308_machined_leader_analytics.py +14 -9
- draftwright-0.4.16/tests/test_issue_1332_zone_labels.py +70 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1334_prevent_ink.py +29 -0
- draftwright-0.4.16/tests/test_issue_1349_precision_display.py +506 -0
- draftwright-0.4.16/tests/test_issue_1350_detected_takeover.py +559 -0
- draftwright-0.4.16/tests/test_issue_1351_structured_note_coverage.py +651 -0
- draftwright-0.4.16/tests/test_issue_1352_searchable_pdf_text.py +989 -0
- draftwright-0.4.16/tests/test_issue_1353_cnc_authoritative_workflow.py +333 -0
- draftwright-0.4.16/tests/test_issue_1360_thread_depth.py +197 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_443_grm03_axial_coverage.py +4 -2
- draftwright-0.4.16/tests/test_issue_563_placement_intent.py +681 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_798_silhouette_lint.py +8 -2
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_label_provenance.py +2 -15
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_make_drawing.py +145 -29
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_private_test_attr_reads.py +1 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_recogniser_capabilities.py +19 -12
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_recognition_manifest.py +17 -9
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_registry.py +19 -2
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_render_seam.py +9 -4
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_script_detail_parity.py +2 -1
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_sheet_identity_invariant.py +14 -16
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_sheet_of.py +1 -1
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_strip_layout.py +10 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_view_plan.py +8 -2
- draftwright-0.4.14/docs/reference/sheet.md +0 -71
- draftwright-0.4.14/src/draftwright/export.py +0 -356
- draftwright-0.4.14/src/draftwright/linting/profiled_bore_coverage.py +0 -123
- draftwright-0.4.14/tests/test_issue_1332_zone_labels.py +0 -49
- {draftwright-0.4.14 → draftwright-0.4.16}/.gitignore +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/LICENSE +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/docs/adr/README.md +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/docs/research/1062-repeating-radial-profile-evidence.md +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/skills/SKILL.md +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/__init__.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/_build_profile.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/_pmi_part21.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/_warnings.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/analysis.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/annotate.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/annotations/__init__.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/annotations/balloons.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/annotations/gears.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/annotations/leaders.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/annotations/orchestrator.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/audit.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/cli.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/evaluation/__init__.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/evaluation/step_analysis.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/fits.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/fonts/IBMPlexMono-Regular.ttf +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/fonts/IBMPlexSansCondensed-Regular.ttf +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/fonts/LICENSE-IBMPlexMono-OFL.txt +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/fonts/LICENSE-IBMPlexSansCondensed-OFL.txt +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/fonts/__init__.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/intents.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/layout.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/linting/__init__.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/linting/evidence.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/linting/gear_coverage.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/linting/ink_overlap.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/linting/issues.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/linting/pmi_coverage.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/linting/structural.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/linting/suggest.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/make_drawing.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/model/pmi_lowering.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/pmi.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/py.typed +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/recognition/__init__.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/recognition_cache.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/repair.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/score.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/src/draftwright/view_plan.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/_kernel.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/_layout_sig.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/ap242_single_cylinder_diameter.step +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/evaluation/README.md +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/evaluation/ambiguous-open-semicircle.step +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/evaluation/blind-hole.step +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/evaluation/corpus-v1.json +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/evaluation/plain-block.step +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/evaluation/topology-a.step +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/evaluation/topology-b.step +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/grm03_thumbwheel_drive_screw.step +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/grm03_thumbwheel_drive_screw_ap242_pmi.step +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/grm04_drive_plate.step +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/if_step_flat_across_cylinder.step +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/issue_1058_wheel_rh.step +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/issue_909_basic_part_design_017_body.step +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/issue_915_case_study_2.step +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/nist_ctc_01_asme1_ap203.stp +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/nist_ctc_01_asme1_ap242.stp +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/nist_ctc_02_asme1_ap203.stp +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/nist_ctc_02_asme1_ap242.stp +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/nist_ctc_03_asme1_ap203.stp +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/nist_ctc_03_asme1_ap242.stp +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/nist_ctc_04_asme1_ap203.stp +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/nist_ctc_04_asme1_ap242.stp +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/nist_ctc_05_asme1_ap203.stp +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/nist_ctc_05_asme1_ap242.stp +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/fixtures/tuner_jig_blind_obround_pockets.step +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/refactor_golden/bracket_section.json +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/refactor_golden/centered_rebate.json +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/refactor_golden/chamfered.json +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/refactor_golden/filleted.json +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/refactor_golden/grid_plate.json +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/refactor_golden/grooved_shaft.json +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/refactor_golden/hex_bar.json +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/refactor_golden/holed_slot.json +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/refactor_golden/pocketed.json +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/refactor_golden/prismatic_ladder.json +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/refactor_golden/scattered_plate.json +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/refactor_golden/side_drilled.json +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_adr0018_arrangement_gate.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_adr0018_view_routing.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_agents_guide.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_api_docs.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_architecture_docs.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_balloon_ring_standoff.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_build_profile_harness.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_carve_free_position_callers.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_counting_calls.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_declare.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_dense_sheet_canary.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_deprecation_dates.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_detect_registry.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_dimension_role_vocabulary.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_drawing_encapsulation.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_e2e_slice.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_export_dxf_curves.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_export_dxf_zoom.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_external_recognition_boundary.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_fillets_adjacency.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_fits.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_flat_completeness.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_flat_stock_identity.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_flat_stock_opposition.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_gdt_placement.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_grid_lattice_convention.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_iso_nts_caption_placement.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1000_envelope_reuse.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1073_cross_body_patterns.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1082_polygonal_stock.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1086_declared_gears.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1116_ap242_hole_tolerance_lowering.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1142_hole_leader_labels.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1143_hole_completeness.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1144_transactional_hole_table.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1146_scale_completeness.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1147_legibility_pair_aggregation.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1153_contradictory_dimensions.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1154_one_owner_per_measurement.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1155_grm04_sheet_use.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1166_cross_pass_feature_leaders.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1176_quality_fidelity.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1177_angular_dimensions.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1187_unroutable_leaders.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1188_per_view_assignment.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1190_section_decision.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1196_deterministic_view_names.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1202_observed_drawing_consumer.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1204_multiscale_view_issues.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1209_linear_pmi_witnesses.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1215_envelope_tolerance.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1215_no_approved_tolerance_is_dropped.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1216_callout_reservation_measures_ink.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1216_pairwise_across_scale_groups.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1217_claimed_representations.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1219_location_claims_its_own_axis.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1229_ledger_member_keying.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1240_iso_above_strip_visibility.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1254_turned_chamfers.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1276_turned_leader_targets.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1281_turned_fillets.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1296_cylindrical_diameter_pmi.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1312_engine_costs.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1332_overlap_remedy.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1332_overlap_remedy_fast.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1336_grm03_ap242_pmi_fixture.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_1338_scale_before_page_escalation.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_367_leader_ink.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_676_polygonal_boss.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_676_polygonal_boss_declare.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_740_leader_assignment.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_798_floor_cardinality.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_798_material_field.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_885_prismatic_coverage.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_909_sloped_profile.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_915_dense_case.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_916_pocket_leader.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_917_open_channel.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_924_zero_length_shoulders.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_955_height_contingency.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_issue_958_cross_solid_recognition.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_layout.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_layout_cleanliness.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_layout_hypothesis.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_layout_property.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_leader_footprint.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_lint_box_cache.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_lint_ink_overlap.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_lint_reconciliation.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_lint_structural.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_linting.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_location_vocabulary.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_note_verb.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_object_aspects.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_occupancy_boxes.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_parameter_id.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_part_model.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_pitch_dim_footprint.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_pmi.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_pmi_datum_lowering.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_pmi_gtol_lowering.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_pmi_part21.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_pocket_pattern.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_pocket_pattern_recognition.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_principal_profile_classifier.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_private_test_imports.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_quality_components.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_recogniser_adoption.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_recogniser_contract.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_recognition.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_recognition_result.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_refactor_golden.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_repack_geometry_seam.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_score.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_shared_box_memo.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_sheet_emit.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_sheet_gdt.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_sheet_notes.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_sheet_section.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_sheet_tables.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_slanted_blind_step.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_slot_completeness.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_slot_pattern.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_slot_pattern_recognition.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_soft_deprecation.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_solve_trace.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_step_analysis_evaluation.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_suppression_ledger.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_suppression_marks.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_tolerances.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_turned_steps.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_witness_label_reconciliation.py +0 -0
- {draftwright-0.4.14 → draftwright-0.4.16}/tests/test_workflows.py +0 -0
|
@@ -4,6 +4,26 @@
|
|
|
4
4
|
|
|
5
5
|
### Added
|
|
6
6
|
|
|
7
|
+
- Referential and measured Sheet dimensions accept optional `view=` / `side=` placement
|
|
8
|
+
intent. Supported pairs survive IR/compiler and generated-script round trips, constrain
|
|
9
|
+
ordinary corridor candidates without exposing page coordinates, and fail clearly when a
|
|
10
|
+
renderer cannot honour the requested view/strip. Compound hole callouts can therefore be
|
|
11
|
+
authored to opposite sides of one end view while retaining normal solve and lint behavior
|
|
12
|
+
(#563).
|
|
13
|
+
- Feature-linked Sheet notes can explicitly satisfy one or more canonical requirement ids with
|
|
14
|
+
`.note(..., satisfies=(...))`. Placed structured notes retain each requirement's identity in
|
|
15
|
+
coverage reports and generated scripts without masquerading as dimensions or parsing prose;
|
|
16
|
+
removing the note restores the ordinary missing/suppressed diagnostics (#1351).
|
|
17
|
+
- `Sheet.from_part(...).take_over(...)` now adopts detected features in place while choosing
|
|
18
|
+
authored or automatic dimension, principal-view, and derived-view sources explicitly. This
|
|
19
|
+
preserves detected handles, supports automatic principal views with authored requirements,
|
|
20
|
+
replaces or suppresses inferred sections without duplicates, and round-trips the adopted view
|
|
21
|
+
request through generated Sheet code (#1350).
|
|
22
|
+
- Referential Sheet dimensions can preserve an explicit number of decimal places with
|
|
23
|
+
`sheet.dimension(feature, "parameter.id").format(decimals=n)`. The policy changes only
|
|
24
|
+
printed display text: numeric reconciliation, tolerances, suppression and dimension
|
|
25
|
+
provenance continue to use the feature parameter, and generated Sheet scripts round-trip the
|
|
26
|
+
policy (#1349).
|
|
7
27
|
- New lint code `annotation_ink_overlap`: reports another annotation's line-work —
|
|
8
28
|
a dimension line, an extension line or a leader shaft — drawn through a label's
|
|
9
29
|
text, which `annotation_overlap` cannot see because it compares label boxes to
|
|
@@ -17,6 +37,11 @@
|
|
|
17
37
|
|
|
18
38
|
### Changed
|
|
19
39
|
|
|
40
|
+
- Declared Double-D bore, countersink, chamfer, fillet, and groove geometry reads now use the
|
|
41
|
+
stable `b123d_recognisers.inspection` namespace from the exact 0.4.5 wheel. A separate
|
|
42
|
+
Draftwright-owned format-1 contract fails closed on changes to the consumed signatures, result
|
|
43
|
+
schemas, units, bevel rejection reasons, or cylindrical surface layout (#1362).
|
|
44
|
+
|
|
20
45
|
- `annotation_overlap` now reports the whole defect when the same pair also draws
|
|
21
46
|
line-work through one of the two labels: the message names the crosser, the label
|
|
22
47
|
crossed and the millimetres, and replaces the "use `label_offset_x`" remedy, which
|
|
@@ -40,6 +65,9 @@
|
|
|
40
65
|
|
|
41
66
|
### Fixed
|
|
42
67
|
|
|
68
|
+
- Non-1:1 orthographic and isometric projection now scales extracted solids about the world
|
|
69
|
+
origin, matching the view-coordinate mapper and solver zones. Solids carrying a non-zero
|
|
70
|
+
build123d `Location` no longer shift their silhouette away from dimensions and callouts.
|
|
43
71
|
- Notes and generic table cells now render U+2300 `⌀` with the established supported drafting
|
|
44
72
|
glyph instead of IBM Plex Mono's missing-glyph square. The substitution happens at the one
|
|
45
73
|
shared measurement/render seam, so source rows remain unchanged and table sizing stays exact
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: draftwright
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.16
|
|
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
|
|
7
7
|
Project-URL: Issues, https://github.com/pzfreo/draftwright/issues
|
|
8
8
|
Project-URL: Changelog, https://github.com/pzfreo/draftwright/blob/main/CHANGELOG.md
|
|
9
9
|
Project-URL: Documentation, https://pzfreo.github.io/draftwright/
|
|
10
|
-
Author-email: Paul Fremantle <
|
|
10
|
+
Author-email: Paul Fremantle <paul@fremantle.org>
|
|
11
11
|
License: GNU AFFERO GENERAL PUBLIC LICENSE
|
|
12
12
|
Version 3, 19 November 2007
|
|
13
13
|
|
|
@@ -684,7 +684,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
684
684
|
Classifier: Topic :: Scientific/Engineering
|
|
685
685
|
Requires-Python: <3.15,>=3.10
|
|
686
686
|
Requires-Dist: antlr4-python3-runtime<4.10
|
|
687
|
-
Requires-Dist: b123d-recognisers==0.
|
|
687
|
+
Requires-Dist: b123d-recognisers==0.4.5
|
|
688
688
|
Requires-Dist: build123d-drafting-helpers>=0.14.2
|
|
689
689
|
Requires-Dist: build123d<0.11,>=0.9.0; python_full_version < '3.13'
|
|
690
690
|
Requires-Dist: build123d<0.12,>=0.11; python_full_version >= '3.13'
|
|
@@ -823,6 +823,24 @@ a chainable handle (`sheet.hole(bore)`) that the aspect and `control(...)` verbs
|
|
|
823
823
|
targets are placed automatically — the view and strip are derived from the referenced
|
|
824
824
|
feature or face, with `view=`/`side=` overrides.
|
|
825
825
|
|
|
826
|
+
A feature-linked note can explicitly satisfy requirements that are legitimately communicated
|
|
827
|
+
as one compound shop instruction instead of separate dimensions. Use the canonical ids exposed
|
|
828
|
+
by the handle; free prose alone never changes coverage:
|
|
829
|
+
|
|
830
|
+
```python
|
|
831
|
+
assert "counterbore.diameter" in hole.dimension_ids()
|
|
832
|
+
hole.note(
|
|
833
|
+
"PROFILED BORE: ⌀14 × 8 DEEP",
|
|
834
|
+
satisfies=("counterbore.diameter", "counterbore.depth"),
|
|
835
|
+
)
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
Each id remains independent provenance in `drawing.registry.satisfaction_of(annotation_name)`;
|
|
839
|
+
the semantic family outcomes report `satisfied_by_structured_note`, while
|
|
840
|
+
`drawing.lint_summary()["quality"]["completeness"]` aggregates the count. The assertion counts
|
|
841
|
+
only if the normal placement solve places the note. Generated Sheet scripts preserve the
|
|
842
|
+
structured claim. Invalid, duplicate, ambiguous, or face-only claims fail at declaration time.
|
|
843
|
+
|
|
826
844
|
### From a part to an object-referenced script
|
|
827
845
|
|
|
828
846
|
`draftwright part.step --script` writes an editable `Sheet` script. When you built the part
|
|
@@ -123,6 +123,24 @@ a chainable handle (`sheet.hole(bore)`) that the aspect and `control(...)` verbs
|
|
|
123
123
|
targets are placed automatically — the view and strip are derived from the referenced
|
|
124
124
|
feature or face, with `view=`/`side=` overrides.
|
|
125
125
|
|
|
126
|
+
A feature-linked note can explicitly satisfy requirements that are legitimately communicated
|
|
127
|
+
as one compound shop instruction instead of separate dimensions. Use the canonical ids exposed
|
|
128
|
+
by the handle; free prose alone never changes coverage:
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
assert "counterbore.diameter" in hole.dimension_ids()
|
|
132
|
+
hole.note(
|
|
133
|
+
"PROFILED BORE: ⌀14 × 8 DEEP",
|
|
134
|
+
satisfies=("counterbore.diameter", "counterbore.depth"),
|
|
135
|
+
)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Each id remains independent provenance in `drawing.registry.satisfaction_of(annotation_name)`;
|
|
139
|
+
the semantic family outcomes report `satisfied_by_structured_note`, while
|
|
140
|
+
`drawing.lint_summary()["quality"]["completeness"]` aggregates the count. The assertion counts
|
|
141
|
+
only if the normal placement solve places the note. Generated Sheet scripts preserve the
|
|
142
|
+
structured claim. Invalid, duplicate, ambiguous, or face-only claims fail at declaration time.
|
|
143
|
+
|
|
126
144
|
### From a part to an object-referenced script
|
|
127
145
|
|
|
128
146
|
`draftwright part.step --script` writes an editable `Sheet` script. When you built the part
|
|
@@ -11,6 +11,15 @@ completeness treatment, and documentation. A stage is either `supported`, `defer
|
|
|
11
11
|
other CAD consumers apply different policy without making Draftwright policy part of the geometry
|
|
12
12
|
library.
|
|
13
13
|
|
|
14
|
+
Declared-feature geometry reads use a different public boundary. The installed package's
|
|
15
|
+
inspection manifest format 1 is joined to the separate Draftwright-owned declaration in
|
|
16
|
+
`draftwright.inspection_contract`. That contract admits inspection API major 1 and exactly the
|
|
17
|
+
consumed `b123d_recognisers.inspection` symbol schemas: the five geometry readers, their public
|
|
18
|
+
result/error types, the cylindrical surface parameter layout, bevel rejection reasons, and the
|
|
19
|
+
semantic names and units of the Double-D tuple. It also checks the exact installed package
|
|
20
|
+
version. Recognition-family policy does not leak into this smaller measurement contract, and an
|
|
21
|
+
additive inspection symbol does not pretend to be a new recogniser family.
|
|
22
|
+
|
|
14
23
|
## What failures mean
|
|
15
24
|
|
|
16
25
|
Validation fails closed and names the family and boundary whenever possible:
|
|
@@ -67,31 +76,23 @@ with no inferred gear feature added to fill the table.
|
|
|
67
76
|
|
|
68
77
|
## Passage compatibility boundary
|
|
69
78
|
|
|
70
|
-
The installed `b123d-recognisers==0.
|
|
71
|
-
in 0.2.6.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
Draftwright's exact dependency pin must remain on a reviewed released version in the interval
|
|
78
|
-
`>=0.2.6,<0.4.0` until the separately reviewed F4b transition is ready. The lower boundary ensures
|
|
79
|
-
the installed manifest really contains `passages`; the upper boundary prevents accidental adoption
|
|
80
|
-
of the planned 0.4 compatibility change.
|
|
79
|
+
The installed `b123d-recognisers==0.4.5` release contains the `passages` family introduced
|
|
80
|
+
in 0.2.6. Version 0.4.0 makes `SectionPassage` the authoritative physical output and retains
|
|
81
|
+
schema-v1 `Passage` as its compatibility projection. Draftwright declares all six public and nested
|
|
82
|
+
record schemas exhaustively but deliberately keeps the family `unsupported`, with the drafting
|
|
83
|
+
decision tracked by issue #1245. This is a truthful consumer disposition: both aggregate
|
|
84
|
+
inventories are visible and explicitly unscored, while Draftwright does not invent an IR feature,
|
|
85
|
+
DSL declaration, generated code, drawing annotation, or completeness requirement for them.
|
|
81
86
|
|
|
82
|
-
The
|
|
87
|
+
The 0.4 contract is explicit:
|
|
83
88
|
|
|
84
89
|
- `SectionPassage` will be the authoritative physical output and aggregate census source;
|
|
85
90
|
- legacy `Passage` values will be an accepted-only compatibility projection;
|
|
86
91
|
- `recognise_passages(..., ledger=...)` will be a fail-loud unavailable compatibility operation;
|
|
87
92
|
- the writer-free `recognise_passages` name will remain public but non-authoritative; and
|
|
88
|
-
- rich split-junction passages can supersede a
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
validator, tests, exact pin, and lockfile together. The current validator remains unchanged and
|
|
95
|
-
fail closed; there is no forward declaration or stale-manifest exception. Crossing 0.4 also
|
|
96
|
-
requires #1245 to decide what those newly Passage-owned occurrences draw, or an explicit reviewed
|
|
97
|
-
decision to accept the resulting loss of the existing Slot callout.
|
|
93
|
+
- rich split-junction passages can supersede a Slot claim, moving physical ownership to the
|
|
94
|
+
unsupported Passage family through `SLOT_SUPERSEDED_BY_PASSAGE`.
|
|
95
|
+
|
|
96
|
+
The exact 0.4.5 pin, manifest-v2 validator and explicit unsupported inventories make that limitation
|
|
97
|
+
fail-visible rather than silently treating rich passages as supported. Issue #1245 still owns the
|
|
98
|
+
decision about what newly Passage-owned occurrences draw and how they participate in completeness.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Sheet and fluent handles
|
|
2
|
+
|
|
3
|
+
`Sheet` is the declared authoring façade. Feature verbs return fluent handles; those handles
|
|
4
|
+
are documented here because they are part of normal use even though their Python names begin
|
|
5
|
+
with an underscore.
|
|
6
|
+
|
|
7
|
+
## Sheet
|
|
8
|
+
|
|
9
|
+
::: draftwright.sheet.Sheet
|
|
10
|
+
options:
|
|
11
|
+
filters: public
|
|
12
|
+
|
|
13
|
+
### Authored views and layout
|
|
14
|
+
|
|
15
|
+
View declarations are semantic constraints. They name projections, relationships and whole-view
|
|
16
|
+
anchors; the layout solve owns the resulting page positions. Authored views must be paired with
|
|
17
|
+
authored dimensions so a deliberately omitted view cannot strand planner-selected annotations:
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
s = Sheet(part).authored_dimensions().authored_views()
|
|
21
|
+
front = s.view("front")
|
|
22
|
+
plan = s.view("plan").above(front, gap=4).align_x(front)
|
|
23
|
+
s.view("iso").scale(0.75)
|
|
24
|
+
|
|
25
|
+
section = s.section_view("A", through=hole)
|
|
26
|
+
detail = s.detail_view("B", around=hole).scale(2)
|
|
27
|
+
dwg = s.build()
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`view(...)`, `section_view(...)` and `detail_view(...)` define complete authored sets;
|
|
31
|
+
omission suppresses a view. `add_view(...)`, `add_section_view(...)` and
|
|
32
|
+
`add_detail_view(...)` augment an explicitly selected `auto_views()` source. `row(...)` and
|
|
33
|
+
`column(...)` are shorthand for whole-view relations. A principal-view handle's `pin((x, y))`
|
|
34
|
+
anchors its projection origin in page millimetres; it never positions an annotation.
|
|
35
|
+
|
|
36
|
+
Principal orthographic views share the sheet scale and reject `.scale(...)`. Detail and
|
|
37
|
+
isometric handles may carry an independent positive factor. Infeasible relations, scales and
|
|
38
|
+
pins raise with their declaration source; unsupported pins on derived or pictorial views are
|
|
39
|
+
refused at declaration and constraints are never silently relaxed. The immutable authored
|
|
40
|
+
snapshot is available as `sheet.view_constraints`, while `drawing.view_plan` is the distinct
|
|
41
|
+
resolved result.
|
|
42
|
+
|
|
43
|
+
### Taking over a detected baseline
|
|
44
|
+
|
|
45
|
+
`Sheet.from_part(part)` retains the detector's feature set and starts with implicit automatic
|
|
46
|
+
dimensions. Use `take_over(...)` to adopt that same Sheet as an explicit editable request without
|
|
47
|
+
copying features into a second Sheet:
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
s = Sheet.from_part(part)
|
|
51
|
+
hole = s.of(next(feature for feature in s.features if feature.kind == "hole"))
|
|
52
|
+
s.take_over(
|
|
53
|
+
dimensions="authored",
|
|
54
|
+
principal_views="automatic",
|
|
55
|
+
derived_views="authored",
|
|
56
|
+
)
|
|
57
|
+
s.dimension(hole, "bore.diameter")
|
|
58
|
+
s.section_view("A", through=hole)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The three sources are chosen atomically. In this example the principal planner keeps the
|
|
62
|
+
automatic front/plan/side/isometric baseline, while the authored derived set replaces inferred
|
|
63
|
+
sections. Leaving that authored set empty suppresses inferred derived views; selecting
|
|
64
|
+
`derived_views="automatic"` accepts them. Matching declarations may appear before or after
|
|
65
|
+
`take_over(...)` with the same result. Explicit source contradictions fail without partially
|
|
66
|
+
changing the Sheet, and automatic dimensions remain incompatible with authored views under ADR
|
|
67
|
+
0018.
|
|
68
|
+
|
|
69
|
+
To emit editable Python from an adopted Sheet, pass both request halves to the script emitter;
|
|
70
|
+
the model carries the feature/dimension semantics and `view_constraints` carries the independent
|
|
71
|
+
view sources and semantic targets:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from draftwright.sheet_emit import emit_sheet_script
|
|
75
|
+
|
|
76
|
+
source = emit_sheet_script(
|
|
77
|
+
s.model(),
|
|
78
|
+
"part = make_part()",
|
|
79
|
+
"drawing",
|
|
80
|
+
title="BRACKET",
|
|
81
|
+
number="DWG-001",
|
|
82
|
+
view_constraints=s.view_constraints,
|
|
83
|
+
)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Refining a staged hole into manufacturing authority
|
|
87
|
+
|
|
88
|
+
A detected hole remains a live feature handle after takeover. Enrich that handle instead of
|
|
89
|
+
declaring a second, unrelated annotation. Counterbore/spotface tools can supply their geometry;
|
|
90
|
+
thread and fit are authored manufacturing intent:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
s = Sheet.from_part(part, page="A2", scale=1)
|
|
94
|
+
stack = s.of(next(feature for feature in s.features if feature.kind == "hole"))
|
|
95
|
+
s.take_over(
|
|
96
|
+
dimensions="authored",
|
|
97
|
+
principal_views="automatic",
|
|
98
|
+
derived_views="authored",
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
stack.cbore(collar_tool) # diameter and depth re-read from the tool
|
|
102
|
+
stack.thread("M6x1", depth=12).fit("H8")
|
|
103
|
+
for parameter_id in stack.dimension_ids():
|
|
104
|
+
intent = s.dimension(stack, parameter_id)
|
|
105
|
+
if parameter_id == "counterbore.diameter":
|
|
106
|
+
intent.format(decimals=2) # 6.35 remains 6.35, still feature-linked
|
|
107
|
+
|
|
108
|
+
s.section_view("A", through=stack) # replaces inferred derived views
|
|
109
|
+
drawing = s.build()
|
|
110
|
+
assert not [issue for issue in drawing.lint() if issue.severity != "info"]
|
|
111
|
+
drawing.export("quote/grm01", formats=("pdf", "svg", "dxf"))
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
An explicit tap depth is a real `thread.depth` parameter: it appears in
|
|
115
|
+
`dimension_ids()`, participates in authored-set suppression and placement, and round-trips
|
|
116
|
+
through generated Sheet code. `fit("H8")` applies only to `bore.diameter`; it does not leak
|
|
117
|
+
onto a counterbore diameter. A plain `thread("M6x1")` remains valid when no independent depth is
|
|
118
|
+
specified.
|
|
119
|
+
|
|
120
|
+
This surface models the common bore + recess + tap-depth stack in one solver-participating
|
|
121
|
+
callout. More general ordered operation stacks remain tracked by issue #1360. Until a physical
|
|
122
|
+
requirement has a structured parameter, use a feature-linked `note(..., satisfies=(...))` only
|
|
123
|
+
for parameter ids the handle actually exposes; free prose does not satisfy coverage.
|
|
124
|
+
|
|
125
|
+
## View handle
|
|
126
|
+
|
|
127
|
+
::: draftwright.sheet._View
|
|
128
|
+
options:
|
|
129
|
+
filters: public
|
|
130
|
+
|
|
131
|
+
## Dimension intent handle
|
|
132
|
+
|
|
133
|
+
`dimension(feature, parameter_id)` and `add_dimension(feature, parameter_id)` return a
|
|
134
|
+
referential `DimensionIntent`. The handle never carries a replacement nominal and never chooses
|
|
135
|
+
page coordinates. Use `format(decimals=n)` to preserve between 0 and 15 decimal places in the
|
|
136
|
+
printed nominal while reconciliation, tolerance, suppression and provenance continue to read the
|
|
137
|
+
numeric parameter from the feature. Optional `view="front|plan|side"` and
|
|
138
|
+
`side="above|below|left|right"` arguments select a supported semantic corridor when authored
|
|
139
|
+
routing must override the derived default; the normal placement solve still chooses coordinates
|
|
140
|
+
and reports capacity/crossing failures. Trailing zeroes are intentional manufacturing display text:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
sheet.authored_dimensions()
|
|
144
|
+
sheet.dimension(envelope, "width.length").format(decimals=2) # 13.5 prints as 13.50
|
|
145
|
+
sheet.dimension(tapped_hole, "bore.diameter", view="plan", side="left")
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
::: draftwright.sheet.DimensionIntent
|
|
149
|
+
options:
|
|
150
|
+
filters: public
|
|
151
|
+
|
|
152
|
+
## Hole handle
|
|
153
|
+
|
|
154
|
+
::: draftwright.sheet._Hole
|
|
155
|
+
options:
|
|
156
|
+
filters: public
|
|
157
|
+
|
|
158
|
+
## Diameter and step handle
|
|
159
|
+
|
|
160
|
+
::: draftwright.sheet._Dim
|
|
161
|
+
options:
|
|
162
|
+
filters: public
|
|
163
|
+
|
|
164
|
+
## Multi-parameter handle
|
|
165
|
+
|
|
166
|
+
::: draftwright.sheet._Params
|
|
167
|
+
options:
|
|
168
|
+
filters: public
|
|
169
|
+
|
|
170
|
+
## GD&T control builder
|
|
171
|
+
|
|
172
|
+
::: draftwright.sheet._Control
|
|
173
|
+
options:
|
|
174
|
+
filters: public
|
|
@@ -4,11 +4,11 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "draftwright"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.16"
|
|
8
8
|
description = "Automated technical-drawing generation for build123d"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
11
|
-
authors = [{ name = "Paul Fremantle", email = "
|
|
11
|
+
authors = [{ name = "Paul Fremantle", email = "paul@fremantle.org" }]
|
|
12
12
|
requires-python = ">=3.10,<3.15"
|
|
13
13
|
dependencies = [
|
|
14
14
|
# build123d ≤0.10 pulls cadquery-ocp (VTK), whose VTK caps at Python 3.12; 0.11 switched to
|
|
@@ -18,7 +18,7 @@ dependencies = [
|
|
|
18
18
|
"build123d>=0.9.0,<0.11 ; python_full_version < '3.13'",
|
|
19
19
|
"build123d>=0.11,<0.12 ; python_full_version >= '3.13'",
|
|
20
20
|
"build123d-drafting-helpers>=0.14.2",
|
|
21
|
-
"b123d-recognisers==0.
|
|
21
|
+
"b123d-recognisers==0.4.5",
|
|
22
22
|
"numpy>=1.24",
|
|
23
23
|
# PNG raster export (SVG→PDF→PNG). Both permissively licensed (Pillow HPND; pypdfium2
|
|
24
24
|
# Apache-2.0 wrapping Google PDFium BSD-3) and ship pre-built wheels with NO native system
|
|
@@ -29,7 +29,18 @@ if TYPE_CHECKING:
|
|
|
29
29
|
|
|
30
30
|
from draftwright.compose import StripDepths
|
|
31
31
|
|
|
32
|
-
from build123d import
|
|
32
|
+
from build123d import (
|
|
33
|
+
Align,
|
|
34
|
+
BoundBox,
|
|
35
|
+
Compound,
|
|
36
|
+
Edge,
|
|
37
|
+
FontStyle,
|
|
38
|
+
Location,
|
|
39
|
+
Mode,
|
|
40
|
+
Shape,
|
|
41
|
+
Text,
|
|
42
|
+
Vector,
|
|
43
|
+
)
|
|
33
44
|
from build123d_drafting.helpers import (
|
|
34
45
|
Dimension,
|
|
35
46
|
TitleBlock,
|
|
@@ -86,7 +97,16 @@ def _decode_hole_location_fact(fact):
|
|
|
86
97
|
return feature, parameter, point
|
|
87
98
|
|
|
88
99
|
|
|
89
|
-
def place_annotation(
|
|
100
|
+
def place_annotation(
|
|
101
|
+
registry,
|
|
102
|
+
items,
|
|
103
|
+
obj,
|
|
104
|
+
name=None,
|
|
105
|
+
view=None,
|
|
106
|
+
feature=None,
|
|
107
|
+
measurement=None,
|
|
108
|
+
satisfaction=None,
|
|
109
|
+
):
|
|
90
110
|
"""The annotation-placement primitive (#817): register *obj* under *name* — replacing any
|
|
91
111
|
prior object of that name (dropped from the render list *items*) so a name maps to one
|
|
92
112
|
object — append it to *items*, and record its owning *view* + source *feature* in *registry*.
|
|
@@ -94,13 +114,15 @@ def place_annotation(registry, items, obj, name=None, view=None, feature=None, m
|
|
|
94
114
|
annotations without reaching into the ``Drawing``. Returns *obj*.
|
|
95
115
|
|
|
96
116
|
*measurement* is the `DimensionId` *obj* draws, where the caller holds one (#1002) —
|
|
97
|
-
one axis finer than *feature*, since a feature has several measurements.
|
|
117
|
+
one axis finer than *feature*, since a feature has several measurements. *satisfaction*
|
|
118
|
+
is the separate set of requirements a structured note explicitly satisfies (#1351); it
|
|
119
|
+
never claims that the note drew a measurement."""
|
|
98
120
|
displaced = registry.named(name) if name is not None else None
|
|
99
121
|
if displaced is not None:
|
|
100
122
|
items.remove(displaced)
|
|
101
123
|
annotate(obj, name)
|
|
102
124
|
items.append(obj)
|
|
103
|
-
registry.add(obj, name, view, feature, measurement)
|
|
125
|
+
registry.add(obj, name, view, feature, measurement, satisfaction)
|
|
104
126
|
return obj
|
|
105
127
|
|
|
106
128
|
|
|
@@ -362,6 +384,7 @@ def _text_size(
|
|
|
362
384
|
font_size: float,
|
|
363
385
|
font_path: str | None = PLEX_MONO,
|
|
364
386
|
font: str = "Arial",
|
|
387
|
+
font_style: FontStyle = FontStyle.REGULAR,
|
|
365
388
|
) -> tuple[float, float]:
|
|
366
389
|
"""Measured rendered (width, height) (page-mm) of *text* at *font_size*.
|
|
367
390
|
|
|
@@ -383,12 +406,43 @@ def _text_size(
|
|
|
383
406
|
font_size=font_size,
|
|
384
407
|
font=font,
|
|
385
408
|
font_path=font_path,
|
|
409
|
+
font_style=font_style,
|
|
386
410
|
align=(Align.CENTER, Align.CENTER),
|
|
387
411
|
mode=Mode.PRIVATE,
|
|
388
412
|
).bounding_box()
|
|
389
413
|
return (bb.size.X, bb.size.Y)
|
|
390
414
|
|
|
391
415
|
|
|
416
|
+
@functools.lru_cache(maxsize=32)
|
|
417
|
+
def _text_line_spacing_em(
|
|
418
|
+
font_size: float,
|
|
419
|
+
font_path: str | None = PLEX_MONO,
|
|
420
|
+
font: str = "Arial",
|
|
421
|
+
) -> float:
|
|
422
|
+
"""Return OCCT's actual newline advance for a regular face, in em units.
|
|
423
|
+
|
|
424
|
+
The advance is face-dependent (Plex Mono is 1.3 em; named Arial on macOS is
|
|
425
|
+
about 1.15 em). Measure the same repeated glyph twice through build123d so
|
|
426
|
+
the invisible PDF layer follows the renderer instead of baking either value.
|
|
427
|
+
"""
|
|
428
|
+
probe = Text(
|
|
429
|
+
txt="A\nA",
|
|
430
|
+
font_size=font_size,
|
|
431
|
+
font=font,
|
|
432
|
+
font_path=font_path,
|
|
433
|
+
font_style=FontStyle.REGULAR,
|
|
434
|
+
align=(Align.CENTER, Align.CENTER),
|
|
435
|
+
mode=Mode.PRIVATE,
|
|
436
|
+
)
|
|
437
|
+
centres = sorted(
|
|
438
|
+
((face.bounding_box().min.Y + face.bounding_box().max.Y) / 2.0 for face in probe.faces()),
|
|
439
|
+
reverse=True,
|
|
440
|
+
)
|
|
441
|
+
if len(centres) < 2: # pragma: no cover - defensive for a pathological font
|
|
442
|
+
return 1.3
|
|
443
|
+
return abs(centres[0] - centres[-1]) / font_size
|
|
444
|
+
|
|
445
|
+
|
|
392
446
|
def _text_width(text: str, font_size: float, font_path: str = PLEX_MONO) -> float:
|
|
393
447
|
"""Measured rendered width (page-mm) of *text* — see :func:`_text_size`."""
|
|
394
448
|
return _text_size(text, font_size, font_path)[0]
|
|
@@ -1207,16 +1261,25 @@ def _make_title_block(dwg, a: Analysis):
|
|
|
1207
1261
|
drawn-by cell bbox (for the hyperlink rect). Shared by :func:`_add_title_block` (which adds
|
|
1208
1262
|
it, last) and :func:`_title_block_box` (which measures its footprint for GD&T avoidance, #481)
|
|
1209
1263
|
so the two never drift."""
|
|
1264
|
+
title = _font_safe_text(a.title)
|
|
1265
|
+
number = _font_safe_text(a.number)
|
|
1266
|
+
tolerance = _font_safe_text(a.tolerance)
|
|
1267
|
+
designed_by = _font_safe_text(_attribution_author(a.drawn_by))
|
|
1268
|
+
material = _font_safe_text(a.material)
|
|
1269
|
+
date = _font_safe_text(a.date)
|
|
1270
|
+
revision = _font_safe_text(a.revision)
|
|
1271
|
+
legal_owner = _font_safe_text(a.company)
|
|
1272
|
+
scale = format_drawing_scale(a.SCALE)
|
|
1210
1273
|
tb = TitleBlock(
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
scale=
|
|
1214
|
-
general_tolerance=
|
|
1215
|
-
designed_by=
|
|
1216
|
-
material=
|
|
1217
|
-
date=
|
|
1218
|
-
revision=
|
|
1219
|
-
legal_owner=
|
|
1274
|
+
title,
|
|
1275
|
+
number,
|
|
1276
|
+
scale=scale,
|
|
1277
|
+
general_tolerance=tolerance,
|
|
1278
|
+
designed_by=designed_by,
|
|
1279
|
+
material=material,
|
|
1280
|
+
date=date,
|
|
1281
|
+
revision=revision,
|
|
1282
|
+
legal_owner=legal_owner,
|
|
1220
1283
|
width=a.TB_W,
|
|
1221
1284
|
# Title block renders in condensed sans (the tight ISO 7200 cells), a
|
|
1222
1285
|
# different face from the monospace dimensions — so it carries its own
|
|
@@ -1231,7 +1294,37 @@ def _make_title_block(dwg, a: Analysis):
|
|
|
1231
1294
|
# than hardcoded column fractions, so the hyperlink rect tracks any upstream
|
|
1232
1295
|
# TitleBlock layout change. Build-frame bbox; translated to page space below.
|
|
1233
1296
|
cell = tb.drawn_by_cell_bbox()
|
|
1234
|
-
|
|
1297
|
+
bx, by = a.PAGE_W - a.TB_W - _TB_CLEAR, _TB_CLEAR
|
|
1298
|
+
tb = tb.locate(Location((bx, by, 0)))
|
|
1299
|
+
|
|
1300
|
+
# Retain authoritative title-block values at their public cell centres for the PDF semantic
|
|
1301
|
+
# text layer. The visible block stays path-rendered; these specs merely let export embed the
|
|
1302
|
+
# same bundled condensed face as invisible selectable text without parsing SVG geometry.
|
|
1303
|
+
fields = (
|
|
1304
|
+
("title", title),
|
|
1305
|
+
("drawing_number", number),
|
|
1306
|
+
("scale", scale),
|
|
1307
|
+
("material", material),
|
|
1308
|
+
("revision", revision or date),
|
|
1309
|
+
("general_tolerance", tolerance),
|
|
1310
|
+
("designed_by", designed_by),
|
|
1311
|
+
("legal_owner", legal_owner),
|
|
1312
|
+
)
|
|
1313
|
+
specs = []
|
|
1314
|
+
for field, value in fields:
|
|
1315
|
+
if not value:
|
|
1316
|
+
continue
|
|
1317
|
+
box = tb.cell_bbox(field)
|
|
1318
|
+
specs.append(
|
|
1319
|
+
(
|
|
1320
|
+
value,
|
|
1321
|
+
bx + (box["min_x"] + box["max_x"]) / 2.0,
|
|
1322
|
+
by + (box["min_y"] + box["max_y"]) / 2.0,
|
|
1323
|
+
dwg.draft.font_size,
|
|
1324
|
+
PLEX_SANS_CONDENSED,
|
|
1325
|
+
)
|
|
1326
|
+
)
|
|
1327
|
+
tb.pdf_text_specs = tuple(specs)
|
|
1235
1328
|
return tb, cell
|
|
1236
1329
|
|
|
1237
1330
|
|
|
@@ -14,9 +14,10 @@ from __future__ import annotations
|
|
|
14
14
|
import logging
|
|
15
15
|
import math
|
|
16
16
|
from dataclasses import dataclass
|
|
17
|
+
from inspect import signature
|
|
17
18
|
|
|
18
19
|
from b123d_recognisers import full_cylinders
|
|
19
|
-
from build123d import Compound
|
|
20
|
+
from build123d import Compound, Shape
|
|
20
21
|
|
|
21
22
|
_log = logging.getLogger(__name__)
|
|
22
23
|
|
|
@@ -190,6 +191,23 @@ def _solids_body(part, src: str = "part"):
|
|
|
190
191
|
return body
|
|
191
192
|
|
|
192
193
|
|
|
194
|
+
_SCALE_SUPPORTS_ABOUT = "about" in signature(Shape.scale).parameters
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _scale_world(shape, factor: float):
|
|
198
|
+
"""Scale a build123d shape about the world origin on every supported version.
|
|
199
|
+
|
|
200
|
+
build123d 0.9/0.10's factor-only ``Shape.scale`` uses the world origin. Version 0.11 added
|
|
201
|
+
``about=`` and changed the default to ``shape.location.position``. Draftwright supports both
|
|
202
|
+
dependency lines, so select the signature once and state the same world-origin transform on
|
|
203
|
+
either API without converting analytic geometry through a general affine transform.
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
if _SCALE_SUPPORTS_ABOUT:
|
|
207
|
+
return shape.scale(factor, about=(0, 0, 0))
|
|
208
|
+
return shape.scale(factor)
|
|
209
|
+
|
|
210
|
+
|
|
193
211
|
def _axis_letter(obj) -> str:
|
|
194
212
|
"""Letter (``"x"``/``"y"``/``"z"``) of ``obj.axis``'s dominant component.
|
|
195
213
|
|
|
@@ -337,11 +355,18 @@ def _axis_direction_is_aligned(axis: str, direction, *, tol: float = 1e-3) -> bo
|
|
|
337
355
|
)
|
|
338
356
|
|
|
339
357
|
|
|
340
|
-
def _fmt(v: float) -> str:
|
|
358
|
+
def _fmt(v: float, decimals: int | None = None) -> str:
|
|
341
359
|
"""Format a float as integer string if whole, otherwise 1 dp. The one number
|
|
342
360
|
formatter the IR (:mod:`draftwright.model.ir`) and the drawing layers
|
|
343
361
|
(:mod:`draftwright._core`) share (#700 — the two copies had already begun to
|
|
344
|
-
drift on ``-0``).
|
|
362
|
+
drift on ``-0``).
|
|
363
|
+
|
|
364
|
+
``decimals`` is an explicit referential-dimension display policy (#1349). It preserves
|
|
365
|
+
trailing zeroes by design; ``None`` retains the established automatic formatting.
|
|
366
|
+
"""
|
|
367
|
+
if decimals is not None:
|
|
368
|
+
normalized = 0.0 if round(float(v), decimals) == 0 else float(v)
|
|
369
|
+
return f"{normalized:.{decimals}f}"
|
|
345
370
|
r = round(v)
|
|
346
371
|
return str(r) if abs(v - r) < 1e-6 else f"{v:.1f}"
|
|
347
372
|
|