draftwright 0.4.22__tar.gz → 0.4.24__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.
Files changed (562) hide show
  1. {draftwright-0.4.22 → draftwright-0.4.24}/CHANGELOG.md +4 -0
  2. {draftwright-0.4.22 → draftwright-0.4.24}/PKG-INFO +4 -2
  3. {draftwright-0.4.22 → draftwright-0.4.24}/docs/reference/recogniser-capabilities.md +2 -2
  4. {draftwright-0.4.22 → draftwright-0.4.24}/docs/reference/sheet.md +86 -0
  5. {draftwright-0.4.22 → draftwright-0.4.24}/pyproject.toml +7 -11
  6. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/_geometry.py +24 -0
  7. draftwright-0.4.24/src/draftwright/angular_geometry.py +146 -0
  8. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/annotations/_common.py +99 -11
  9. draftwright-0.4.24/src/draftwright/annotations/angular.py +136 -0
  10. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/annotations/from_model.py +401 -137
  11. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/annotations/orchestrator.py +24 -5
  12. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/annotations/sections.py +25 -40
  13. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/builder.py +32 -22
  14. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/compose.py +135 -14
  15. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/drawing.py +124 -5
  16. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/inspection_contract.py +36 -1
  17. draftwright-0.4.24/src/draftwright/linting/angular.py +553 -0
  18. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/coverage.py +7 -4
  19. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/evidence.py +37 -0
  20. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/quality.py +14 -0
  21. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/requirements.py +10 -0
  22. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/structural.py +32 -14
  23. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/suggest.py +15 -4
  24. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/model/__init__.py +10 -0
  25. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/model/compiled.py +227 -11
  26. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/model/declare.py +61 -2
  27. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/model/detect.py +46 -0
  28. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/model/ir.py +211 -1
  29. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/model/planner.py +162 -30
  30. draftwright-0.4.24/src/draftwright/profile_angles.py +310 -0
  31. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/recognition_ownership.py +58 -0
  32. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/registry.py +8 -0
  33. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/reporting.py +77 -5
  34. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/sheet.py +45 -2
  35. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/sheet_emit.py +42 -7
  36. {draftwright-0.4.22 → draftwright-0.4.24}/tests/refactor_golden/grooved_shaft.json +128 -68
  37. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_add_dimension.py +9 -0
  38. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_compiled_plan_boundary.py +1 -0
  39. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_declared_recognition_gate.py +2 -3
  40. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_import_boundaries.py +3 -0
  41. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_inspection_contract.py +21 -1
  42. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1143_hole_completeness.py +1 -0
  43. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1144_transactional_hole_table.py +23 -0
  44. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1176_quality_fidelity.py +3 -3
  45. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1177_angular_dimensions.py +15 -7
  46. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1215_no_approved_tolerance_is_dropped.py +7 -2
  47. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1299_page_escalation.py +5 -4
  48. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1334_prevent_ink.py +26 -1
  49. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1372_groove_completeness_evidence.py +6 -6
  50. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1374_turned_step_completeness_evidence.py +6 -3
  51. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1438_report_projection.py +6 -8
  52. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1460_step_inspection.py +3 -0
  53. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1466_semantic_sides.py +7 -0
  54. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1485_curved_pockets.py +4 -3
  55. draftwright-0.4.24/tests/test_issue_1504_angle_patterns.py +219 -0
  56. draftwright-0.4.24/tests/test_issue_1504_angular_references.py +130 -0
  57. draftwright-0.4.24/tests/test_issue_1504_angular_rendering.py +322 -0
  58. draftwright-0.4.24/tests/test_issue_1504_canonical_angles.py +763 -0
  59. draftwright-0.4.24/tests/test_issue_1504_profile_angles.py +185 -0
  60. draftwright-0.4.24/tests/test_issue_1505_diameter_coverage.py +156 -0
  61. draftwright-0.4.24/tests/test_issue_1505_short_axial_chains.py +303 -0
  62. draftwright-0.4.24/tests/test_issue_1511_turned_boss_heights.py +340 -0
  63. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_740_leader_assignment.py +7 -1
  64. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_909_sloped_profile.py +43 -2
  65. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_955_height_contingency.py +14 -2
  66. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_make_drawing.py +75 -36
  67. draftwright-0.4.24/tests/test_overall_height_coverage.py +199 -0
  68. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_parameter_id.py +12 -0
  69. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_private_test_attr_reads.py +1 -0
  70. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_recogniser_capabilities.py +1 -1
  71. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_refactor_golden.py +5 -0
  72. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_registry.py +16 -0
  73. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_render_seam.py +27 -20
  74. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_sheet_emit.py +46 -15
  75. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_sheet_identity_invariant.py +2 -0
  76. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_tolerances.py +17 -0
  77. {draftwright-0.4.22 → draftwright-0.4.24}/.gitignore +0 -0
  78. {draftwright-0.4.22 → draftwright-0.4.24}/LICENSE +0 -0
  79. {draftwright-0.4.22 → draftwright-0.4.24}/README.md +0 -0
  80. {draftwright-0.4.22 → draftwright-0.4.24}/docs/adr/README.md +0 -0
  81. {draftwright-0.4.22 → draftwright-0.4.24}/docs/research/1062-repeating-radial-profile-evidence.md +0 -0
  82. {draftwright-0.4.22 → draftwright-0.4.24}/skills/SKILL.md +0 -0
  83. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/__init__.py +0 -0
  84. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/_build_profile.py +0 -0
  85. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/_core.py +0 -0
  86. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/_pmi_part21.py +0 -0
  87. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/_warnings.py +0 -0
  88. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/analysis.py +0 -0
  89. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/annotate.py +0 -0
  90. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/annotations/__init__.py +0 -0
  91. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/annotations/balloons.py +0 -0
  92. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/annotations/gears.py +0 -0
  93. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/annotations/holes.py +0 -0
  94. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/annotations/leaders.py +0 -0
  95. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/audit.py +0 -0
  96. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/blend_contract.py +0 -0
  97. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/cli.py +0 -0
  98. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/evaluation/__init__.py +0 -0
  99. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/evaluation/step_analysis.py +0 -0
  100. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/export.py +0 -0
  101. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/feature_identity.py +0 -0
  102. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/fits.py +0 -0
  103. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/fonts/IBMPlexMono-Regular.ttf +0 -0
  104. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/fonts/IBMPlexSansCondensed-Regular.ttf +0 -0
  105. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/fonts/LICENSE-IBMPlexMono-OFL.txt +0 -0
  106. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/fonts/LICENSE-IBMPlexSansCondensed-OFL.txt +0 -0
  107. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/fonts/__init__.py +0 -0
  108. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/inspection.py +0 -0
  109. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/intents.py +0 -0
  110. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/layout.py +0 -0
  111. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/__init__.py +0 -0
  112. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/_registry.py +0 -0
  113. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/angled_step_coverage.py +0 -0
  114. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/blend_coverage.py +0 -0
  115. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/chamfer_coverage.py +0 -0
  116. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/channel_coverage.py +0 -0
  117. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/circular_blind_step_coverage.py +0 -0
  118. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/fillet_coverage.py +0 -0
  119. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/flat_coverage.py +0 -0
  120. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/gear_coverage.py +0 -0
  121. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/groove_coverage.py +0 -0
  122. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/hole_coverage.py +0 -0
  123. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/ink_overlap.py +0 -0
  124. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/issues.py +0 -0
  125. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/oriented_slot_coverage.py +0 -0
  126. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/pad_coverage.py +0 -0
  127. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/paired_ramp_step_coverage.py +0 -0
  128. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/passage_coverage.py +0 -0
  129. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/plate_coverage.py +0 -0
  130. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/pmi_coverage.py +0 -0
  131. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/pocket_coverage.py +0 -0
  132. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/pocket_pattern_coverage.py +0 -0
  133. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/polygonal_boss_coverage.py +0 -0
  134. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/polygonal_stock_coverage.py +0 -0
  135. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/prismatic_pocket_coverage.py +0 -0
  136. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/profiled_bore_coverage.py +0 -0
  137. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/rectangular_blind_slot_coverage.py +0 -0
  138. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/round_bottom_blind_slot_coverage.py +0 -0
  139. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/section_recess_coverage.py +0 -0
  140. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/slot_coverage.py +0 -0
  141. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/through_step_coverage.py +0 -0
  142. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/linting/turned_step_coverage.py +0 -0
  143. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/make_drawing.py +0 -0
  144. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/model/callout.py +0 -0
  145. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/model/pmi_lowering.py +0 -0
  146. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/oriented_slot_contract.py +0 -0
  147. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/plate_correspondence.py +0 -0
  148. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/pmi.py +0 -0
  149. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/projection.py +0 -0
  150. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/py.typed +0 -0
  151. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/recogniser_contract.py +0 -0
  152. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/recogniser_policy.py +0 -0
  153. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/recogniser_schema.py +0 -0
  154. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/recognition/__init__.py +0 -0
  155. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/recognition_cache.py +0 -0
  156. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/recognition_frame.py +0 -0
  157. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/repair.py +0 -0
  158. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/score.py +0 -0
  159. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/section_recess_contract.py +0 -0
  160. {draftwright-0.4.22 → draftwright-0.4.24}/src/draftwright/view_plan.py +0 -0
  161. {draftwright-0.4.22 → draftwright-0.4.24}/tests/_evidence_contract.py +0 -0
  162. {draftwright-0.4.22 → draftwright-0.4.24}/tests/_kernel.py +0 -0
  163. {draftwright-0.4.22 → draftwright-0.4.24}/tests/_layout_sig.py +0 -0
  164. {draftwright-0.4.22 → draftwright-0.4.24}/tests/_mutation_corpus.py +0 -0
  165. {draftwright-0.4.22 → draftwright-0.4.24}/tests/_recogniser_public_contract.py +0 -0
  166. {draftwright-0.4.22 → draftwright-0.4.24}/tests/_section_recess_cases.py +0 -0
  167. {draftwright-0.4.22 → draftwright-0.4.24}/tests/conftest.py +0 -0
  168. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/ap242_single_cylinder_diameter.step +0 -0
  169. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/README.md +0 -0
  170. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/ambiguous-open-semicircle.step +0 -0
  171. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/blind-hole.step +0 -0
  172. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/chamfer-asymmetric.step +0 -0
  173. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/chamfer-compound.step +0 -0
  174. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/chamfer-overlap.step +0 -0
  175. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/chamfer-plain.step +0 -0
  176. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/chamfer-planar-x.step +0 -0
  177. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/chamfer-planar-y.step +0 -0
  178. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/chamfer-planar-z.step +0 -0
  179. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/chamfer-topology-a.step +0 -0
  180. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/chamfer-topology-b.step +0 -0
  181. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/chamfer-turned.step +0 -0
  182. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/corpus-chamfers-v1.json +0 -0
  183. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/corpus-countersinks-v1.json +0 -0
  184. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/corpus-double-d-bores-v1.json +0 -0
  185. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/corpus-fillets-v1.json +0 -0
  186. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/corpus-flats-v1.json +0 -0
  187. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/corpus-grooves-v1.json +0 -0
  188. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/corpus-hole-patterns-v1.json +0 -0
  189. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/corpus-plates-v1.json +0 -0
  190. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/corpus-pocket-patterns-v1.json +0 -0
  191. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/corpus-pockets-v1.json +0 -0
  192. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/corpus-polygonal-bosses-v1.json +0 -0
  193. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/corpus-polygonal-stock-v1.json +0 -0
  194. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/corpus-rectangular-pads-v1.json +0 -0
  195. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/corpus-turned-steps-v1.json +0 -0
  196. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/corpus-v1.json +0 -0
  197. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/countersink-deburr.step +0 -0
  198. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/countersink-external-cone.step +0 -0
  199. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/countersink-mixed-pair.step +0 -0
  200. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/countersink-single.step +0 -0
  201. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/countersink-topology-a.step +0 -0
  202. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/countersink-topology-b.step +0 -0
  203. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/double-d-axis-x.step +0 -0
  204. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/double-d-axis-y.step +0 -0
  205. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/double-d-blind.step +0 -0
  206. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/double-d-coaxial-compound.step +0 -0
  207. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/double-d-opposed-blind.step +0 -0
  208. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/double-d-roll-30.step +0 -0
  209. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/double-d-round-bore.step +0 -0
  210. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/double-d-single-z.step +0 -0
  211. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/double-d-topology-a.step +0 -0
  212. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/double-d-topology-b.step +0 -0
  213. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/fillet-compound.step +0 -0
  214. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/fillet-overlap.step +0 -0
  215. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/fillet-plain.step +0 -0
  216. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/fillet-planar-x.step +0 -0
  217. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/fillet-planar-y.step +0 -0
  218. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/fillet-planar-z.step +0 -0
  219. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/fillet-repeated.step +0 -0
  220. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/fillet-topology-a.step +0 -0
  221. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/fillet-topology-b.step +0 -0
  222. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/fillet-turned.step +0 -0
  223. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/flat-coaxial.step +0 -0
  224. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/flat-double-d.step +0 -0
  225. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/flat-lone-d.step +0 -0
  226. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/flat-nonround.step +0 -0
  227. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/flat-slanted-double-d.step +0 -0
  228. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/flat-topology-a.step +0 -0
  229. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/flat-topology-b.step +0 -0
  230. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/groove-compound.step +0 -0
  231. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/groove-lone-x.step +0 -0
  232. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/groove-lone-y.step +0 -0
  233. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/groove-lone-z.step +0 -0
  234. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/groove-monotonic-negative.step +0 -0
  235. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/groove-narrow.step +0 -0
  236. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/groove-topology-a.step +0 -0
  237. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/groove-topology-b.step +0 -0
  238. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pad-compound-equal.step +0 -0
  239. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pad-detached-body-negative.step +0 -0
  240. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pad-full-span-ledge-negative.step +0 -0
  241. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pad-nested-staircase-negative.step +0 -0
  242. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pad-topology-a.step +0 -0
  243. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pad-topology-b.step +0 -0
  244. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pad-x-negative.step +0 -0
  245. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pad-x-positive.step +0 -0
  246. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pad-y-negative.step +0 -0
  247. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pad-y-positive.step +0 -0
  248. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pad-z-negative.step +0 -0
  249. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pad-z-positive.step +0 -0
  250. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pattern-ambiguous.step +0 -0
  251. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pattern-grid.step +0 -0
  252. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pattern-topology-a.step +0 -0
  253. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pattern-topology-b.step +0 -0
  254. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/plain-block.step +0 -0
  255. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/plate-compound-equal.step +0 -0
  256. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/plate-cross-topology-a.step +0 -0
  257. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/plate-cross-topology-b.step +0 -0
  258. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/plate-detached-negative.step +0 -0
  259. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/plate-rotational-negative.step +0 -0
  260. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/plate-single-negative.step +0 -0
  261. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/plate-t-xz.step +0 -0
  262. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/plate-t-yz.step +0 -0
  263. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/plate-thick-negative.step +0 -0
  264. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/plate-u-additive.step +0 -0
  265. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/plate-u-cut.step +0 -0
  266. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pocket-compound.step +0 -0
  267. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pocket-edge-anchored.step +0 -0
  268. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pocket-lone.step +0 -0
  269. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pocket-opposed.step +0 -0
  270. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pocket-pattern-ambiguous.step +0 -0
  271. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pocket-pattern-grid.step +0 -0
  272. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pocket-pattern-linear.step +0 -0
  273. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pocket-pattern-pair.step +0 -0
  274. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pocket-pattern-topology-a.step +0 -0
  275. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pocket-pattern-topology-b.step +0 -0
  276. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pocket-prismatic-negative.step +0 -0
  277. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pocket-side.step +0 -0
  278. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pocket-through-negative.step +0 -0
  279. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pocket-topology-a.step +0 -0
  280. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pocket-topology-b.step +0 -0
  281. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/pocket-two-equal.step +0 -0
  282. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-boss-compound-equal.step +0 -0
  283. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-boss-detached-negative.step +0 -0
  284. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-boss-in-plane-rotated.step +0 -0
  285. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-boss-other-protrusions-negative.step +0 -0
  286. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-boss-recess-negative.step +0 -0
  287. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-boss-stock-negative.step +0 -0
  288. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-boss-topology-a.step +0 -0
  289. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-boss-topology-b.step +0 -0
  290. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-boss-x.step +0 -0
  291. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-boss-y.step +0 -0
  292. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-boss-z.step +0 -0
  293. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-stock-compound-negative.step +0 -0
  294. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-stock-cylinder-negative.step +0 -0
  295. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-stock-irregular-negative.step +0 -0
  296. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-stock-octagon-negative.step +0 -0
  297. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-stock-recess-negative.step +0 -0
  298. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-stock-roll17.step +0 -0
  299. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-stock-topology-a.step +0 -0
  300. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-stock-topology-b.step +0 -0
  301. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-stock-translated.step +0 -0
  302. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-stock-x.step +0 -0
  303. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/polygonal-stock-y.step +0 -0
  304. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/topology-a.step +0 -0
  305. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/topology-b.step +0 -0
  306. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/turned-step-axis-x.step +0 -0
  307. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/turned-step-axis-y.step +0 -0
  308. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/turned-step-axis-z.step +0 -0
  309. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/turned-step-compound.step +0 -0
  310. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/turned-step-repeated-lengths.step +0 -0
  311. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/turned-step-through-bore.step +0 -0
  312. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/turned-step-topology-a.step +0 -0
  313. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/turned-step-topology-b.step +0 -0
  314. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/evaluation/turned-step-translated-blind-bore.step +0 -0
  315. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/grm03_thumbwheel_drive_screw.step +0 -0
  316. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/grm03_thumbwheel_drive_screw_ap242_pmi.step +0 -0
  317. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/grm04_drive_plate.step +0 -0
  318. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/if_step_flat_across_cylinder.step +0 -0
  319. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/issue_1058_wheel_rh.step +0 -0
  320. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/issue_1247_angled_blind_step.step +0 -0
  321. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/issue_909_basic_part_design_017_body.step +0 -0
  322. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/issue_915_case_study_2.step +0 -0
  323. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/nist_ctc_01_asme1_ap203.stp +0 -0
  324. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/nist_ctc_01_asme1_ap242.stp +0 -0
  325. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/nist_ctc_02_asme1_ap203.stp +0 -0
  326. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/nist_ctc_02_asme1_ap242.stp +0 -0
  327. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/nist_ctc_03_asme1_ap203.stp +0 -0
  328. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/nist_ctc_03_asme1_ap242.stp +0 -0
  329. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/nist_ctc_04_asme1_ap203.stp +0 -0
  330. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/nist_ctc_04_asme1_ap242.stp +0 -0
  331. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/nist_ctc_05_asme1_ap203.stp +0 -0
  332. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/nist_ctc_05_asme1_ap242.stp +0 -0
  333. {draftwright-0.4.22 → draftwright-0.4.24}/tests/fixtures/tuner_jig_blind_obround_pockets.step +0 -0
  334. {draftwright-0.4.22 → draftwright-0.4.24}/tests/refactor_golden/bracket_section.json +0 -0
  335. {draftwright-0.4.22 → draftwright-0.4.24}/tests/refactor_golden/centered_rebate.json +0 -0
  336. {draftwright-0.4.22 → draftwright-0.4.24}/tests/refactor_golden/chamfered.json +0 -0
  337. {draftwright-0.4.22 → draftwright-0.4.24}/tests/refactor_golden/filleted.json +0 -0
  338. {draftwright-0.4.22 → draftwright-0.4.24}/tests/refactor_golden/flange_dense.json +0 -0
  339. {draftwright-0.4.22 → draftwright-0.4.24}/tests/refactor_golden/grid_plate.json +0 -0
  340. {draftwright-0.4.22 → draftwright-0.4.24}/tests/refactor_golden/hex_bar.json +0 -0
  341. {draftwright-0.4.22 → draftwright-0.4.24}/tests/refactor_golden/holed_slot.json +0 -0
  342. {draftwright-0.4.22 → draftwright-0.4.24}/tests/refactor_golden/pocketed.json +0 -0
  343. {draftwright-0.4.22 → draftwright-0.4.24}/tests/refactor_golden/prismatic_ladder.json +0 -0
  344. {draftwright-0.4.22 → draftwright-0.4.24}/tests/refactor_golden/scattered_plate.json +0 -0
  345. {draftwright-0.4.22 → draftwright-0.4.24}/tests/refactor_golden/side_drilled.json +0 -0
  346. {draftwright-0.4.22 → draftwright-0.4.24}/tests/refactor_golden/turned_stepped.json +0 -0
  347. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_adr0018_arrangement_gate.py +0 -0
  348. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_adr0018_view_routing.py +0 -0
  349. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_adr0018_view_selection.py +0 -0
  350. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_adr_corpus.py +0 -0
  351. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_agents_guide.py +0 -0
  352. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_api_docs.py +0 -0
  353. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_architecture_docs.py +0 -0
  354. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_audit_differential.py +0 -0
  355. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_balloon_ring_standoff.py +0 -0
  356. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_build_profile_harness.py +0 -0
  357. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_carve_free_position_callers.py +0 -0
  358. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_clone_budget.py +0 -0
  359. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_counting_calls.py +0 -0
  360. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_declare.py +0 -0
  361. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_dense_sheet_canary.py +0 -0
  362. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_deprecation_dates.py +0 -0
  363. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_detect_once.py +0 -0
  364. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_detect_registry.py +0 -0
  365. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_dimension_role_vocabulary.py +0 -0
  366. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_drawing_encapsulation.py +0 -0
  367. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_e2e_slice.py +0 -0
  368. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_e2e_standards.py +0 -0
  369. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_export_dxf_curves.py +0 -0
  370. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_export_dxf_zoom.py +0 -0
  371. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_export_reproducible.py +0 -0
  372. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_external_recognition_boundary.py +0 -0
  373. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_fillets_adjacency.py +0 -0
  374. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_fits.py +0 -0
  375. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_flat_completeness.py +0 -0
  376. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_flat_stock_identity.py +0 -0
  377. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_flat_stock_opposition.py +0 -0
  378. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_gdt_placement.py +0 -0
  379. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_geometry_graph_spike.py +0 -0
  380. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_grid_lattice_convention.py +0 -0
  381. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_iso_nts_caption_placement.py +0 -0
  382. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1000_envelope_reuse.py +0 -0
  383. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1006_measurement_comparison.py +0 -0
  384. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1058_wheel_profile.py +0 -0
  385. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1073_cross_body_patterns.py +0 -0
  386. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1082_polygonal_stock.py +0 -0
  387. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1086_declared_gears.py +0 -0
  388. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1116_ap242_hole_tolerance_lowering.py +0 -0
  389. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1130_view_planning_evidence.py +0 -0
  390. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1142_hole_leader_labels.py +0 -0
  391. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1146_scale_completeness.py +0 -0
  392. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1147_legibility_pair_aggregation.py +0 -0
  393. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1153_contradictory_dimensions.py +0 -0
  394. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1154_one_owner_per_measurement.py +0 -0
  395. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1155_grm04_sheet_use.py +0 -0
  396. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1166_cross_pass_feature_leaders.py +0 -0
  397. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1187_unroutable_leaders.py +0 -0
  398. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1188_per_view_assignment.py +0 -0
  399. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1190_section_decision.py +0 -0
  400. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1196_deterministic_view_names.py +0 -0
  401. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1202_observed_drawing_consumer.py +0 -0
  402. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1204_multiscale_view_issues.py +0 -0
  403. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1209_linear_pmi_witnesses.py +0 -0
  404. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1215_envelope_tolerance.py +0 -0
  405. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1216_callout_reservation_measures_ink.py +0 -0
  406. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1216_pairwise_across_scale_groups.py +0 -0
  407. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1217_claimed_representations.py +0 -0
  408. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1217_the_facility_is_shared.py +0 -0
  409. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1219_location_claims_its_own_axis.py +0 -0
  410. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1229_ledger_member_keying.py +0 -0
  411. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1240_iso_above_strip_visibility.py +0 -0
  412. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1245_passage_disposition.py +0 -0
  413. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1246_prismatic_pocket_disposition.py +0 -0
  414. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1247_angled_step_disposition.py +0 -0
  415. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1254_turned_chamfers.py +0 -0
  416. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1260_view_constraints.py +0 -0
  417. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1262_automatic_turned_views.py +0 -0
  418. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1276_turned_leader_targets.py +0 -0
  419. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1281_turned_fillets.py +0 -0
  420. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1296_cylindrical_diameter_pmi.py +0 -0
  421. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1298_manufacturing_requirements.py +0 -0
  422. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1308_machined_leader_analytics.py +0 -0
  423. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1312_engine_costs.py +0 -0
  424. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1325_nominal_agreement.py +0 -0
  425. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1332_overlap_remedy.py +0 -0
  426. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1332_zone_labels.py +0 -0
  427. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1333_bounded_ink_repair.py +0 -0
  428. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1336_grm03_ap242_pmi_fixture.py +0 -0
  429. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1338_scale_before_page_escalation.py +0 -0
  430. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1349_precision_display.py +0 -0
  431. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1350_detected_takeover.py +0 -0
  432. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1351_structured_note_coverage.py +0 -0
  433. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1352_searchable_pdf_text.py +0 -0
  434. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1353_cnc_authoritative_workflow.py +0 -0
  435. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1357_framed_activation.py +0 -0
  436. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1357_framed_boundary.py +0 -0
  437. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1357_plural_turned_profiles.py +0 -0
  438. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1357_pmi_frame.py +0 -0
  439. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1360_thread_depth.py +0 -0
  440. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1369_hole_completeness_evidence.py +0 -0
  441. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1370_countersink_completeness_evidence.py +0 -0
  442. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1370_double_d_completeness_evidence.py +0 -0
  443. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1370_hole_pattern_completeness_evidence.py +0 -0
  444. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1371_flat_completeness_evidence.py +0 -0
  445. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1371_polygonal_stock_completeness_evidence.py +0 -0
  446. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1372_pad_completeness_evidence.py +0 -0
  447. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1372_pocket_completeness_evidence.py +0 -0
  448. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1372_pocket_pattern_completeness_evidence.py +0 -0
  449. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1372_polygonal_boss_completeness_evidence.py +0 -0
  450. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1373_plate_completeness_evidence.py +0 -0
  451. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1374_chamfer_completeness_evidence.py +0 -0
  452. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1374_fillet_completeness_evidence.py +0 -0
  453. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1378_diameter_leader_targets.py +0 -0
  454. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1382_046_step_inventory.py +0 -0
  455. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1382_circular_blind_step_semantics.py +0 -0
  456. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1382_framed_step_family_evidence.py +0 -0
  457. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1382_paired_ramp_semantics.py +0 -0
  458. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1382_through_step_semantics.py +0 -0
  459. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1390_sheet_registration.py +0 -0
  460. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1392_recognisers_048.py +0 -0
  461. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1395_degenerate_iso_region.py +0 -0
  462. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1396_layout_advisories.py +0 -0
  463. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1397_unverifiable_requirement_message.py +0 -0
  464. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1421_rectangular_blind_slot_completeness.py +0 -0
  465. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1421_rectangular_blind_slot_semantics.py +0 -0
  466. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1421_round_bottom_blind_slot_completeness.py +0 -0
  467. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1421_round_bottom_blind_slot_semantics.py +0 -0
  468. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1432_adoption.py +0 -0
  469. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1432_boundary_failures.py +0 -0
  470. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1432_oriented_slot_semantics.py +0 -0
  471. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1433_blend_semantics.py +0 -0
  472. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1438_boss_ownership.py +0 -0
  473. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1438_channel_ownership.py +0 -0
  474. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1438_cli_report_sidecar.py +0 -0
  475. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1438_generation_snapshot.py +0 -0
  476. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1438_nested_ownership.py +0 -0
  477. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1438_occurrence_ownership.py +0 -0
  478. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1438_pattern_ownership.py +0 -0
  479. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1438_plate_ownership.py +0 -0
  480. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1438_policy_dispositions.py +0 -0
  481. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1438_report_writer.py +0 -0
  482. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1438_through_step_ownership.py +0 -0
  483. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1438_turned_step_ownership.py +0 -0
  484. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1450_boss_blend_ownership.py +0 -0
  485. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1466_dimension_options.py +0 -0
  486. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1471_boundary_failures.py +0 -0
  487. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1471_evidence_schema.py +0 -0
  488. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1471_groove_profile.py +0 -0
  489. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1471_section_recess_contract.py +0 -0
  490. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1471_section_recess_pockets.py +0 -0
  491. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1479_radius_leader_targets.py +0 -0
  492. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1485_quiddity_024_boundary.py +0 -0
  493. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_1485_rounded_pockets.py +0 -0
  494. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_367_leader_ink.py +0 -0
  495. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_443_grm03_axial_coverage.py +0 -0
  496. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_563_placement_intent.py +0 -0
  497. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_676_polygonal_boss.py +0 -0
  498. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_676_polygonal_boss_declare.py +0 -0
  499. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_798_floor_cardinality.py +0 -0
  500. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_798_material_field.py +0 -0
  501. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_798_silhouette_lint.py +0 -0
  502. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_827_real_part_canary.py +0 -0
  503. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_883_location_identity.py +0 -0
  504. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_885_prismatic_coverage.py +0 -0
  505. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_915_dense_case.py +0 -0
  506. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_916_pocket_leader.py +0 -0
  507. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_917_open_channel.py +0 -0
  508. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_924_zero_length_shoulders.py +0 -0
  509. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_issue_958_cross_solid_recognition.py +0 -0
  510. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_label_provenance.py +0 -0
  511. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_layout.py +0 -0
  512. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_layout_cleanliness.py +0 -0
  513. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_layout_hypothesis.py +0 -0
  514. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_layout_property.py +0 -0
  515. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_leader_footprint.py +0 -0
  516. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_lint_box_cache.py +0 -0
  517. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_lint_ink_overlap.py +0 -0
  518. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_lint_reconciliation.py +0 -0
  519. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_lint_structural.py +0 -0
  520. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_linting.py +0 -0
  521. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_location_vocabulary.py +0 -0
  522. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_note_verb.py +0 -0
  523. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_object_aspects.py +0 -0
  524. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_occupancy_boxes.py +0 -0
  525. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_part_model.py +0 -0
  526. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_pitch_dim_footprint.py +0 -0
  527. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_pmi.py +0 -0
  528. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_pmi_datum_lowering.py +0 -0
  529. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_pmi_gtol_lowering.py +0 -0
  530. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_pmi_part21.py +0 -0
  531. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_pocket_pattern.py +0 -0
  532. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_pocket_pattern_recognition.py +0 -0
  533. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_principal_profile_classifier.py +0 -0
  534. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_private_test_imports.py +0 -0
  535. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_quality_components.py +0 -0
  536. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_recogniser_adoption.py +0 -0
  537. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_recogniser_contract.py +0 -0
  538. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_recognition_result.py +0 -0
  539. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_repack_geometry_seam.py +0 -0
  540. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_score.py +0 -0
  541. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_script_detail_parity.py +0 -0
  542. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_shared_box_memo.py +0 -0
  543. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_sheet_gdt.py +0 -0
  544. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_sheet_notes.py +0 -0
  545. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_sheet_of.py +0 -0
  546. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_sheet_section.py +0 -0
  547. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_sheet_tables.py +0 -0
  548. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_slanted_blind_step.py +0 -0
  549. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_slot_completeness.py +0 -0
  550. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_slot_pattern.py +0 -0
  551. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_slot_pattern_recognition.py +0 -0
  552. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_soft_deprecation.py +0 -0
  553. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_solve_trace.py +0 -0
  554. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_step_analysis_evaluation.py +0 -0
  555. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_strip_layout.py +0 -0
  556. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_suppression_ledger.py +0 -0
  557. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_suppression_marks.py +0 -0
  558. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_turned_steps.py +0 -0
  559. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_version_bump_ci.py +0 -0
  560. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_view_plan.py +0 -0
  561. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_witness_label_reconciliation.py +0 -0
  562. {draftwright-0.4.22 → draftwright-0.4.24}/tests/test_workflows.py +0 -0
@@ -478,6 +478,10 @@
478
478
 
479
479
  ### Fixed
480
480
 
481
+ - Overall height and envelope width remain dimensioned when approved turned-step lengths
482
+ cover only part of the respective extent. Redundancy suppression now requires adjoining
483
+ measurements on one profile to reach both overall endpoints; STC618 retains its missing
484
+ 62 mm height (#1509).
481
485
  - Non-1:1 orthographic and isometric projection now scales extracted solids about the world
482
486
  origin, matching the view-coordinate mapper and solver zones. Solids carrying a non-zero
483
487
  build123d `Location` no longer shift their silhouette away from dimensions and callouts.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: draftwright
3
- Version: 0.4.22
3
+ Version: 0.4.24
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
@@ -687,10 +687,12 @@ Requires-Dist: antlr4-python3-runtime<4.10
687
687
  Requires-Dist: build123d-drafting-helpers>=0.14.2
688
688
  Requires-Dist: build123d<0.11,>=0.9.0; python_full_version < '3.13'
689
689
  Requires-Dist: build123d<0.12,>=0.11; python_full_version >= '3.13'
690
+ Requires-Dist: cadquery-ocp-novtk!=7.9.3.1.1; python_full_version >= '3.13'
690
691
  Requires-Dist: numpy>=1.24
692
+ Requires-Dist: ocp-gordon<0.3
691
693
  Requires-Dist: pillow>=10
692
694
  Requires-Dist: pypdfium2>=4
693
- Requires-Dist: quiddity==0.2.5
695
+ Requires-Dist: quiddity==0.2.6
694
696
  Requires-Dist: reportlab>=4.0
695
697
  Requires-Dist: steputils==0.1
696
698
  Requires-Dist: svglib>=1.5
@@ -70,9 +70,9 @@ issue. The contract test derives package record outputs, converter registries, l
70
70
  and emitter branches independently, so copying a new name into the declaration alone cannot make CI
71
71
  pass.
72
72
 
73
- ### Quiddity 0.2.5 runtime contract
73
+ ### Quiddity 0.2.6 runtime contract
74
74
 
75
- The runtime pins the published `quiddity==0.2.5` package, following the 0.2.4 adoption in
75
+ The runtime pins the published `quiddity==0.2.6` package, following the 0.2.4 adoption in
76
76
  [#1486](https://github.com/pzfreo/draftwright/pull/1486) and the migration in
77
77
  [#1471](https://github.com/pzfreo/draftwright/issues/1471). Its public `quiddity`, `quiddity.evidence` and
78
78
  `quiddity.inspection` surfaces supply recognition, exact occurrence evidence and declared geometry
@@ -67,6 +67,86 @@ build. Build and lint still assess the resulting Sheet. A
67
67
  query never replaces an existing dimension request. Keep the original feature handle for edits;
68
68
  these reports do not introduce persistent feature identities or new lane, route or pin controls.
69
69
 
70
+ ## Angular measurements
71
+
72
+ `Sheet.angle()` derives an included angle from a vertex and two witness points
73
+ in model coordinates. Select its canonical `included.angle` measurement with
74
+ `dimension()`. The engine chooses a true-angle principal view and places the arc,
75
+ arrows and complete compiler-owned label through the shared corridor solver.
76
+
77
+ ```python
78
+ from math import sqrt
79
+ from build123d import Polygon, extrude
80
+ from draftwright import Sheet
81
+
82
+ part = extrude(Polygon((0, 0), (30, 0), (15, 15 * sqrt(3)), align=None), amount=3)
83
+ sheet = Sheet(part).authored_dimensions()
84
+ angle = sheet.angle(
85
+ vertex=(0, 0, 3), first=(15, 0, 3), second=(7.5, 7.5 * sqrt(3), 3),
86
+ )
87
+ angle.tolerance(0.05, on="included.angle")
88
+ sheet.dimension(angle, "included.angle")
89
+ drawing = sheet.build()
90
+ for finding in drawing.lint():
91
+ print(finding.code, finding.message)
92
+ ```
93
+
94
+ The default `sector="minor"` is the non-reflex angle towards the two witness
95
+ points. `sector="opposite"` selects the vertically opposite sector, extending
96
+ both supports through the vertex. It preserves the numerical angle and can keep
97
+ an exterior dimension beside its corner. The engine never silently switches
98
+ between these sectors or substitutes a supplementary angle.
99
+ Reversing witness order preserves the selected angle. For extended supports meeting beyond
100
+ a rounded corner, use `virtual_vertex=True`; this declares the virtual
101
+ intersection without asserting that the vertex lies on a physical edge.
102
+ Zero-length or collinear rays, oblique planes and unsupported sectors are
103
+ rejected. Insufficient page space produces `angular_dimension_dropped` against
104
+ the named measurement. Symmetric tolerances and lower/upper deviation magnitudes
105
+ retain degree units, including small deviations when the nominal display is
106
+ coarse. Omitting the dimension request suppresses the angle; generated scripts
107
+ retain its reference geometry and tolerances.
108
+
109
+ After building, `drawing.dimension(feature, "included.angle", pin=True, priority=2)`
110
+ uses the shared corridor in live and deferred edits. As with other edits, use an
111
+ exact feature from `drawing.model()`. Measurement comparison records the angular
112
+ references, so equal-valued support substitutions cannot appear preserved merely
113
+ because the labels match.
114
+
115
+ `Sheet.angle_pattern(*references)` declares repeated coplanar corners using
116
+ `AngularReference` values from `draftwright.model`. Each corner remains independently
117
+ addressable as `included.angle.member1`, `included.angle.member2`, and so on, in
118
+ declaration order. Request every member with `dimension()` to permit one quantity
119
+ label such as `3× 60°`. Different member tolerances or side preferences produce
120
+ individual labels; omitting one member suppresses that measurement without renumbering
121
+ the others. The generated script retains the full member geometry and each request.
122
+
123
+ After the conservative strip solve, curved dimensions have up to three
124
+ corner-local radius alternatives at the existing tier spacing. The shared
125
+ placement stage accepts a shorter radius or recovers a dropped candidate only
126
+ when its actual lines and label clear fixed and same-batch ink and fit the page.
127
+ Pinned dimensions retain their solved position.
128
+
129
+ The lower-level `measured_dimension(kind="angular", ...)` route retains nominal
130
+ author-supplied text. Its explicit `AngularReference` supplies the same ray
131
+ geometry; plain Sheet-authored three-point `ref_pts` use `(first, vertex, second)`.
132
+ Imported PMI requires explicit ordering. Structured tolerances on that raw route
133
+ remain unsupported; use the canonical declaration for new authored angles.
134
+ Lint compares degree values at their displayed resolution, inspects the visible
135
+ angular ink and checks complete canonical labels against the compiler. Physical
136
+ critique checks each claimed corner against finite supports in the cached provider
137
+ evidence, including members represented by a quantity label. Unprovable correspondence
138
+ produces `angular_support_unverifiable`; contradictory supports produce
139
+ `angular_support_mismatch`.
140
+
141
+ Automatic drawings derive outside-profile angular requirements from ordered face
142
+ supports in Quiddity 0.2.6. Angles already defined by a recognised chamfer or
143
+ regular-polygon callout do not add duplicate automatic requirements. This requires
144
+ the same run's exact face or shared-edge evidence, not matching numerical angles;
145
+ explicit angle declarations remain available on those corners.
146
+ Verified profile repetitions can share a quantity label;
147
+ equal numerical angles alone do not establish a pattern. The requirement audit retains
148
+ one outcome per physical corner even when several share one mark.
149
+
70
150
  ## Selecting a hole location component
71
151
 
72
152
  Use `location` alone to request the usual location set. To select one component of a hole
@@ -171,6 +251,12 @@ omission suppresses a view. `add_view(...)`, `add_section_view(...)` and
171
251
  `column(...)` are shorthand for whole-view relations. A principal-view handle's `pin((x, y))`
172
252
  anchors its projection origin in page millimetres; it never positions an annotation.
173
253
 
254
+ A detail around a turned step with an approved `step.length` uses a profile view
255
+ and redraws that length through the shared dimension pass. For example,
256
+ `s.detail_view("A", around=shoulder).scale(3)` retains its measurement identity and
257
+ tolerance at three times the sheet scale. Omitted measurements stay omitted. An
258
+ authored recovery detail that cannot place its dimension raises an error.
259
+
174
260
  Principal orthographic views share the sheet scale and reject `.scale(...)`. Detail and
175
261
  isometric handles may carry an independent positive factor. Infeasible relations, scales and
176
262
  pins raise with their declaration source; unsupported pins on derived or pictorial views are
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "draftwright"
7
- version = "0.4.22"
7
+ version = "0.4.24"
8
8
  description = "Automated technical-drawing generation for build123d"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -17,8 +17,13 @@ dependencies = [
17
17
  # 3.13+. Mirrors pzfreo/build123d-mcp's dependency handling.
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
+ # Supported build123d releases use OCP 7.x; ocp_gordon 0.3 requires OCP 8.x.
21
+ "ocp_gordon<0.3",
22
+ # This novtk release lacks OCP.GccEnt on macOS. The exclusion must reach
23
+ # published wheels, not only uv's development resolver constraints.
24
+ "cadquery-ocp-novtk!=7.9.3.1.1 ; python_full_version >= '3.13'",
20
25
  "build123d-drafting-helpers>=0.14.2",
21
- "quiddity==0.2.5",
26
+ "quiddity==0.2.6",
22
27
  "numpy>=1.24",
23
28
  # PNG raster export (SVG→PDF→PNG). Both permissively licensed (Pillow HPND; pypdfium2
24
29
  # Apache-2.0 wrapping Google PDFium BSD-3) and ship pre-built wheels with NO native system
@@ -187,12 +192,3 @@ skip = "*.stp,*.step,*.svg,*.dxf,*.pdf,uv.lock,.git,*.ttf,*.otf,src/draftwright/
187
192
  # `nd` a Dijkstra distance var, `tread` a real word (stair-tread faces), `accreting`
188
193
  # a real word, `testof` the `TestOf` class name, and the valid hyphenated re-* forms.
189
194
  ignore-words-list = "nd,tread,accreting,testof,re-using,re-declare,re-declared,re-declaring"
190
-
191
- [tool.uv]
192
- # On Python 3.13/3.14, build123d resolves to 0.11, whose OCP kernel is
193
- # cadquery-ocp-novtk (VTK dropped from the transitive tree — fine here, draftwright
194
- # renders headless and never imports VTK). Its 7.9.3.1.1 release ships a broken macOS
195
- # wheel (no OCP.GccEnt module → build123d fails to import), so pin it out. Only bites
196
- # when novtk is actually resolved (build123d 0.11); harmless on 0.10/cadquery-ocp.
197
- # Mirrors pzfreo/build123d-mcp. Remove once upstream fixes the wheel.
198
- constraint-dependencies = ["cadquery-ocp-novtk!=7.9.3.1.1"]
@@ -585,6 +585,30 @@ def _fmt(v: float, decimals: int | None = None) -> str:
585
585
  return str(r) if abs(v - r) < 1e-6 else f"{v:.1f}"
586
586
 
587
587
 
588
+ def _fmt_angle(value, decimals=None, tolerance=None) -> str:
589
+ """Complete angular text shared by footprint sizing and compilation.
590
+
591
+ This pure formatter approves no content and needs no feature or compiled plan.
592
+ """
593
+ nominal = f"{_fmt(value, decimals)}°"
594
+ if tolerance is None:
595
+ return nominal
596
+
597
+ def magnitude(value):
598
+ if isinstance(value, bool) or not isinstance(value, (int, float)):
599
+ raise ValueError("angular tolerance must be a nonnegative degree magnitude")
600
+ if not math.isfinite(value) or value < 0:
601
+ raise ValueError("angular tolerance must be finite and nonnegative")
602
+ # Keep small authored deviations even when nominal display precision is
603
+ # coarse; formatting a nonzero tolerance as zero would change the claim.
604
+ return format(Decimal(str(value)), "f")
605
+
606
+ if isinstance(tolerance, tuple) and len(tolerance) == 2:
607
+ lower, upper = tolerance
608
+ return f"{nominal} +{magnitude(upper)}° -{magnitude(lower)}°"
609
+ return f"{nominal} ±{magnitude(tolerance)}°"
610
+
611
+
588
612
  def _boxes_overlap(a, b) -> bool:
589
613
  """True when two ``(x0, y0, x1, y1)`` AABBs overlap (strict: a touch is not
590
614
  an overlap). The one pairwise test behind both the placement-side
@@ -0,0 +1,146 @@
1
+ """Analytic angular footprints shared by composition and rendered dimensions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from math import atan2, cos, hypot, pi, sin
7
+
8
+
9
+ @dataclass(frozen=True)
10
+ class AngularStyle:
11
+ """Fixed paper-space dimensions needed for analytic angular ink."""
12
+
13
+ arrow_length: float
14
+ extension_gap: float
15
+ pad_around_text: float
16
+ line_width: float
17
+
18
+
19
+ def _box(points, padding=0.0):
20
+ xs, ys = zip(*points, strict=True)
21
+ return min(xs) - padding, min(ys) - padding, max(xs) + padding, max(ys) + padding
22
+
23
+
24
+ def _rotate(point, angle):
25
+ c, s = cos(angle), sin(angle)
26
+ x, y = point
27
+ return c * x - s * y, s * x + c * y
28
+
29
+
30
+ class AngularGeometry:
31
+ """One projected angular intent; only its radius varies during placement.
32
+
33
+ Coordinates belong to the already selected true-angle projection. The two
34
+ directed rays fix the sector: moving an annotation cannot turn an acute
35
+ dimension into its supplementary angle or move it to the opposite sector.
36
+ """
37
+
38
+ def __init__(self, vertex, first, second, text_size, draft, *, sector="minor"):
39
+ if sector not in ("minor", "opposite"):
40
+ raise ValueError("angular ink needs a minor or opposite sector")
41
+ self.sector = sector
42
+ self.vertex = tuple(vertex[:2])
43
+ points = (tuple(first[:2]), tuple(second[:2]))
44
+ rays = [tuple(p - v for p, v in zip(point, self.vertex, strict=True)) for point in points]
45
+ lengths = tuple(hypot(*ray) for ray in rays)
46
+ # Page-fit bisection can project valid model rays far below a nanometre.
47
+ # Their directions still define the same angle and fixed-size label;
48
+ # rejecting them here turns an infeasible sheet into a render exception.
49
+ if min(lengths) == 0:
50
+ raise ValueError("angular ink needs two nonzero projected rays")
51
+ rays = [tuple(c / length for c in ray) for ray, length in zip(rays, lengths, strict=True)]
52
+ if sector == "opposite":
53
+ rays = [tuple(-component for component in ray) for ray in rays]
54
+ lengths = tuple(-length for length in lengths)
55
+ first_ray, second_ray = rays
56
+ signed = atan2(
57
+ first_ray[0] * second_ray[1] - first_ray[1] * second_ray[0],
58
+ sum(a * b for a, b in zip(first_ray, second_ray, strict=True)),
59
+ )
60
+ self.sweep = abs(signed)
61
+ if not 1e-9 < self.sweep < pi - 1e-9:
62
+ raise ValueError("angular ink needs a nondegenerate minor sector")
63
+ if signed < 0:
64
+ first_ray, second_ray = second_ray, first_ray
65
+ points = points[::-1]
66
+ lengths = lengths[::-1]
67
+ self.start = atan2(first_ray[1], first_ray[0])
68
+ self.middle = self.start + self.sweep / 2
69
+ self.rays = (first_ray, second_ray)
70
+ self.witnesses = points
71
+ self.lengths = lengths
72
+ self.draft = draft
73
+ self.text_size = text_size
74
+ tangent = (self.middle + pi / 2) % (2 * pi)
75
+ self.text_angle = tangent - pi if pi / 2 < tangent <= 3 * pi / 2 else tangent
76
+ width, height = self.text_size
77
+ # This bound leaves room for both arrow shafts and the full text. It also
78
+ # keeps extension lines beyond their physical witness points. Opposite
79
+ # witnesses have negative stations: their extensions cross the vertex.
80
+ self.minimum_radius = max(
81
+ max(lengths) + draft.extension_gap + draft.arrow_length,
82
+ (width + height + 2 * draft.pad_around_text + 4 * draft.arrow_length) / self.sweep
83
+ + height / 2
84
+ + draft.pad_around_text,
85
+ )
86
+
87
+ @property
88
+ def bisector(self):
89
+ return cos(self.middle), sin(self.middle)
90
+
91
+ def point(self, radius, angle):
92
+ x, y = self.vertex
93
+ return x + radius * cos(angle), y + radius * sin(angle)
94
+
95
+ def label_polygon(self, radius):
96
+ width, height = self.text_size
97
+ centre = self.point(radius, self.middle)
98
+ return tuple(
99
+ tuple(a + b for a, b in zip(centre, _rotate(point, self.text_angle), strict=True))
100
+ for point in (
101
+ (-width / 2, -height / 2),
102
+ (width / 2, -height / 2),
103
+ (width / 2, height / 2),
104
+ (-width / 2, height / 2),
105
+ )
106
+ )
107
+
108
+ def extension_segments(self, radius):
109
+ end_radius = radius + self.draft.extension_gap
110
+ return tuple(
111
+ (
112
+ self.point(length + self.draft.extension_gap, angle),
113
+ self.point(end_radius, angle),
114
+ )
115
+ for length, angle in zip(
116
+ self.lengths, (self.start, self.start + self.sweep), strict=True
117
+ )
118
+ )
119
+
120
+ def arc_intervals(self, radius):
121
+ width, height = self.text_size
122
+ gap = atan2(
123
+ width / 2 + self.draft.pad_around_text,
124
+ radius - height / 2 - self.draft.pad_around_text,
125
+ )
126
+ intervals = ((self.start, self.middle - gap), (self.middle + gap, self.start + self.sweep))
127
+ if any((end - start) * radius <= self.draft.arrow_length for start, end in intervals):
128
+ raise ValueError("angular radius cannot carry the complete label and arrows")
129
+ return intervals
130
+
131
+ def footprint(self, radius):
132
+ """Conservative analytic ink box, including arc extrema and arrow heads.
133
+
134
+ The perpendicular extent changes with radius. Supplying this function to
135
+ the corridor prevents its straight-dimension translation model from
136
+ hiding obstacles from an angular candidate.
137
+ """
138
+ angles = [self.start, self.start + self.sweep]
139
+ for index in range(-4, 9):
140
+ angle = index * pi / 2
141
+ if self.start < angle < self.start + self.sweep:
142
+ angles.append(angle)
143
+ points = [self.point(radius, angle) for angle in angles]
144
+ points.extend(point for segment in self.extension_segments(radius) for point in segment)
145
+ points.extend(self.label_polygon(radius))
146
+ return _box(points, self.draft.arrow_length + self.draft.line_width)
@@ -13,6 +13,7 @@ import logging
13
13
  import math
14
14
  import os
15
15
  from dataclasses import dataclass, field
16
+ from itertools import chain
16
17
  from pathlib import Path
17
18
  from typing import Any
18
19
 
@@ -33,6 +34,7 @@ from draftwright._geometry import ( # noqa: F401
33
34
  _segment_crosses_box,
34
35
  _segments_cross_or_overlap,
35
36
  )
37
+ from draftwright.annotations.angular import AngularDimension
36
38
  from draftwright.layout import StripCandidate, plan_strip
37
39
  from draftwright.linting.ink_overlap import (
38
40
  MIN_CROSSING_MM,
@@ -44,6 +46,8 @@ from draftwright.linting.issues import LintIssue
44
46
  from draftwright.linting.structural import (
45
47
  _ann_box,
46
48
  _centerline_extent,
49
+ _edges_intersect_rect,
50
+ _view_edge_entries,
47
51
  )
48
52
  from draftwright.model.compiled import resolve_feature
49
53
  from draftwright.model.ir import HoleFeature, PatternFeature
@@ -616,6 +620,12 @@ class SolveTrace:
616
620
  (with *label*) for a pass-local strip placement outside any corridor."""
617
621
  rec: dict = {
618
622
  "force": force,
623
+ # A fallback can use another axis/view while its parent corridor is
624
+ # still open. Every pass therefore owns its coordinate frame.
625
+ "label": label,
626
+ "view": view,
627
+ "axis": axis,
628
+ "strip": self._strip_rec(strip),
619
629
  "obstacles": [],
620
630
  "free_segments": [],
621
631
  "placed": [],
@@ -628,10 +638,6 @@ class SolveTrace:
628
638
  rec = {
629
639
  "seq": self._next_seq(),
630
640
  "phase": self._phase,
631
- "label": label,
632
- "view": view,
633
- "axis": axis,
634
- "strip": self._strip_rec(strip),
635
641
  **rec,
636
642
  "items": [],
637
643
  }
@@ -1504,7 +1510,7 @@ def box_within_page_and_clear(bb, page_box, obstacles) -> bool:
1504
1510
  )
1505
1511
 
1506
1512
 
1507
- def annotation_ink_clear(dwg, candidate, *, view=None) -> bool:
1513
+ def annotation_ink_clear(dwg, candidate, *, view=None, additional=()) -> bool:
1508
1514
  """Whether *candidate* clears exact decomposable ink and conservative fixed furniture.
1509
1515
 
1510
1516
  A diagonal dimension cannot use the strip system's conservative AABB occupancy as its
@@ -1528,8 +1534,8 @@ def annotation_ink_clear(dwg, candidate, *, view=None) -> bool:
1528
1534
  )
1529
1535
  if candidate_region is None:
1530
1536
  return False
1531
- for name, annotation in dwg.iter_annotations():
1532
- owner = dwg.view_of(name)
1537
+ for name, annotation in chain(dwg.iter_annotations(), ((None, item) for item in additional)):
1538
+ owner = dwg.view_of(name) if name is not None else view
1533
1539
  if view is not None and owner is not None and owner != view:
1534
1540
  continue
1535
1541
  annotation_segments = segments_of(annotation)
@@ -1542,9 +1548,9 @@ def annotation_ink_clear(dwg, candidate, *, view=None) -> bool:
1542
1548
  item=annotation,
1543
1549
  segments=annotation_segments,
1544
1550
  )
1545
- crossable_strokes = isinstance(annotation, (Dimension, SafeDimension)) or (
1546
- type(annotation).__name__ in CROSSABLE_TYPES
1547
- )
1551
+ crossable_strokes = isinstance(
1552
+ annotation, (Dimension, SafeDimension, AngularDimension)
1553
+ ) or (type(annotation).__name__ in CROSSABLE_TYPES)
1548
1554
  if annotation_label is not None and annotation_region is None:
1549
1555
  try:
1550
1556
  conservative_label_hit = _boxes_overlap(candidate_label, annotation_label) or any(
@@ -1593,6 +1599,19 @@ def annotation_ink_clear(dwg, candidate, *, view=None) -> bool:
1593
1599
  return True
1594
1600
 
1595
1601
 
1602
+ def view_label_clearance(dwg, view):
1603
+ """A label guard over the same projected edges the structural critic reads.
1604
+
1605
+ Prepare the edges once per batch, outside candidate evaluation. Missing view
1606
+ geometry supplies no guard; unreadable geometry cannot establish clearance.
1607
+ """
1608
+ placed = getattr(dwg, "views", {}).get(view)
1609
+ if not placed or placed[0] is None:
1610
+ return None
1611
+ entries = _view_edge_entries(placed[0], {})
1612
+ return lambda box: entries is not None and not _edges_intersect_rect(entries, box)
1613
+
1614
+
1596
1615
  def prevent_dimension_label_ink(
1597
1616
  dimensions,
1598
1617
  *,
@@ -1600,6 +1619,7 @@ def prevent_dimension_label_ink(
1600
1619
  immutable=(),
1601
1620
  obstacles=(),
1602
1621
  perpendicular_step=None,
1622
+ label_clear=None,
1603
1623
  ):
1604
1624
  """Choose small along-line label offsets for a just-built dimension batch.
1605
1625
 
@@ -1627,12 +1647,14 @@ def prevent_dimension_label_ink(
1627
1647
  whose line-work cannot be cleared by moving labels along their measured spans.
1628
1648
  Fixed *obstacles* do not make an existing contact this local batch's responsibility, but
1629
1649
  no selected move may introduce a new label contact with one.
1650
+ ``label_clear`` optionally checks labels against projected part ink. Unlike
1651
+ pre-existing annotation contacts, these are conflicts to resolve in this batch.
1630
1652
 
1631
1653
  Returns ``[(name, dimension), ...]`` in input order.
1632
1654
  """
1633
1655
 
1634
1656
  original = list(dimensions)
1635
- if len(original) < 2:
1657
+ if not original or (len(original) < 2 and label_clear is None):
1636
1658
  return original
1637
1659
  immutable = set(immutable)
1638
1660
  obstacles = tuple(obstacles)
@@ -1729,6 +1751,8 @@ def prevent_dimension_label_ink(
1729
1751
  for target, (label, region) in enumerate(zip(labels, regions, strict=True)):
1730
1752
  if label is None or region is None:
1731
1753
  continue
1754
+ if label_clear is not None and not label_clear(label):
1755
+ found.add(("view", target))
1732
1756
  # Helpers expose no arrow polygons. The foreign dimension's exact
1733
1757
  # attachment tips still participate, closing the line-metadata gap without
1734
1758
  # guessing the orientation of this dimension's own inside/outside arrows.
@@ -1907,6 +1931,8 @@ def prevent_dimension_label_ink(
1907
1931
  involved.update((conflict[1], conflict[2])) # source + crossed label
1908
1932
  elif conflict[0] == "fixed":
1909
1933
  involved.add(conflict[2])
1934
+ elif conflict[0] == "view":
1935
+ involved.add(conflict[1])
1910
1936
  else: # label/label
1911
1937
  involved.update((conflict[1], conflict[2]))
1912
1938
  best = None
@@ -2053,6 +2079,13 @@ class CorridorCandidate:
2053
2079
  # keeping footprints truthful (``dim_footprint``, ±0.05 mm) is what keeps that
2054
2080
  # fallback rare and the placement identical to the probe path.
2055
2081
  footprint: object | None = None
2082
+ # A candidate can need a minimum geometric clearance (e.g. an angular arc
2083
+ # must carry its complete label). Reject an infeasible tier before building
2084
+ # OCC ink; the caller's normal drop/fallback path remains authoritative.
2085
+ valid_position: object | None = None
2086
+ # Bounded curved-ink alternatives, checked against actual ink after the
2087
+ # conservative strip solve. They preserve the approved content and sector.
2088
+ compact_candidates: object | None = None
2056
2089
 
2057
2090
 
2058
2091
  def solve_corridor(dwg, strip, view, axis, cands, tier, corner_reserves=(), *, key=None, ctx=None):
@@ -2210,6 +2243,8 @@ def solve_corridor(dwg, strip, view, axis, cands, tier, corner_reserves=(), *, k
2210
2243
  anchored = {c.name: c.anchored for c in kept if c.anchored}
2211
2244
  naturals = {c.name: c.natural for c in kept if c.natural is not None}
2212
2245
  foots = {c.name: c.footprint for c in kept if c.footprint is not None} # analytical (#602)
2246
+ valid_positions = {c.name: c.valid_position for c in kept if c.valid_position is not None}
2247
+ compactions = {c.name: c.compact_candidates for c in kept if c.compact_candidates is not None}
2213
2248
  left = {
2214
2249
  n
2215
2250
  for n, _ in place_strip_candidates(
@@ -2229,6 +2264,8 @@ def solve_corridor(dwg, strip, view, axis, cands, tier, corner_reserves=(), *, k
2229
2264
  anchored=anchored,
2230
2265
  naturals=naturals,
2231
2266
  footprints=foots,
2267
+ valid_positions=valid_positions,
2268
+ compact_candidates=compactions,
2232
2269
  corner_reserves=corner_reserves,
2233
2270
  trace=trace,
2234
2271
  )
@@ -2247,6 +2284,8 @@ def solve_corridor(dwg, strip, view, axis, cands, tier, corner_reserves=(), *, k
2247
2284
  ctx=ctx,
2248
2285
  force=True,
2249
2286
  footprints=foots,
2287
+ valid_positions=valid_positions,
2288
+ compact_candidates=compactions,
2250
2289
  corner_reserves=corner_reserves,
2251
2290
  features=feats,
2252
2291
  measurements=meas,
@@ -2538,6 +2577,8 @@ def place_strip_candidates(
2538
2577
  anchored=None,
2539
2578
  naturals=None,
2540
2579
  footprints=None,
2580
+ valid_positions=None,
2581
+ compact_candidates=None,
2541
2582
  corner_reserves=(),
2542
2583
  trace=None,
2543
2584
  trace_label=None,
@@ -2777,6 +2818,11 @@ def place_strip_candidates(
2777
2818
  _reject(name, "over_capacity")
2778
2819
  rejected.append((name, build))
2779
2820
  continue
2821
+ valid_position = (valid_positions or {}).get(name)
2822
+ if valid_position is not None and not valid_position(pos):
2823
+ _reject(name, "geometric_clearance")
2824
+ rejected.append((name, build))
2825
+ continue
2780
2826
  # Predicted box, not built geometry (#602): the refill loop re-evaluates
2781
2827
  # every already-accepted candidate each iteration, so building here made
2782
2828
  # the drain quadratic in OCC builds.
@@ -2867,6 +2913,48 @@ def place_strip_candidates(
2867
2913
  continue
2868
2914
  real = _geom_box(dim)
2869
2915
  solved.append((name, natural if _real_box_conflict(name, real) else dim))
2916
+ # Curved ink can enclose large empty rectangles. After the shared strip
2917
+ # solve, try a bounded contraction using actual segments and labels against
2918
+ # both committed ink and this batch. Never move an anchored dimension.
2919
+ active_names = {name for name, _build in cands}
2920
+ for name, alternatives in (compact_candidates or {}).items():
2921
+ if name not in active_names:
2922
+ continue
2923
+ if (anchored or {}).get(name, False):
2924
+ continue
2925
+ index = next((i for i, (key, _dim) in enumerate(solved) if key == name), None)
2926
+ original = solved[index][1] if index is not None else None
2927
+ others = [item for key, item in solved if key != name]
2928
+ for candidate in alternatives():
2929
+ if original is not None and candidate.arc_radius >= original.arc_radius - 1e-6:
2930
+ break
2931
+ box = _geom_box(candidate)
2932
+ if (
2933
+ box is None
2934
+ or box[0] < _MARGIN
2935
+ or box[1] < _MARGIN
2936
+ or box[2] > dwg.page_w - _MARGIN
2937
+ or box[3] > dwg.page_h - _MARGIN
2938
+ or ((forbid or {}).get(name) is not None and _box_hits(box, (forbid[name],)))
2939
+ or not annotation_ink_clear(dwg, candidate, additional=others)
2940
+ ):
2941
+ continue
2942
+ if index is None:
2943
+ solved.append((name, candidate))
2944
+ todo = [(key, build) for key, build in todo if key != name]
2945
+ if tp is not None:
2946
+ label = candidate.label_bbox
2947
+ tp["placed"].append({"name": name, "pos": (label[idx] + label[idx + 2]) / 2})
2948
+ else:
2949
+ solved[index] = (name, candidate)
2950
+ if tp is not None:
2951
+ entry = next(item for item in tp["placed"] if item["name"] == name)
2952
+ label = candidate.label_bbox
2953
+ entry["strip_pos"] = entry["pos"]
2954
+ entry["pos"] = (label[idx] + label[idx + 2]) / 2
2955
+ if tp is not None:
2956
+ tp.setdefault("angular_contractions", []).append(name)
2957
+ break
2870
2958
  for name, dim in solved:
2871
2959
  # Record feature provenance (ADR 5 (was 0010)): the drain-time seam for corridor-placed
2872
2960
  # dims — `features` maps this batch's names to their source IR feature.