draftwright 0.1.2__tar.gz → 0.1.3__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.1.2 → draftwright-0.1.3}/PKG-INFO +1 -1
- {draftwright-0.1.2 → draftwright-0.1.3}/pyproject.toml +1 -1
- {draftwright-0.1.2 → draftwright-0.1.3}/src/draftwright/make_drawing.py +94 -33
- {draftwright-0.1.2 → draftwright-0.1.3}/tests/test_make_drawing.py +25 -22
- {draftwright-0.1.2 → draftwright-0.1.3}/.gitignore +0 -0
- {draftwright-0.1.2 → draftwright-0.1.3}/CHANGELOG.md +0 -0
- {draftwright-0.1.2 → draftwright-0.1.3}/LICENSE +0 -0
- {draftwright-0.1.2 → draftwright-0.1.3}/README.md +0 -0
- {draftwright-0.1.2 → draftwright-0.1.3}/skills/SKILL.md +0 -0
- {draftwright-0.1.2 → draftwright-0.1.3}/src/draftwright/__init__.py +0 -0
- {draftwright-0.1.2 → draftwright-0.1.3}/src/draftwright/pmi.py +0 -0
- {draftwright-0.1.2 → draftwright-0.1.3}/tests/fixtures/nist_ctc_01_asme1_ap242.stp +0 -0
- {draftwright-0.1.2 → draftwright-0.1.3}/tests/test_e2e_standards.py +0 -0
- {draftwright-0.1.2 → draftwright-0.1.3}/tests/test_pmi.py +0 -0
|
@@ -810,6 +810,29 @@ def _analyse(step_file, title, number, tolerance, drawn_by, out, scale=None, pag
|
|
|
810
810
|
ISO_X = sv_right + right_avail / 2
|
|
811
811
|
ISO_Y = PV_Y
|
|
812
812
|
|
|
813
|
+
# When the standard iso zone (right of SV) is narrower than the natural iso
|
|
814
|
+
# extent, check whether the upper-right zone — right of FV/PV and above the SV
|
|
815
|
+
# y-range — offers more room. This zone shares no y-range with the SV, so the
|
|
816
|
+
# iso can sit there without conflicting with SV annotations.
|
|
817
|
+
_iso_natural = bbox_max * SCALE * 0.7
|
|
818
|
+
_ur_left = FV_X + fv_hw + gap_fv_sv # = sv_left_edge; clears FV/PV right strips
|
|
819
|
+
_sv_top = FV_Y + fv_hh # SV_Y == FV_Y; sv_top == FV_Y + fv_hh
|
|
820
|
+
_ur_bottom = _sv_top + DIM_PAD
|
|
821
|
+
_ur_w = max(0.0, iso_right_limit - _ur_left)
|
|
822
|
+
_ur_h = max(0.0, (PAGE_H - margin) - _ur_bottom)
|
|
823
|
+
_std_min = min(right_avail, PAGE_H - 2 * margin)
|
|
824
|
+
_ur_min = min(_ur_w, _ur_h)
|
|
825
|
+
if _std_min < _iso_natural and _ur_min > _std_min:
|
|
826
|
+
ISO_X = (_ur_left + iso_right_limit) / 2
|
|
827
|
+
ISO_Y = (_ur_bottom + PAGE_H - margin) / 2
|
|
828
|
+
iso_left_limit = _ur_left
|
|
829
|
+
iso_bottom_limit = _ur_bottom
|
|
830
|
+
iso_in_upper_right = True
|
|
831
|
+
else:
|
|
832
|
+
iso_left_limit = sv_right
|
|
833
|
+
iso_bottom_limit = margin
|
|
834
|
+
iso_in_upper_right = False
|
|
835
|
+
|
|
813
836
|
# ------------------------------------------------------------------
|
|
814
837
|
# Strip / zone construction.
|
|
815
838
|
# Phase 1: defines regions only — annotation functions still use their
|
|
@@ -909,6 +932,9 @@ def _analyse(step_file, title, number, tolerance, drawn_by, out, scale=None, pag
|
|
|
909
932
|
SV_Y=SV_Y,
|
|
910
933
|
ISO_X=ISO_X,
|
|
911
934
|
ISO_Y=ISO_Y,
|
|
935
|
+
iso_left_limit=iso_left_limit,
|
|
936
|
+
iso_bottom_limit=iso_bottom_limit,
|
|
937
|
+
iso_in_upper_right=iso_in_upper_right,
|
|
912
938
|
# View half-extents in page units (convenient for strip arithmetic)
|
|
913
939
|
fv_hw=fv_hw,
|
|
914
940
|
fv_hh=fv_hh,
|
|
@@ -1259,7 +1285,15 @@ def _auto_annotate(dwg, a):
|
|
|
1259
1285
|
# the limit (dims already placed may overlap the iso view).
|
|
1260
1286
|
_iso_x0, _, _, _ = _iso_bbox(dwg)
|
|
1261
1287
|
_iso_x_limit = _iso_x0 - 4
|
|
1262
|
-
|
|
1288
|
+
# When the iso sits above the SV (upper-right zone), the SV right strip shares
|
|
1289
|
+
# no y-range with the iso, so tightening sv_zones.right by iso_x would set
|
|
1290
|
+
# outer_limit below the strip anchor and break all SV annotation allocations.
|
|
1291
|
+
_right_strips = (
|
|
1292
|
+
(a.fv_zones.right, a.pv_zones.right)
|
|
1293
|
+
if a.iso_in_upper_right
|
|
1294
|
+
else (a.fv_zones.right, a.pv_zones.right, a.sv_zones.right)
|
|
1295
|
+
)
|
|
1296
|
+
for _rs in _right_strips:
|
|
1263
1297
|
_rs.outer_limit = min(_rs.outer_limit, _iso_x_limit)
|
|
1264
1298
|
if _rs._cursor >= _iso_x_limit:
|
|
1265
1299
|
_log.warning(
|
|
@@ -2662,25 +2696,31 @@ def _project_iso(dwg, a, scale, shape_s=None):
|
|
|
2662
2696
|
dwg._coords["iso"] = ViewCoordinates(axes, a.ISO_X, a.ISO_Y, a.cx, a.cy, a.cz, scale)
|
|
2663
2697
|
|
|
2664
2698
|
|
|
2665
|
-
def _fit_iso_view(dwg, a):
|
|
2666
|
-
"""
|
|
2699
|
+
def _fit_iso_view(dwg, a, annotate: bool = True):
|
|
2700
|
+
"""Scale the iso view to fill its page zone, captioning it NTS when the
|
|
2701
|
+
scale differs from sheet scale. Pass ``annotate=False`` to suppress the
|
|
2702
|
+
NTS note (used when ``auto_dims=False``).
|
|
2703
|
+
|
|
2704
|
+
The iso is always centred at (ISO_X, ISO_Y) which sits at the centre of
|
|
2705
|
+
the available zone. The projection is linear, so the factor needed to
|
|
2706
|
+
fill the zone can be computed from the measured extents without iteration.
|
|
2667
2707
|
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
iso bbox overflows the region, re-project at a clean fraction of sheet
|
|
2672
|
-
scale and add an "ISO VIEW (NTS)" caption below it.
|
|
2708
|
+
- Overflow (needed < 1): shrink with 2 % safety margin.
|
|
2709
|
+
- Under-fill (needed > 1): grow to 90 % of zone, leaving breathing room.
|
|
2710
|
+
- Within 5 % of sheet scale: leave as-is (no NTS label).
|
|
2673
2711
|
"""
|
|
2674
|
-
|
|
2712
|
+
# Use the precomputed iso zone limits. When iso is in the upper-right zone,
|
|
2713
|
+
# any section view sits below the iso's y-range so its x-extent doesn't
|
|
2714
|
+
# constrain the iso region.
|
|
2715
|
+
region_left = a.iso_left_limit
|
|
2716
|
+
if not a.iso_in_upper_right and "section_aa" in dwg.views:
|
|
2717
|
+
sec_vis, sec_hid = dwg.views["section_aa"]
|
|
2718
|
+
sec_right = sec_vis.bounding_box().max.X
|
|
2719
|
+
if sec_hid:
|
|
2720
|
+
sec_right = max(sec_right, sec_hid.bounding_box().max.X)
|
|
2721
|
+
region_left = max(region_left, sec_right + 4)
|
|
2722
|
+
region = (region_left, a.iso_bottom_limit, a.iso_right_limit, a.PAGE_H - a.margin)
|
|
2675
2723
|
bb = _iso_bbox(dwg)
|
|
2676
|
-
# Exact check (no tolerance): the lint's view_out_of_bounds is exact, so
|
|
2677
|
-
# accepting a sub-tolerance overflow here would pass the fit yet fail lint.
|
|
2678
|
-
if _bbox_within(bb, region, tol=0.0):
|
|
2679
|
-
return
|
|
2680
|
-
# Orthographic projection is linear and the view centre maps to
|
|
2681
|
-
# (ISO_X, ISO_Y), so each bbox side's offset from the centre scales
|
|
2682
|
-
# exactly with the shape scale — the factor needed to fit can be computed
|
|
2683
|
-
# from the measured extents, costing a single re-projection.
|
|
2684
2724
|
ratios = [
|
|
2685
2725
|
avail / extent
|
|
2686
2726
|
for extent, avail in (
|
|
@@ -2692,24 +2732,32 @@ def _fit_iso_view(dwg, a):
|
|
|
2692
2732
|
if extent > 0
|
|
2693
2733
|
]
|
|
2694
2734
|
needed = min(ratios, default=1.0)
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2735
|
+
if needed >= 1.0:
|
|
2736
|
+
# Iso fits; grow to 90 % of zone — leaves comfortable breathing room.
|
|
2737
|
+
margin_pct = 0.90
|
|
2738
|
+
else:
|
|
2739
|
+
# Iso overflows; shrink to just fit with 2 % safety margin.
|
|
2740
|
+
margin_pct = 0.98
|
|
2741
|
+
factor = math.floor(needed * margin_pct * 10000) / 10000
|
|
2742
|
+
if needed >= 1.0:
|
|
2743
|
+
factor = max(factor, 1.0) # grow branch must never shrink
|
|
2744
|
+
if abs(factor - 1.0) < 0.05:
|
|
2745
|
+
return # within 5 % of sheet scale — no rescale, no NTS label
|
|
2699
2746
|
_project_iso(dwg, a, a.SCALE * factor)
|
|
2700
2747
|
bb = _iso_bbox(dwg)
|
|
2701
|
-
if not _bbox_within(bb, region):
|
|
2748
|
+
if factor < 1.0 and not _bbox_within(bb, region):
|
|
2702
2749
|
_log.warning("Iso view still overflows its page region at %g× sheet scale", factor)
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2750
|
+
if annotate:
|
|
2751
|
+
font = dwg.draft.font_size
|
|
2752
|
+
dwg.add(
|
|
2753
|
+
Note(
|
|
2754
|
+
"ISO VIEW (NTS)",
|
|
2755
|
+
(a.ISO_X, max(bb[1] - 2 * font, a.margin + font)),
|
|
2756
|
+
dwg.draft,
|
|
2757
|
+
),
|
|
2758
|
+
"note_iso_nts",
|
|
2759
|
+
)
|
|
2760
|
+
_log.info("Iso view scaled to %g× sheet scale%s", factor, " (NTS)" if annotate else "")
|
|
2713
2761
|
|
|
2714
2762
|
|
|
2715
2763
|
def build_drawing(
|
|
@@ -2779,11 +2827,24 @@ def build_drawing(
|
|
|
2779
2827
|
dwg.add_view("plan", part_s, (cxs, cys, czs + dist), (0, 1, 0), (a.PV_X, a.PV_Y), scaled=True)
|
|
2780
2828
|
dwg.add_view("side", part_s, (cxs + dist, cys, czs), (0, 0, 1), (a.SV_X, a.SV_Y), scaled=True)
|
|
2781
2829
|
_project_iso(dwg, a, a.SCALE, shape_s=part_s)
|
|
2782
|
-
_fit_iso_view(dwg, a)
|
|
2783
2830
|
|
|
2784
2831
|
if auto_dims:
|
|
2832
|
+
# Snapshot outer_limits before _auto_annotate tightens them against the
|
|
2833
|
+
# initial (possibly overflowing) iso. After _fit_iso_view rescales the
|
|
2834
|
+
# iso we restore all three right strips to min(original, final_iso_x_limit)
|
|
2835
|
+
# so each strip reflects actual final geometry, not the transient state.
|
|
2836
|
+
_fv_ol = a.fv_zones.right.outer_limit
|
|
2837
|
+
_pv_ol = a.pv_zones.right.outer_limit
|
|
2838
|
+
_sv_ol = a.sv_zones.right.outer_limit
|
|
2785
2839
|
_auto_annotate(dwg, a)
|
|
2840
|
+
_fit_iso_view(dwg, a)
|
|
2841
|
+
_final_iso_x_lim = _iso_bbox(dwg)[0] - 4
|
|
2842
|
+
a.fv_zones.right.outer_limit = min(_fv_ol, _final_iso_x_lim)
|
|
2843
|
+
a.pv_zones.right.outer_limit = min(_pv_ol, _final_iso_x_lim)
|
|
2844
|
+
if not a.iso_in_upper_right:
|
|
2845
|
+
a.sv_zones.right.outer_limit = min(_sv_ol, _final_iso_x_lim)
|
|
2786
2846
|
else:
|
|
2847
|
+
_fit_iso_view(dwg, a, annotate=False)
|
|
2787
2848
|
_add_title_block(dwg, a)
|
|
2788
2849
|
return dwg
|
|
2789
2850
|
|
|
@@ -1135,52 +1135,55 @@ def test_clear_annotations_keep_custom_and_unnamed_removed():
|
|
|
1135
1135
|
|
|
1136
1136
|
|
|
1137
1137
|
@pytest.fixture(scope="module")
|
|
1138
|
-
def
|
|
1139
|
-
#
|
|
1140
|
-
# sheet scale and is auto-shrunk. Module-scoped; tests must not mutate it.
|
|
1138
|
+
def ctc01_a3_drawing():
|
|
1139
|
+
# Fixture — NIST CTC-01-like plate at 1:5 on A3. Module-scoped; tests must not mutate it.
|
|
1141
1140
|
return build_drawing(Box(800, 450, 150), scale=0.2, page="A3")
|
|
1142
1141
|
|
|
1143
1142
|
|
|
1144
1143
|
@pytest.mark.timeout(120)
|
|
1145
|
-
def
|
|
1146
|
-
# #75 —
|
|
1147
|
-
#
|
|
1144
|
+
def test_ctc01_iso_uses_upper_right_zone(ctc01_a3_drawing):
|
|
1145
|
+
# #75 updated — wide/flat part on A3: the iso is repositioned into the upper-right
|
|
1146
|
+
# zone (above the SV, right of FV/PV) where it fits at sheet scale. No NTS label.
|
|
1148
1147
|
from draftwright.make_drawing import _iso_bbox
|
|
1149
1148
|
|
|
1150
|
-
dwg =
|
|
1149
|
+
dwg = ctc01_a3_drawing
|
|
1151
1150
|
labels = [getattr(a, "label", "") for a in dwg.annotations]
|
|
1152
|
-
assert "ISO VIEW (NTS)" in labels
|
|
1151
|
+
assert "ISO VIEW (NTS)" not in labels # iso now fits at sheet scale — no NTS
|
|
1153
1152
|
x0, y0, x1, y1 = _iso_bbox(dwg)
|
|
1154
1153
|
assert (
|
|
1155
1154
|
x1 <= dwg.page_w - 10 + 0.5 and x0 >= 0 and y0 >= 10 - 0.5 and y1 <= dwg.page_h - 10 + 0.5
|
|
1156
1155
|
)
|
|
1156
|
+
# iso must be significantly larger than the old 65 mm (shrunken) view
|
|
1157
|
+
assert (x1 - x0) > 100
|
|
1157
1158
|
|
|
1158
1159
|
|
|
1159
1160
|
@pytest.mark.timeout(120)
|
|
1160
|
-
def
|
|
1161
|
-
#
|
|
1162
|
-
#
|
|
1163
|
-
|
|
1164
|
-
dwg = shrunk_iso_drawing
|
|
1161
|
+
def test_ctc01_iso_world_to_page_mapping(ctc01_a3_drawing):
|
|
1162
|
+
# dwg.at("iso", ...) must map world points to page even after the iso is
|
|
1163
|
+
# repositioned to the upper-right zone (still projected at sheet scale).
|
|
1164
|
+
dwg = ctc01_a3_drawing
|
|
1165
1165
|
cx, cy, cz = dwg.centroid
|
|
1166
1166
|
centre = dwg.at("iso", cx, cy, cz)
|
|
1167
1167
|
vis, _hid = dwg.views["iso"]
|
|
1168
1168
|
bb = vis.bounding_box()
|
|
1169
1169
|
assert bb.min.X < centre[0] < bb.max.X and bb.min.Y < centre[1] < bb.max.Y
|
|
1170
|
-
|
|
1171
|
-
# the sheet scale). Derive the actual shrunk scale from _coords so the
|
|
1172
|
-
# test does not depend on a specific discretised shrink factor.
|
|
1173
|
-
shrunk_scale = dwg._coords["iso"]._scale
|
|
1174
|
-
assert shrunk_scale < dwg.scale, "iso should be shrunk below sheet scale"
|
|
1170
|
+
iso_scale = dwg._coords["iso"]._scale
|
|
1175
1171
|
raised = dwg.at("iso", cx, cy, cz + 100)
|
|
1176
|
-
assert raised[1] - centre[1] == pytest.approx(100 *
|
|
1172
|
+
assert raised[1] - centre[1] == pytest.approx(100 * iso_scale)
|
|
1177
1173
|
|
|
1178
1174
|
|
|
1179
1175
|
@pytest.mark.timeout(60)
|
|
1180
|
-
def
|
|
1176
|
+
def test_iso_stays_within_page_bounds():
|
|
1177
|
+
# Whether scaled up or not, the iso must always lie within the page margin.
|
|
1178
|
+
from draftwright.make_drawing import _iso_bbox
|
|
1179
|
+
|
|
1181
1180
|
dwg = build_drawing(Box(30, 20, 10))
|
|
1182
|
-
|
|
1183
|
-
|
|
1181
|
+
x0, y0, x1, y1 = _iso_bbox(dwg)
|
|
1182
|
+
margin = 10
|
|
1183
|
+
assert x0 >= margin - 0.5
|
|
1184
|
+
assert y0 >= margin - 0.5
|
|
1185
|
+
assert x1 <= dwg.page_w - margin + 0.5
|
|
1186
|
+
assert y1 <= dwg.page_h - margin + 0.5
|
|
1184
1187
|
|
|
1185
1188
|
|
|
1186
1189
|
@pytest.mark.timeout(60)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|