Third-party drawing-annotation helpers for build123d — dim_linear, leader, view_axes, lint_drawing
Project description
build123d-drafting-helpers
Third-party drawing-annotation helpers for build123d — pure Python, no MCP dependency. Not affiliated with the upstream build123d project.
from build123d_drafting import (
dim_linear, place_dims, place_labels, centerline,
leader, view_axes, lint_drawing,
)
The install name is build123d-drafting-helpers; the import name is build123d_drafting.
Not to be confused with
baverman/build123d_draft— that project is modelling shortcuts (slot helpers, rotation aliases,build_linewrappers), not drafting/annotation. Different scope despite the similar name.
Installation
pip install build123d-drafting-helpers
Or with uv:
uv add build123d-drafting-helpers
Requires build123d >= 0.7.0 and Python ≥ 3.10.
Helpers
dim_linear(p1, p2, side, distance, draft, label=None, tolerance=None, label_offset_x=0.0)
ExtensionLine wrapper with named placement side instead of raw signed offset.
draft = Draft(font_size=2.5, decimal_precision=1)
dim = dim_linear((-20, -10, 0), (20, -10, 0), "below", 8, draft, label="40")
side accepts "above" / "below" / "left" / "right" or an explicit world-direction vector.
The correct offset sign is computed from the path direction's right-hand normal — no guessing.
label_offset_x shifts the label along the dim line (mm, signed). Use it to move the label away
from a crossing centreline without changing the dim position or geometry. Positive shifts toward p2.
# Label crosses bore centreline at x=0 — shift it right by 15 mm
dim = dim_linear((-10, 0, 0), (10, 0, 0), "above", 8, draft, label="Ø5.0 H8", label_offset_x=15)
Returns a DimResult(shape, label_str, measured_length, dim_level_y, label_bbox).
label_bbox is the precise text extent (min_x, min_y, max_x, max_y) — used by lint_drawing
and place_labels for centreline-overlap detection.
place_dims(specs, draft, base_distance=8.0, tier_spacing=None)
Build a stack of parallel dims with automatically assigned offsets. No need to compute distance manually.
dims = place_dims([
((-30, 0, 0), (30, 0, 0), "above", "60"), # full width → tier 0 (innermost)
((-10, 0, 0), (10, 0, 0), "above", "20"), # overlaps → tier 1
(( 15, 0, 0), (30, 0, 0), "above", "15"), # non-overlap → tier 0 (shares with first)
], draft)
Specs are (p1, p2, side, label) or (p1, p2, side, label, tolerance) — no distance.
Dims whose X/Y spans overlap are placed on successive tiers; non-overlapping dims share a tier.
Order matters: specs listed first are placed on lower (inner) tiers.
tier_spacing defaults to draft.font_size * 3 + draft.arrow_length.
place_labels(specs, draft, centerlines, gap=1.0)
Like place_dims but also auto-shifts each label to clear any crossing vertical centreline.
bore_cl = centerline((0, -30, 0), (0, 30, 0)) # vertical centreline at x=0
dims = place_labels([
((-10, 0, 0), (10, 0, 0), "above", 8, "Ø5.0 H8"),
((-20, 0, 0), (20, 0, 0), "above", 18, "40"),
], draft, centerlines=[bore_cl])
Specs are (p1, p2, side, distance, label) or (p1, p2, side, distance, label, tolerance).
For each dim whose label would cross a centreline, the minimum left/right shift is computed
automatically. Multiple crossing centrelines are handled in one pass.
centerline(p1, p2) / CenterlineResult
Thin Edge compound representing a centreline, returned as a CenterlineResult.
bore_cl = centerline((cx, -50, 0), (cx, 50, 0)) # vertical through bore axis
Pass CenterlineResult objects to place_labels(..., centerlines=[bore_cl]) for auto-avoidance,
or pass them to lint_drawing([...] + [bore_cl]) to get label_centerline_overlap warnings.
When working with the MCP server, register centrelines with register_centerline(shape, name) so
lint_drawing() in session mode can also check them.
safe_dim_line(path, label, draft, fallback_label=None)
DimensionLine wrapper that won't raise ValueError when the label is wider than the dim path.
Truncates gracefully and retries.
leader(tip, elbow, label, draft)
Leader annotation built from scratch. The line stops cleanly before the label text.
res = leader((5, 5, 0), (20, 12, 0), "⌀7.93 H7", draft)
exporter.add_shape(res.lines, layer="dims") # arrowhead + shelf — fill_color layer
exporter.add_shape(res.text, layer="text") # glyphs — fill_color layer
Returns LeaderResult(lines, text, label_str, tip, elbow). Route lines and text to
separate SVG layers, both with fill_color set.
view_axes(viewport_origin, viewport_up=(0,1,0), look_at=(0,0,0))
Returns the world→page axis mapping for a project_to_viewport call, computed analytically.
axes = view_axes((0, 0, -100), (0, 1, 0), (0, 0, 0))
# {"world_X": ("page_X", -1.0), "world_Y": ("page_Y", 1.0), "world_Z": ("depth", 0.0)}
# ↑ bottom view flips world-X on the page
lint_drawing(items, part_bbox=None)
Structural checks on a list of DimResult / LeaderResult / CenterlineResult objects:
| Check | Trigger |
|---|---|
label_vs_measured |
Label value differs from measured path length by >0.5% — likely axis swap |
annotation_overlap |
Two annotations overlap by >0.5 mm in both axes at the same Y level |
label_centerline_overlap |
Dim label bbox crosses a CenterlineResult — use label_offset_x or place_labels |
dim_inside_part |
Dim bbox overlaps part outline by >10% — dim is inside the view |
leader_line_through_text |
Leader elbow point inside label bbox — line strikes through text |
bore_cl = centerline((0, -30, 0), (0, 30, 0))
issues = lint_drawing([dim1, dim2, lea1, bore_cl])
for issue in issues:
print(issue.severity, issue.message)
iso_title_block(...) and surface_finish_mark(...)
iso_title_block is a standalone title box (170 × 16 mm by default), positioned by the caller. It is not a substitute for build123d.TechnicalDrawing, which is a whole-page chrome — page-sized border + grid ticks + embedded title box, returned as a single Sketch. Use TechnicalDrawing when you want the full drawing-sheet frame; reach for iso_title_block when you want just the title box, positionable anywhere, with separate lines/text Compounds for SVG layer routing, and with material / general_tolerance fields that TechnicalDrawing does not carry.
surface_finish_mark produces an ISO 1302 Ra-value check-mark symbol — build123d does not ship one.
Status against upstream
lint_drawingis a prototype of rule-based drawing checks that build123d's roadmap mentions as future work. If upstream ships its own linter later, this one can be deprecated.dim_linearis a thin convenience wrapper overExtensionLine— it does not replace the underlying class, it just lets you writeside="above"instead of computing the right-hand-normal signed offset by hand. If upstream adds a named-side parameter, this helper becomes redundant.
Development
git clone https://github.com/pzfreo/build123d-drafting-helpers.git
cd build123d-drafting-helpers
uv run pytest tests/
Status
Alpha. API may change. Developed alongside build123d-mcp, which integrates these helpers into its LLM-facing drawing workflow.
Documentation
- Drafting conventions and gotchas — offset sign table, crash modes, recommended feedback loop, and when to reach for which helper.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file build123d_drafting_helpers-0.1.4.tar.gz.
File metadata
- Download URL: build123d_drafting_helpers-0.1.4.tar.gz
- Upload date:
- Size: 26.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8b0308ea0e69956afe38661ec3997d2aa182f22c20fbac5ee5fc2a247fd89be0
|
|
| MD5 |
7f3127c1565385d1ea432eeafa84f81b
|
|
| BLAKE2b-256 |
840cea37aecdadb715426c424edd3c9dba8fa4270a8f80a38dba9a74939c6b28
|
Provenance
The following attestation bundles were made for build123d_drafting_helpers-0.1.4.tar.gz:
Publisher:
publish.yml on pzfreo/build123d-drafting-helpers
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
build123d_drafting_helpers-0.1.4.tar.gz -
Subject digest:
8b0308ea0e69956afe38661ec3997d2aa182f22c20fbac5ee5fc2a247fd89be0 - Sigstore transparency entry: 1591191505
- Sigstore integration time:
-
Permalink:
pzfreo/build123d-drafting-helpers@4e9dd8c01805a783af6ddc7707f17f22f2e38fe3 -
Branch / Tag:
refs/tags/v0.1.4 - Owner: https://github.com/pzfreo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4e9dd8c01805a783af6ddc7707f17f22f2e38fe3 -
Trigger Event:
release
-
Statement type:
File details
Details for the file build123d_drafting_helpers-0.1.4-py3-none-any.whl.
File metadata
- Download URL: build123d_drafting_helpers-0.1.4-py3-none-any.whl
- Upload date:
- Size: 24.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a6003490fe6097b76850ef17b625e76cce2aa513d74ea1853c9beee42b665200
|
|
| MD5 |
e0bcaec4410605f5b74c56b7273bd40a
|
|
| BLAKE2b-256 |
54579949e7f127cf7df09339c7782a0fec47b1743b400504496b10985c8ecfc2
|
Provenance
The following attestation bundles were made for build123d_drafting_helpers-0.1.4-py3-none-any.whl:
Publisher:
publish.yml on pzfreo/build123d-drafting-helpers
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
build123d_drafting_helpers-0.1.4-py3-none-any.whl -
Subject digest:
a6003490fe6097b76850ef17b625e76cce2aa513d74ea1853c9beee42b665200 - Sigstore transparency entry: 1591191507
- Sigstore integration time:
-
Permalink:
pzfreo/build123d-drafting-helpers@4e9dd8c01805a783af6ddc7707f17f22f2e38fe3 -
Branch / Tag:
refs/tags/v0.1.4 - Owner: https://github.com/pzfreo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4e9dd8c01805a783af6ddc7707f17f22f2e38fe3 -
Trigger Event:
release
-
Statement type: