draftwright 0.1.1__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.1 → draftwright-0.1.3}/PKG-INFO +1 -1
- {draftwright-0.1.1 → draftwright-0.1.3}/pyproject.toml +1 -1
- {draftwright-0.1.1 → draftwright-0.1.3}/src/draftwright/make_drawing.py +99 -36
- {draftwright-0.1.1 → draftwright-0.1.3}/tests/test_make_drawing.py +25 -19
- {draftwright-0.1.1 → draftwright-0.1.3}/.gitignore +0 -0
- {draftwright-0.1.1 → draftwright-0.1.3}/CHANGELOG.md +0 -0
- {draftwright-0.1.1 → draftwright-0.1.3}/LICENSE +0 -0
- {draftwright-0.1.1 → draftwright-0.1.3}/README.md +0 -0
- {draftwright-0.1.1 → draftwright-0.1.3}/skills/SKILL.md +0 -0
- {draftwright-0.1.1 → draftwright-0.1.3}/src/draftwright/__init__.py +0 -0
- {draftwright-0.1.1 → draftwright-0.1.3}/src/draftwright/pmi.py +0 -0
- {draftwright-0.1.1 → draftwright-0.1.3}/tests/fixtures/nist_ctc_01_asme1_ap242.stp +0 -0
- {draftwright-0.1.1 → draftwright-0.1.3}/tests/test_e2e_standards.py +0 -0
- {draftwright-0.1.1 → 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,
|
|
@@ -1254,15 +1280,22 @@ def _auto_annotate(dwg, a):
|
|
|
1254
1280
|
return a.PV_Y + (y - a.cy) * a.SCALE
|
|
1255
1281
|
|
|
1256
1282
|
# Tighten right-strip outer_limits to the actual iso view left edge now
|
|
1257
|
-
# that the iso has been projected and fitted.
|
|
1258
|
-
#
|
|
1259
|
-
#
|
|
1283
|
+
# that the iso has been projected and fitted. Always apply so that any
|
|
1284
|
+
# future allocations are bounded; warn when the cursor has already passed
|
|
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
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
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:
|
|
1297
|
+
_rs.outer_limit = min(_rs.outer_limit, _iso_x_limit)
|
|
1298
|
+
if _rs._cursor >= _iso_x_limit:
|
|
1266
1299
|
_log.warning(
|
|
1267
1300
|
"right-strip cursor %.1f >= iso_x limit %.1f: right-strip dims"
|
|
1268
1301
|
" may overlap iso view (iso view overflows into annotation zone)",
|
|
@@ -2663,25 +2696,31 @@ def _project_iso(dwg, a, scale, shape_s=None):
|
|
|
2663
2696
|
dwg._coords["iso"] = ViewCoordinates(axes, a.ISO_X, a.ISO_Y, a.cx, a.cy, a.cz, scale)
|
|
2664
2697
|
|
|
2665
2698
|
|
|
2666
|
-
def _fit_iso_view(dwg, a):
|
|
2667
|
-
"""
|
|
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``).
|
|
2668
2703
|
|
|
2669
|
-
The
|
|
2670
|
-
|
|
2671
|
-
the
|
|
2672
|
-
|
|
2673
|
-
|
|
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.
|
|
2707
|
+
|
|
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).
|
|
2674
2711
|
"""
|
|
2675
|
-
|
|
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)
|
|
2676
2723
|
bb = _iso_bbox(dwg)
|
|
2677
|
-
# Exact check (no tolerance): the lint's view_out_of_bounds is exact, so
|
|
2678
|
-
# accepting a sub-tolerance overflow here would pass the fit yet fail lint.
|
|
2679
|
-
if _bbox_within(bb, region, tol=0.0):
|
|
2680
|
-
return
|
|
2681
|
-
# Orthographic projection is linear and the view centre maps to
|
|
2682
|
-
# (ISO_X, ISO_Y), so each bbox side's offset from the centre scales
|
|
2683
|
-
# exactly with the shape scale — the factor needed to fit can be computed
|
|
2684
|
-
# from the measured extents, costing a single re-projection.
|
|
2685
2724
|
ratios = [
|
|
2686
2725
|
avail / extent
|
|
2687
2726
|
for extent, avail in (
|
|
@@ -2693,21 +2732,32 @@ def _fit_iso_view(dwg, a):
|
|
|
2693
2732
|
if extent > 0
|
|
2694
2733
|
]
|
|
2695
2734
|
needed = min(ratios, default=1.0)
|
|
2696
|
-
|
|
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
|
|
2697
2746
|
_project_iso(dwg, a, a.SCALE * factor)
|
|
2698
2747
|
bb = _iso_bbox(dwg)
|
|
2699
|
-
if not _bbox_within(bb, region):
|
|
2748
|
+
if factor < 1.0 and not _bbox_within(bb, region):
|
|
2700
2749
|
_log.warning("Iso view still overflows its page region at %g× sheet scale", factor)
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
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 "")
|
|
2711
2761
|
|
|
2712
2762
|
|
|
2713
2763
|
def build_drawing(
|
|
@@ -2777,11 +2827,24 @@ def build_drawing(
|
|
|
2777
2827
|
dwg.add_view("plan", part_s, (cxs, cys, czs + dist), (0, 1, 0), (a.PV_X, a.PV_Y), scaled=True)
|
|
2778
2828
|
dwg.add_view("side", part_s, (cxs + dist, cys, czs), (0, 0, 1), (a.SV_X, a.SV_Y), scaled=True)
|
|
2779
2829
|
_project_iso(dwg, a, a.SCALE, shape_s=part_s)
|
|
2780
|
-
_fit_iso_view(dwg, a)
|
|
2781
2830
|
|
|
2782
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
|
|
2783
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)
|
|
2784
2846
|
else:
|
|
2847
|
+
_fit_iso_view(dwg, a, annotate=False)
|
|
2785
2848
|
_add_title_block(dwg, a)
|
|
2786
2849
|
return dwg
|
|
2787
2850
|
|
|
@@ -1135,49 +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
|
-
# World +Z maps to page +Y; the offset must use the shrunk view scale.
|
|
1170
|
+
iso_scale = dwg._coords["iso"]._scale
|
|
1172
1171
|
raised = dwg.at("iso", cx, cy, cz + 100)
|
|
1173
|
-
assert raised[1] - centre[1] == pytest.approx(100 *
|
|
1172
|
+
assert raised[1] - centre[1] == pytest.approx(100 * iso_scale)
|
|
1174
1173
|
|
|
1175
1174
|
|
|
1176
1175
|
@pytest.mark.timeout(60)
|
|
1177
|
-
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
|
+
|
|
1178
1180
|
dwg = build_drawing(Box(30, 20, 10))
|
|
1179
|
-
|
|
1180
|
-
|
|
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
|
|
1181
1187
|
|
|
1182
1188
|
|
|
1183
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
|