draftwright 0.4.9__tar.gz → 0.4.10__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.9 → draftwright-0.4.10}/CHANGELOG.md +85 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/PKG-INFO +2 -2
- {draftwright-0.4.9 → draftwright-0.4.10}/docs/adr/README.md +1 -1
- {draftwright-0.4.9 → draftwright-0.4.10}/docs/reference/recogniser-capabilities.md +16 -7
- draftwright-0.4.10/docs/reference/sheet.md +71 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/pyproject.toml +2 -2
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/__init__.py +7 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/_core.py +49 -5
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/_geometry.py +121 -1
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/analysis.py +173 -3
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/annotations/from_model.py +234 -117
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/annotations/holes.py +6 -4
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/annotations/orchestrator.py +140 -5
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/annotations/sections.py +157 -86
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/builder.py +437 -51
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/compose.py +251 -45
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/drawing.py +69 -6
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/linting/hole_coverage.py +2 -2
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/linting/pmi_coverage.py +45 -3
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/linting/quality.py +8 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/model/__init__.py +5 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/model/compiled.py +64 -23
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/model/declare.py +114 -13
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/model/detect.py +55 -19
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/model/ir.py +37 -8
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/model/planner.py +293 -11
- draftwright-0.4.10/src/draftwright/model/pmi_lowering.py +276 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/recogniser_contract.py +83 -11
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/sheet.py +558 -27
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/sheet_emit.py +30 -4
- draftwright-0.4.10/src/draftwright/view_plan.py +710 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/refactor_golden/bracket_section.json +4 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/refactor_golden/centered_rebate.json +4 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/refactor_golden/chamfered.json +40 -36
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/refactor_golden/filleted.json +40 -36
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/refactor_golden/flange_dense.json +4 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/refactor_golden/grid_plate.json +9 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/refactor_golden/grooved_shaft.json +9 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/refactor_golden/hex_bar.json +4 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/refactor_golden/holed_slot.json +4 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/refactor_golden/pocketed.json +4 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/refactor_golden/prismatic_ladder.json +44 -40
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/refactor_golden/scattered_plate.json +9 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/refactor_golden/side_drilled.json +4 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/refactor_golden/turned_stepped.json +4 -0
- draftwright-0.4.10/tests/test_adr0018_arrangement_gate.py +383 -0
- draftwright-0.4.10/tests/test_adr0018_view_routing.py +115 -0
- draftwright-0.4.10/tests/test_adr0018_view_selection.py +566 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_audit_differential.py +7 -6
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_compiled_plan_boundary.py +7 -7
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_drawing_encapsulation.py +5 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_e2e_standards.py +37 -19
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_import_boundaries.py +13 -1
- draftwright-0.4.10/tests/test_issue_1116_ap242_hole_tolerance_lowering.py +395 -0
- draftwright-0.4.10/tests/test_issue_1130_view_planning_evidence.py +211 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1146_scale_completeness.py +46 -4
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1188_per_view_assignment.py +19 -11
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1240_iso_above_strip_visibility.py +14 -6
- draftwright-0.4.10/tests/test_issue_1254_turned_chamfers.py +159 -0
- draftwright-0.4.10/tests/test_issue_1260_view_constraints.py +462 -0
- draftwright-0.4.10/tests/test_issue_1276_turned_leader_targets.py +332 -0
- draftwright-0.4.10/tests/test_issue_1281_turned_fillets.py +113 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_798_silhouette_lint.py +10 -6
- draftwright-0.4.10/tests/test_issue_924_zero_length_shoulders.py +118 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_label_provenance.py +1 -1
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_make_drawing.py +57 -25
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_pitch_dim_footprint.py +36 -2
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_pmi.py +76 -32
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_recogniser_capabilities.py +124 -19
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_recognition_manifest.py +18 -21
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_recognition_result.py +9 -12
- draftwright-0.4.10/tests/test_refactor_golden.py +432 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_sheet_emit.py +8 -1
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_sheet_gdt.py +2 -1
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_sheet_identity_invariant.py +61 -7
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_sheet_notes.py +4 -2
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_strip_layout.py +28 -10
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_tolerances.py +34 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_two_repository_workflow.py +62 -0
- draftwright-0.4.10/tests/test_view_plan.py +572 -0
- draftwright-0.4.9/docs/reference/sheet.md +0 -35
- draftwright-0.4.9/tests/test_refactor_golden.py +0 -261
- {draftwright-0.4.9 → draftwright-0.4.10}/.gitignore +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/LICENSE +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/README.md +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/docs/research/1062-repeating-radial-profile-evidence.md +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/skills/SKILL.md +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/_pmi_part21.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/_warnings.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/annotate.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/annotations/__init__.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/annotations/_common.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/annotations/balloons.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/annotations/gears.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/annotations/leaders.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/audit.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/cli.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/evaluation/__init__.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/evaluation/step_analysis.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/export.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/fits.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/fonts/IBMPlexMono-Regular.ttf +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/fonts/IBMPlexSansCondensed-Regular.ttf +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/fonts/LICENSE-IBMPlexMono-OFL.txt +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/fonts/LICENSE-IBMPlexSansCondensed-OFL.txt +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/fonts/__init__.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/intents.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/layout.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/linting/__init__.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/linting/channel_coverage.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/linting/coverage.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/linting/evidence.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/linting/flat_coverage.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/linting/gear_coverage.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/linting/issues.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/linting/polygonal_stock_coverage.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/linting/profiled_bore_coverage.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/linting/slot_coverage.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/linting/structural.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/linting/suggest.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/make_drawing.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/model/callout.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/pmi.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/projection.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/py.typed +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/recognition/__init__.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/recognition_cache.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/registry.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/repair.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/src/draftwright/score.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/_kernel.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/_layout_sig.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/conftest.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/evaluation/README.md +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/evaluation/ambiguous-open-semicircle.step +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/evaluation/blind-hole.step +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/evaluation/corpus-v1.json +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/evaluation/plain-block.step +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/evaluation/topology-a.step +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/evaluation/topology-b.step +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/grm03_thumbwheel_drive_screw.step +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/if_step_flat_across_cylinder.step +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/issue_1058_wheel_rh.step +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/issue_909_basic_part_design_017_body.step +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/issue_915_case_study_2.step +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/nist_ctc_01_asme1_ap203.stp +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/nist_ctc_01_asme1_ap242.stp +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/nist_ctc_02_asme1_ap203.stp +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/nist_ctc_02_asme1_ap242.stp +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/nist_ctc_03_asme1_ap203.stp +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/nist_ctc_03_asme1_ap242.stp +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/nist_ctc_04_asme1_ap203.stp +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/nist_ctc_04_asme1_ap242.stp +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/nist_ctc_05_asme1_ap203.stp +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/nist_ctc_05_asme1_ap242.stp +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/fixtures/tuner_jig_blind_obround_pockets.step +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_add_dimension.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_agents_guide.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_api_docs.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_architecture_docs.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_balloon_ring_standoff.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_carve_free_position_callers.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_counting_calls.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_cross_repository_delivery_protocol.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_declare.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_declared_recognition_gate.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_dense_sheet_canary.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_deprecation_dates.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_detect_once.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_detect_registry.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_dimension_role_vocabulary.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_e2e_slice.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_export_dxf_curves.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_export_dxf_zoom.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_external_recognition_boundary.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_fillets_adjacency.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_fits.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_flat_completeness.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_flat_stock_identity.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_flat_stock_opposition.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_gdt_placement.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_grid_lattice_convention.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_iso_nts_caption_placement.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1000_envelope_reuse.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1058_wheel_profile.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1073_cross_body_patterns.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1082_polygonal_stock.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1086_declared_gears.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1142_hole_leader_labels.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1143_hole_completeness.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1144_transactional_hole_table.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1147_legibility_pair_aggregation.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1153_contradictory_dimensions.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1154_one_owner_per_measurement.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1166_cross_pass_feature_leaders.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1176_quality_fidelity.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1177_angular_dimensions.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1187_unroutable_leaders.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1190_section_decision.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1196_deterministic_view_names.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1202_observed_drawing_consumer.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1204_multiscale_view_issues.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1215_envelope_tolerance.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1215_no_approved_tolerance_is_dropped.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1216_callout_reservation_measures_ink.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1216_pairwise_across_scale_groups.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1217_claimed_representations.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1217_the_facility_is_shared.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1219_location_claims_its_own_axis.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_1229_ledger_member_keying.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_367_leader_ink.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_676_polygonal_boss.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_676_polygonal_boss_declare.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_740_leader_assignment.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_798_floor_cardinality.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_798_material_field.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_885_prismatic_coverage.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_909_sloped_profile.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_915_dense_case.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_916_pocket_leader.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_917_open_channel.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_955_height_contingency.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_issue_958_cross_solid_recognition.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_layout.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_layout_cleanliness.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_layout_hypothesis.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_layout_property.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_leader_footprint.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_lint_box_cache.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_lint_reconciliation.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_lint_structural.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_linting.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_location_vocabulary.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_note_verb.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_object_aspects.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_occupancy_boxes.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_parameter_id.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_part_model.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_pmi_datum_lowering.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_pmi_gtol_lowering.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_pmi_part21.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_pocket_pattern.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_pocket_pattern_recognition.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_principal_profile_classifier.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_private_test_attr_reads.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_private_test_imports.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_quality_components.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_recogniser_adoption.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_recogniser_contract.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_recognition.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_registry.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_render_seam.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_repack_geometry_seam.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_score.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_script_detail_parity.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_shared_box_memo.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_sheet_of.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_sheet_section.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_sheet_tables.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_slanted_blind_step.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_slot_completeness.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_slot_pattern.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_slot_pattern_recognition.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_soft_deprecation.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_solve_trace.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_step_analysis_evaluation.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_suppression_ledger.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_suppression_marks.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_turned_steps.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_witness_label_reconciliation.py +0 -0
- {draftwright-0.4.9 → draftwright-0.4.10}/tests/test_workflows.py +0 -0
|
@@ -1,5 +1,90 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.4.10 — 2026-08-22
|
|
4
|
+
|
|
5
|
+
**A view-set-aware planning and turned-edge-treatment patch.** Authored view constraints now
|
|
6
|
+
compile into an explicit resolved plan, automatic drawings fail closed when required content is
|
|
7
|
+
lost, AP242 hole tolerances reach their semantic feature owners, and the exact
|
|
8
|
+
`b123d-recognisers` 0.3.0 release supplies turned chamfer and fillet evidence through truthful
|
|
9
|
+
profile-view callouts.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `Sheet` can now author a complete or augmenting semantic view set with `authored_views()`,
|
|
14
|
+
`auto_views()`, `view()`, `section_view()`, `detail_view()`, and their `add_*` forms. Fluent
|
|
15
|
+
view handles declare relationships, alignment, scale, and whole-view pins without exposing
|
|
16
|
+
annotation coordinates; unsupported or infeasible constraints fail at their declaration
|
|
17
|
+
source instead of being silently relaxed. `sheet.view_constraints` exposes the immutable
|
|
18
|
+
request and `drawing.view_plan` the distinct resolved result (#1260).
|
|
19
|
+
- Drawings now retain their resolved view topology, per-view requirement coverage, and
|
|
20
|
+
arrangement decision as inspectable values. The engine can build and semantically compare
|
|
21
|
+
alternative arrangements and requested view sets while keeping projection and page placement
|
|
22
|
+
derived from the same plan (#1130).
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- Dimension planning is now aware of the selected principal view set. Requirements supported by
|
|
27
|
+
another planned view are re-homed before projection; an unsupported set raises one aggregated
|
|
28
|
+
`ViewPlanIncomplete` naming every unmet requirement rather than failing late or producing a
|
|
29
|
+
plausible-looking drawing with missing dimensions (#1259).
|
|
30
|
+
- Three sparse corpus drawings now use a `stacked-iso` arrangement and fit A4 instead of A3 at
|
|
31
|
+
the same scale, with identical annotations, labels, and build issues. An alternative may only
|
|
32
|
+
compact the scale already selected by the default arrangement and must survive a real compile
|
|
33
|
+
without semantic loss; otherwise the default is retained (#1130).
|
|
34
|
+
- Updated the exact `b123d-recognisers` production lock from 0.2.9 to 0.3.0.
|
|
35
|
+
The immutable PyPI wheel/sdist hashes and capability-manifest digest `6645def94cbabaca7b9676fdb029b02e467266d1f020ea536e903b7d86b52685` are
|
|
36
|
+
recorded in `.github/recogniser-release.json`; focused compatibility evidence and the
|
|
37
|
+
normal consumer gates run on the generated PR.
|
|
38
|
+
- Accepted the additive Chamfer and Fillet schema-2 recogniser contract alongside schema 1 for
|
|
39
|
+
the `b123d-recognisers` 0.3.0 cutover; all other record schemas remain fail-closed at version 1
|
|
40
|
+
(#1276).
|
|
41
|
+
|
|
42
|
+
- Updated the exact `b123d-recognisers` production lock from 0.2.6 to 0.2.9.
|
|
43
|
+
The immutable PyPI wheel/sdist hashes and capability-manifest digest `805876905d548fd0ef1301e2cf24427a86d34bc2e592b8d2d0cb43db94e1d3bd` are
|
|
44
|
+
recorded in `.github/recogniser-release.json`; focused compatibility evidence and the
|
|
45
|
+
normal consumer gates run on the generated PR. The aggregate now inventories chamfers and
|
|
46
|
+
fillets on turned parts, and the fixed coaxial-post slot regression retires its downstream
|
|
47
|
+
strict xfail.
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
|
|
51
|
+
- Automatic builds now apply the same required-outcome gate as explicit-scale builds. A settled
|
|
52
|
+
drawing that lost required placement outcomes records `plan_incomplete`, reports an
|
|
53
|
+
`incomplete` scale decision, preserves measurement/hole/source provenance, and fails lint
|
|
54
|
+
rather than presenting a diagnostic drawing as complete (#1250).
|
|
55
|
+
|
|
56
|
+
- Supported AP242 diameter tolerances now correlate with their canonical hole or pattern owner at
|
|
57
|
+
the completed IR boundary and round-trip through emitted `Sheet` declarations with source
|
|
58
|
+
provenance. Unmatched, ambiguous, conflicting, partial-pattern, and unsupported requirements
|
|
59
|
+
fail closed to provenance-preserving measured dimensions rather than being duplicated or lost
|
|
60
|
+
(#1116).
|
|
61
|
+
|
|
62
|
+
- A declared step shoulder coincident with its datum is now pruned before rendering instead of
|
|
63
|
+
sending identical endpoints to the border-dimension helper and raising `ValueError`. Valid
|
|
64
|
+
siblings remain, while the omission is recorded in `Drawing.suppressions()` and reported as
|
|
65
|
+
`step_position_coincident_with_datum` (#924).
|
|
66
|
+
|
|
67
|
+
- Turned chamfer and fillet leaders now read in a shaft profile view and land on their physical
|
|
68
|
+
edge-treatment sites instead of collapsing axial stations in the end view. Cylindrical
|
|
69
|
+
feature notes, knurl callouts, and surface finishes likewise derive a model-space surface
|
|
70
|
+
target rather than pointing at the shaft axis; all continue through the shared placement
|
|
71
|
+
solves, with X/Y/Z parity and declared Sheet round-trip (#1276).
|
|
72
|
+
|
|
73
|
+
- Toroidal fillets returned for turned parts by the shared recognition inventory now lower into
|
|
74
|
+
the existing one-feature-per-round IR and render through the common leader solve. Equal radii
|
|
75
|
+
share one `n× R` callout carrying every physical fillet's measurement provenance, and emitted
|
|
76
|
+
Sheet programs preserve the full inventory without rescanning geometry (#1281).
|
|
77
|
+
|
|
78
|
+
- Turned chamfers returned by the shared recognition inventory now lower into the same
|
|
79
|
+
one-feature-per-edge-treatment IR as prismatic chamfers. Equal specifications render as one
|
|
80
|
+
`n×` callout carrying every member's measurement provenance; different chamfer forms do not
|
|
81
|
+
collapse merely because their first legs match, and distinct tolerances split into truthful
|
|
82
|
+
requirements instead of being lost or applied to untoleranced siblings (#1254).
|
|
83
|
+
|
|
84
|
+
- Recogniser dependency automation now starts a fresh `Unreleased` section when the previous
|
|
85
|
+
Draftwright release has finalized the changelog, so a published recogniser can enter through
|
|
86
|
+
the documented immutable update workflow instead of failing before it opens a PR (#1279).
|
|
87
|
+
|
|
3
88
|
## v0.4.9 — 2026-08-21
|
|
4
89
|
|
|
5
90
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: draftwright
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.10
|
|
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
|
|
@@ -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.3.0
|
|
688
688
|
Requires-Dist: build123d-drafting-helpers>=0.14.1
|
|
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'
|
|
@@ -34,7 +34,7 @@ architecture** table; open retired or superseded records only for design history
|
|
|
34
34
|
| [0015](0015-part-drawing-compiler-as-built.md) | The part-drawing compiler, as built | Use one detected-or-declared feature IR and planner-fed dimension groups as the compiler waist. | Accepted; supersedes 0008 | `test_part_model.py`, `test_detect_once.py`, `test_import_boundaries.py` |
|
|
35
35
|
| [0016](0016-declared-dimensioning-intent.md) | Declared dimensioning intent: capture what to measure, let the engine place it | Declare which measurements matter as scale-independent intent routed through the planner and corridor solve; never hardcode dimension geometry. | Accepted; epic #867 complete; phase 6 landed (#940) | `test_compiled_plan_boundary.py`, `test_issue_1215_no_approved_tolerance_is_dropped.py`, `test_label_provenance.py`, `test_sheet_emit.py`, `test_add_dimension.py` |
|
|
36
36
|
| [0017](0017-recognition-inventory-correspondence-and-measurement-provenance.md) | One recognition result per run; correspondence is evidence-gated | Produce one external immutable recognition result held by Draftwright's per-run cache; require vertical-slice evidence before generalising correspondence, identity, requirements, outcomes, or reconciliation. | Accepted; external cache ownership clarified, extensions gated by #1018 | `test_external_recognition_boundary.py`, `test_recognition_manifest.py`, `test_declared_recognition_gate.py` |
|
|
37
|
-
| [0018](0018-requirement-driven-view-planning-and-editable-sheet-layout.md) | Requirement-driven view planning and editable sheet layout | Use one `ViewSpec` vocabulary and planner with distinct authored `ViewConstraints` and immutable `ResolvedViewPlan`; jointly validate views, typography, convention, scale, paper and layout against requirement survival. Supersedes ADR 0004's fixed-topology assumption while retaining compose-then-pack. | Accepted 2026-08-16
|
|
37
|
+
| [0018](0018-requirement-driven-view-planning-and-editable-sheet-layout.md) | Requirement-driven view planning and editable sheet layout | Use one `ViewSpec` vocabulary and planner with distinct authored `ViewConstraints` and immutable `ResolvedViewPlan`; jointly validate views, typography, convention, scale, paper and layout against requirement survival. Supersedes ADR 0004's fixed-topology assumption while retaining compose-then-pack. | Accepted 2026-08-16; partially implemented (`ViewSpec`, `ResolvedViewPlan`, `ViewCoverage`, arrangement choice and requirement gate); tracked by #1130/#1259-#1262 | Required guards are listed in the ADR |
|
|
38
38
|
| [0019](0019-display-complete-labels-and-dimension-outcomes.md) | Display-complete labels and a dimension-outcome ledger | The compiled plan carries the full label text (tolerance and collapse wording included) so renderers render and never compose; dimension outcomes reconcile at one seam on both build routes; ladder rungs get per-mark identity. Finishes the ADR 0016 Amdt 1 boundary; supersedes Amdt 6's enforcement mechanism. | Proposed | `test_issue_1215_no_approved_tolerance_is_dropped.py` reduces to plan-equality when implemented |
|
|
39
39
|
|
|
40
40
|
## Historical records
|
|
@@ -26,7 +26,9 @@ Validation fails closed and names the family and boundary whenever possible:
|
|
|
26
26
|
CI instead — adoption is still required, and is enforced where the decision is made. Provide the
|
|
27
27
|
downstream behavior or an explicit non-supported state as before.
|
|
28
28
|
- **record schema mismatch** — a consumed record schema changed. Review the record fields and
|
|
29
|
-
compatibility notes, update the relevant adapter and tests, then
|
|
29
|
+
compatibility notes, update the relevant adapter and tests, then explicitly list the accepted
|
|
30
|
+
schema version. A bounded dual-readable list may name the current and next additive schemas
|
|
31
|
+
during a provider-first release; it is never an open-ended range.
|
|
30
32
|
- **stale implementation** — a declared adapter, `Sheet` method, emitter, renderer, or completeness
|
|
31
33
|
function no longer resolves. Repair the implementation reference and its independent behavior
|
|
32
34
|
evidence; do not merely rename the string.
|
|
@@ -47,12 +49,19 @@ Validation fails closed and names the family and boundary whenever possible:
|
|
|
47
49
|
|
|
48
50
|
## Adding or changing a recogniser
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
For an additive field that increments an existing record schema, first land a narrow Draftwright
|
|
53
|
+
declaration accepting both the installed schema and the named candidate schema. The existing adapter
|
|
54
|
+
must remain valid when the new field is ignored, and tests must prove the next schema is accepted
|
|
55
|
+
only by that explicit declaration while later schemas still fail. The package canary then proves
|
|
56
|
+
the real candidate wheel against that committed consumer point. After the package release, the
|
|
57
|
+
Draftwright dependency/behavior PR locks the immutable artifact, adopts the field, and narrows the
|
|
58
|
+
declaration to the new schema.
|
|
59
|
+
|
|
60
|
+
For each applicable stage, add the adapter, declaration, emitted-Sheet round trip, drawing behavior,
|
|
61
|
+
and completeness evidence; for an inapplicable or deferred stage, state why and link its tracking
|
|
62
|
+
issue. The contract test derives package record outputs, converter registries, live `Sheet` methods,
|
|
63
|
+
and emitter branches independently, so copying a new name into the declaration alone cannot make CI
|
|
64
|
+
pass.
|
|
56
65
|
|
|
57
66
|
`bosses` is the fully consumed reference family. `repeating-radial-profiles` is the opposite
|
|
58
67
|
reference: it remains geometry-only critique evidence for a separately authored gear declaration,
|
|
@@ -0,0 +1,71 @@
|
|
|
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
|
+
## View handle
|
|
44
|
+
|
|
45
|
+
::: draftwright.sheet._View
|
|
46
|
+
options:
|
|
47
|
+
filters: public
|
|
48
|
+
|
|
49
|
+
## Hole handle
|
|
50
|
+
|
|
51
|
+
::: draftwright.sheet._Hole
|
|
52
|
+
options:
|
|
53
|
+
filters: public
|
|
54
|
+
|
|
55
|
+
## Diameter and step handle
|
|
56
|
+
|
|
57
|
+
::: draftwright.sheet._Dim
|
|
58
|
+
options:
|
|
59
|
+
filters: public
|
|
60
|
+
|
|
61
|
+
## Multi-parameter handle
|
|
62
|
+
|
|
63
|
+
::: draftwright.sheet._Params
|
|
64
|
+
options:
|
|
65
|
+
filters: public
|
|
66
|
+
|
|
67
|
+
## GD&T control builder
|
|
68
|
+
|
|
69
|
+
::: draftwright.sheet._Control
|
|
70
|
+
options:
|
|
71
|
+
filters: public
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "draftwright"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.10"
|
|
8
8
|
description = "Automated technical-drawing generation for build123d"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -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.1",
|
|
21
|
-
"b123d-recognisers==0.
|
|
21
|
+
"b123d-recognisers==0.3.0",
|
|
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
|
|
@@ -36,6 +36,9 @@ _LAZY = {
|
|
|
36
36
|
"extract_pmi": "draftwright.pmi",
|
|
37
37
|
"extract_pmi_report": "draftwright.pmi",
|
|
38
38
|
"choose_scale": "draftwright.compose",
|
|
39
|
+
"ViewPlanIncomplete": "draftwright.view_plan",
|
|
40
|
+
"ViewConstraints": "draftwright.view_plan",
|
|
41
|
+
"ViewSpec": "draftwright.view_plan",
|
|
39
42
|
# A warning category users are told to filter must be importable without reaching into a
|
|
40
43
|
# private module (#1043 review) — and without paying for the CAD kernel. It lives in the
|
|
41
44
|
# dependency-free `_warnings` leaf for that second reason: defined in `_core` it cost ~6 s
|
|
@@ -91,6 +94,7 @@ if TYPE_CHECKING: # static analysers / IDEs — no runtime import, no kernel co
|
|
|
91
94
|
extract_pmi_report,
|
|
92
95
|
)
|
|
93
96
|
from draftwright.sheet import Sheet
|
|
97
|
+
from draftwright.view_plan import ViewConstraints, ViewPlanIncomplete, ViewSpec
|
|
94
98
|
|
|
95
99
|
|
|
96
100
|
def __dir__():
|
|
@@ -110,6 +114,9 @@ __all__ = [
|
|
|
110
114
|
"Sheet",
|
|
111
115
|
"ScaleIncompatibilityError",
|
|
112
116
|
"ScaleCompletenessWarning",
|
|
117
|
+
"ViewPlanIncomplete",
|
|
118
|
+
"ViewConstraints",
|
|
119
|
+
"ViewSpec",
|
|
113
120
|
"build_drawing",
|
|
114
121
|
"choose_scale",
|
|
115
122
|
"extract_pmi",
|
|
@@ -42,7 +42,14 @@ from build123d_drafting.helpers import (
|
|
|
42
42
|
# now live in the leaf `draftwright._geometry` so the IR waist (`model/`) can use them
|
|
43
43
|
# without importing this stage-level grab-bag (ADR 0008; #584 WP2). Re-exported here for
|
|
44
44
|
# the above-`_core` consumers (annotations/sheet/drawing/linting) that already import them.
|
|
45
|
-
from draftwright._geometry import
|
|
45
|
+
from draftwright._geometry import ( # noqa: F401
|
|
46
|
+
_EDGE_ON,
|
|
47
|
+
_END_ON,
|
|
48
|
+
HoleRef,
|
|
49
|
+
_axis_letter,
|
|
50
|
+
_fmt,
|
|
51
|
+
_xyz,
|
|
52
|
+
)
|
|
46
53
|
from draftwright.fits import FitClass
|
|
47
54
|
from draftwright.fonts import PLEX_MONO, PLEX_SANS_CONDENSED
|
|
48
55
|
from draftwright.layout import _greedy_strip_1d, _solve_strip_1d
|
|
@@ -804,8 +811,8 @@ class DetailRequest:
|
|
|
804
811
|
footprint that depends on the chosen scale (the prismatic
|
|
805
812
|
ladder reserves one rung per *legible-at-that-scale* step, so it
|
|
806
813
|
shrinks with the scale during the fit). Overrides ``pad_top``.
|
|
807
|
-
source_view: orthographic direction to preserve in the detail (``"front"
|
|
808
|
-
or ``"side"``).
|
|
814
|
+
source_view: orthographic direction to preserve in the detail (``"front"``,
|
|
815
|
+
``"plan"`` or ``"side"``).
|
|
809
816
|
crop_lo/crop_hi: optional crop bounds along ``axis`` when the projected
|
|
810
817
|
detail must include context outside the marked feature band.
|
|
811
818
|
Prismatic absolute-height details use this to retain their
|
|
@@ -823,13 +830,23 @@ class DetailRequest:
|
|
|
823
830
|
redraw: Callable[..., int]
|
|
824
831
|
pad_top: float = 0.0
|
|
825
832
|
pads: Callable[[float], tuple[float, float]] | None = None
|
|
826
|
-
source_view: Literal["front", "side"] = "front"
|
|
833
|
+
source_view: Literal["front", "plan", "side"] = "front"
|
|
827
834
|
crop_lo: float | None = None
|
|
828
835
|
crop_hi: float | None = None
|
|
829
836
|
cross_axis: Literal["x", "y", "z"] | None = None
|
|
830
837
|
cross_lo: float | None = None
|
|
831
838
|
cross_hi: float | None = None
|
|
832
839
|
kind: str = "detail"
|
|
840
|
+
#: Authored detail identity/label. ``None`` lets the automatic resolver assign A-H.
|
|
841
|
+
view_name: str | None = None
|
|
842
|
+
label: str | None = None
|
|
843
|
+
#: Exact authored multiple of sheet scale; automatic requests keep ``None`` and use the
|
|
844
|
+
#: legibility-derived preferred series.
|
|
845
|
+
scale_factor: float | None = None
|
|
846
|
+
#: An authored orientation crop is defining geometry even when it carries no redrawn
|
|
847
|
+
#: dimension. Automatic recovery details retain the historical "no dimension, no view" gate.
|
|
848
|
+
keep_without_annotations: bool = False
|
|
849
|
+
source: object | None = None
|
|
833
850
|
|
|
834
851
|
|
|
835
852
|
@dataclass(frozen=True)
|
|
@@ -1021,7 +1038,7 @@ class Analysis:
|
|
|
1021
1038
|
step_zs: list[float]
|
|
1022
1039
|
layout_strips: StripDepths
|
|
1023
1040
|
layout_n_steps: int
|
|
1024
|
-
layout_section:
|
|
1041
|
+
layout_section: int
|
|
1025
1042
|
layout_table_sizes: tuple[tuple[float, float], ...]
|
|
1026
1043
|
layout_required_tables: tuple[tuple[tuple[float, float], str], ...]
|
|
1027
1044
|
sv_right: float
|
|
@@ -1090,6 +1107,28 @@ class Analysis:
|
|
|
1090
1107
|
# declared a model (ADR 0011) or on a manually-built Analysis — consumers fall
|
|
1091
1108
|
# back to build_model(a).
|
|
1092
1109
|
model: object | None = None
|
|
1110
|
+
#: The relational arrangement the sheet was composed under — ADR 0018 §5's fourth
|
|
1111
|
+
#: dimension, decided once by `compose.choose_scale` and carried here so that placement
|
|
1112
|
+
#: and the repack loop compose under the arrangement whose feasibility was actually
|
|
1113
|
+
#: established. They call `_layout_geometry` with MEASURED strip depths where selection
|
|
1114
|
+
#: passed estimates, so a stage that re-derives this instead of reading it can reach a
|
|
1115
|
+
#: different answer for the same sheet and lose dimensions to the mismatch (#1130).
|
|
1116
|
+
#: Defaulted for hand-built `Analysis` objects, which mean the long-standing arrangement.
|
|
1117
|
+
arrangement: str = "columns"
|
|
1118
|
+
#: The principal views this sheet carries, or None for the third-angle three (ADR 0018).
|
|
1119
|
+
#: Decided once alongside scale/page/arrangement and carried, for the same reason: the
|
|
1120
|
+
#: layout must reserve space for exactly the views the builder creates, or dropping one
|
|
1121
|
+
#: costs its annotations without reclaiming its paper.
|
|
1122
|
+
planned_views: tuple[str, ...] | None = None
|
|
1123
|
+
#: Whether the orientation isometric participates in this authored plan. It is separate
|
|
1124
|
+
#: from ``planned_views`` because that tuple is the principal set consumed by the
|
|
1125
|
+
#: requirement compiler.
|
|
1126
|
+
planned_iso: bool = True
|
|
1127
|
+
#: ``None`` lets the orientation iso auto-fit; a number is an authored exact factor.
|
|
1128
|
+
planned_iso_scale: float | None = None
|
|
1129
|
+
#: Immutable ADR 0018 authored input, retained for the resolver/diagnostics without making
|
|
1130
|
+
#: this low-level module depend on the view-planning leaf at runtime.
|
|
1131
|
+
view_constraints: object | None = None
|
|
1093
1132
|
|
|
1094
1133
|
@property
|
|
1095
1134
|
def pmi(self) -> list:
|
|
@@ -1276,6 +1315,11 @@ def _add_zone_grid(dwg, a: Analysis):
|
|
|
1276
1315
|
|
|
1277
1316
|
def _iso_bbox(dwg):
|
|
1278
1317
|
"""(min_x, min_y, max_x, max_y) of the placed iso view, hidden lines included."""
|
|
1318
|
+
if "iso" not in dwg.views:
|
|
1319
|
+
# A deliberately omitted orientation view contributes no obstacle. Infinity makes
|
|
1320
|
+
# every existing iso-clearance comparison a no-op without teaching annotation passes
|
|
1321
|
+
# a second page-edge convention.
|
|
1322
|
+
return (math.inf, math.inf, math.inf, math.inf)
|
|
1279
1323
|
return dwg.view_bounds("iso")
|
|
1280
1324
|
|
|
1281
1325
|
|
|
@@ -15,13 +15,133 @@ import logging
|
|
|
15
15
|
import math
|
|
16
16
|
from dataclasses import dataclass
|
|
17
17
|
|
|
18
|
+
from b123d_recognisers import full_cylinders
|
|
18
19
|
from build123d import Compound
|
|
19
20
|
|
|
20
21
|
_log = logging.getLogger(__name__)
|
|
21
22
|
|
|
22
|
-
# Axis letter -> the orthographic view a feature on that axis reads end-on in
|
|
23
|
+
# Axis letter -> the orthographic view a feature on that axis reads end-on in: a z-hole is
|
|
24
|
+
# a circle in plan, an x-channel is a cross-section in side.
|
|
25
|
+
#
|
|
26
|
+
# The ONE owner of that routing. It was duplicated as a bare literal at eight sites across
|
|
27
|
+
# six modules, which is ADR 0018's own sentence about itself — "which views should exist is
|
|
28
|
+
# a decision nothing currently owns" — in miniature: a mapping copied eight times cannot be
|
|
29
|
+
# taught that a view is absent, and the engine's answer to a missing view was a `KeyError`
|
|
30
|
+
# raised inside a centermark pass. Route through this, never re-spell it (#1130).
|
|
23
31
|
_END_ON = {"x": "side", "y": "front", "z": "plan"}
|
|
24
32
|
|
|
33
|
+
# Axis letter -> the orthographic view a planar face with that NORMAL shows as an edge in
|
|
34
|
+
# (prefer front, else side). The companion routing to `_END_ON`, and its second owner: this
|
|
35
|
+
# one was spelled out three times — the groove profile callouts, `declare._EDGE_ON_VIEW` and
|
|
36
|
+
# `planner._PROFILE`, the last of which documented the duplication in a comment rather than
|
|
37
|
+
# resolving it. Same reasoning as above: route through it, never re-spell it (#1130).
|
|
38
|
+
_EDGE_ON = {"x": "front", "y": "side", "z": "front"}
|
|
39
|
+
|
|
40
|
+
# Model axes retained by each orthographic projection. Besides documenting the projection
|
|
41
|
+
# convention once, this lets surface-bound annotations choose a radial direction that the
|
|
42
|
+
# requested view can actually show (#1276).
|
|
43
|
+
_VIEW_AXES = {"plan": ("x", "y"), "front": ("x", "z"), "side": ("y", "z")}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _radial_axis_in_view(axis: str, view: str) -> str:
|
|
47
|
+
"""Return a principal radial axis visible in *view* for a shaft along *axis*.
|
|
48
|
+
|
|
49
|
+
Profile views contain the shaft axis and exactly one radial axis. A caller may also
|
|
50
|
+
explicitly choose the face-on view, where both projected axes are radial; the first is a
|
|
51
|
+
deterministic, equally physical surface direction.
|
|
52
|
+
"""
|
|
53
|
+
try:
|
|
54
|
+
return next(candidate for candidate in _VIEW_AXES[view] if candidate != axis)
|
|
55
|
+
except (KeyError, StopIteration) as e:
|
|
56
|
+
raise ValueError(f"no radial axis for shaft axis {axis!r} in view {view!r}") from e
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _canonical_profile_site(site, centre, axis: str, view: str) -> tuple[float, float, float]:
|
|
60
|
+
"""Rotate a turned surface *site* about its shaft onto the selected profile plane.
|
|
61
|
+
|
|
62
|
+
Conical and toroidal recognisers may return any circumferential point on the same physical
|
|
63
|
+
edge treatment. Orthographic projection can discard that point's sole radial component
|
|
64
|
+
(notably an X-offset site viewed in the Y-Z side view). Preserve its axial station and
|
|
65
|
+
radial distance while rotating it to the radial axis visible in *view*.
|
|
66
|
+
"""
|
|
67
|
+
values = [float(value) for value in site]
|
|
68
|
+
centre_values = [float(value) for value in centre]
|
|
69
|
+
axis_i = "xyz".index(axis)
|
|
70
|
+
radial = [i for i in (0, 1, 2) if i != axis_i]
|
|
71
|
+
visible_i = "xyz".index(_radial_axis_in_view(axis, view))
|
|
72
|
+
if visible_i not in radial:
|
|
73
|
+
raise ValueError(f"view {view!r} is not a profile view of axis {axis!r}")
|
|
74
|
+
hidden_i = next(i for i in radial if i != visible_i)
|
|
75
|
+
visible_delta = values[visible_i] - centre_values[visible_i]
|
|
76
|
+
hidden_delta = values[hidden_i] - centre_values[hidden_i]
|
|
77
|
+
radius = math.hypot(visible_delta, hidden_delta)
|
|
78
|
+
direction = visible_delta if abs(visible_delta) > 1e-12 else hidden_delta
|
|
79
|
+
values[visible_i] = centre_values[visible_i] + math.copysign(radius, direction or 1.0)
|
|
80
|
+
values[hidden_i] = centre_values[hidden_i]
|
|
81
|
+
return (values[0], values[1], values[2])
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _turned_profile_site(site, axis: str, view: str, cylinders) -> tuple[float, float, float]:
|
|
85
|
+
"""Return *site* rotated onto *view* about its nearest external shaft axis.
|
|
86
|
+
|
|
87
|
+
A part may contain several parallel shafts, so the part bounding-box centre is not an
|
|
88
|
+
axis. Rank the shared cylinder substrate by the site's distance from each finite cylinder
|
|
89
|
+
patch (radial surface gap plus axial-span gap), then rotate about that cylinder's own
|
|
90
|
+
``axis_xyz``. The finite span matters for compounds: an unrelated cylinder at a remote
|
|
91
|
+
axial station can coincidentally have the exact radial distance (#1276 review).
|
|
92
|
+
When no matching external cylinder exists, preserve the physical site: inventing an axis
|
|
93
|
+
would be worse than retaining a possibly edge-on circumferential anchor.
|
|
94
|
+
"""
|
|
95
|
+
values = (float(site[0]), float(site[1]), float(site[2]))
|
|
96
|
+
axis_i = "xyz".index(axis)
|
|
97
|
+
radial = tuple(i for i in (0, 1, 2) if i != axis_i)
|
|
98
|
+
candidates = []
|
|
99
|
+
# ``analyse_cylinders`` is deliberately a complete face inventory: longitudinal blends
|
|
100
|
+
# and slot caps are cylindrical too. Only its public substrate filter proves which
|
|
101
|
+
# records collectively describe a shaft, including an OD split by a keyway/slot.
|
|
102
|
+
substrates = (full_cylinders(list(group)) for group in cylinders)
|
|
103
|
+
for cylinder in (item for group in substrates for item in group):
|
|
104
|
+
if not cylinder.get("external") or cylinder.get("axis") != axis:
|
|
105
|
+
continue
|
|
106
|
+
centre = tuple(float(value) for value in cylinder["axis_xyz"])
|
|
107
|
+
radial_distance = math.hypot(
|
|
108
|
+
values[radial[0]] - centre[radial[0]],
|
|
109
|
+
values[radial[1]] - centre[radial[1]],
|
|
110
|
+
)
|
|
111
|
+
surface_gap = abs(radial_distance - float(cylinder["diameter"]) / 2)
|
|
112
|
+
direction = tuple(float(value) for value in cylinder["dir_xyz"])
|
|
113
|
+
axial_station = sum(value * component for value, component in zip(values, direction))
|
|
114
|
+
s_lo = float(cylinder["s_lo"])
|
|
115
|
+
s_hi = float(cylinder["s_hi"])
|
|
116
|
+
axial_gap = max(s_lo - axial_station, 0.0, axial_station - s_hi)
|
|
117
|
+
patch_distance = math.hypot(surface_gap, axial_gap)
|
|
118
|
+
# A complete cylinder elsewhere in a compound is not evidence for this feature. If
|
|
119
|
+
# the recogniser's physical point is more than one radius from the finite patch, keep
|
|
120
|
+
# that point rather than rotating it around an invented remote axis. This also keeps
|
|
121
|
+
# a chamfer on a partial OD (for example a D-shaft) safe when ``full_cylinders`` quite
|
|
122
|
+
# correctly declines to call the partial wall a complete shaft substrate.
|
|
123
|
+
radius = float(cylinder["diameter"]) / 2
|
|
124
|
+
if patch_distance > radius:
|
|
125
|
+
continue
|
|
126
|
+
candidates.append(
|
|
127
|
+
(
|
|
128
|
+
(
|
|
129
|
+
patch_distance,
|
|
130
|
+
axial_gap,
|
|
131
|
+
surface_gap,
|
|
132
|
+
radial_distance,
|
|
133
|
+
int(cylinder["solid_idx"]),
|
|
134
|
+
centre[radial[0]],
|
|
135
|
+
centre[radial[1]],
|
|
136
|
+
),
|
|
137
|
+
centre,
|
|
138
|
+
)
|
|
139
|
+
)
|
|
140
|
+
if not candidates:
|
|
141
|
+
return values
|
|
142
|
+
_score, centre = min(candidates, key=lambda candidate: candidate[0])
|
|
143
|
+
return _canonical_profile_site(values, centre, axis, view)
|
|
144
|
+
|
|
25
145
|
|
|
26
146
|
def _xyz(loc) -> tuple[float, float, float]:
|
|
27
147
|
"""A build123d ``Vector`` (has ``.X/.Y/.Z``) or an ``(x, y, z)`` sequence → an
|