Plain units already get a gap from the source whitespace, so drop the leading space inside the string; keep it only on superscripted units (in^2, in^3, in^4, ft^2). Also fix the generated concrete-beam figure labels. Regenerate all affected PDFs.
180 lines
5.5 KiB
Python
180 lines
5.5 KiB
Python
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
HERE = Path(__file__).resolve().parent
|
|
|
|
SCALE = 9.5 # points per inch
|
|
LEFT = 48.0
|
|
RIGHT = 56.0
|
|
TOP = 28.0
|
|
BOTTOM = 38.0
|
|
|
|
STIRRUP_STROKE = 2.0 # drawn stirrup line width, points
|
|
STIRRUP_RADIUS = 3.0 # drawn stirrup corner radius, points
|
|
DRAW_COVER = 1.0 # schematic cover shown in the drawing, inches
|
|
|
|
MUTED = 'rgb("#626b73")'
|
|
|
|
|
|
def _f(value: float) -> str:
|
|
return f"{value:.4g}"
|
|
|
|
|
|
def _centers(size: float, number: int, bw: float, edge: float) -> list[float]:
|
|
half = size / 2.0
|
|
left = edge + half
|
|
right = bw - left
|
|
if number == 1:
|
|
return [bw / 2.0]
|
|
return [left + index * (right - left) / (number - 1) for index in range(number)]
|
|
|
|
|
|
def render(values: dict) -> str:
|
|
s = SCALE
|
|
bw = float(values["bw"])
|
|
h = float(values["h"])
|
|
stirrup_size = int(values["stirrup_size"])
|
|
stirrup_spacing = float(values["stirrup_spacing"])
|
|
bar_size = int(values["bar_size"])
|
|
bar_db = float(values["bar_db"])
|
|
n_bars = int(values["n_bars"])
|
|
top_bar_size = int(values["top_bar_size"])
|
|
top_bar_db = float(values["top_bar_db"])
|
|
n_top_bars = int(values["n_top_bars"])
|
|
|
|
w_sec = bw * s
|
|
h_sec = h * s
|
|
width = LEFT + w_sec + RIGHT
|
|
height = TOP + h_sec + BOTTOM
|
|
ox = LEFT
|
|
oy = TOP
|
|
|
|
def sx(x_in: float) -> float:
|
|
return ox + x_in * s
|
|
|
|
def sy(y_in: float) -> float:
|
|
return oy + (h - y_in) * s
|
|
|
|
edge = DRAW_COVER + STIRRUP_STROKE / s
|
|
inset = DRAW_COVER + STIRRUP_STROKE / s / 2.0
|
|
y_bottom = edge + bar_db / 2.0
|
|
bottom = _centers(bar_db, n_bars, bw, edge)
|
|
top_y = h - (edge + top_bar_db / 2.0)
|
|
top = _centers(top_bar_db, n_top_bars, bw, edge)
|
|
|
|
lines: list[str] = []
|
|
add = lines.append
|
|
add("// Generated by beam_section.py from input.yaml - do not edit by hand.")
|
|
add("#let beam-section() = {")
|
|
add(f" box(width: {_f(width)}pt, height: {_f(height)}pt)[")
|
|
|
|
add(
|
|
f" #place(dx: {_f(ox)}pt, dy: {_f(oy)}pt, "
|
|
f'rect(width: {_f(w_sec)}pt, height: {_f(h_sec)}pt, fill: rgb("#f2f2f2"), stroke: 1pt + black))'
|
|
)
|
|
add(
|
|
f" #place(dx: {_f(sx(inset))}pt, dy: {_f(sy(h - inset))}pt, "
|
|
f"rect(width: {_f((bw - 2.0 * inset) * s)}pt, height: {_f((h - 2.0 * inset) * s)}pt, "
|
|
f"radius: {_f(STIRRUP_RADIUS)}pt, stroke: {_f(STIRRUP_STROKE)}pt + black))"
|
|
)
|
|
|
|
for x_in in bottom:
|
|
r = bar_db / 2.0 * s
|
|
add(
|
|
f" #place(dx: {_f(sx(x_in) - r)}pt, dy: {_f(sy(y_bottom) - r)}pt, "
|
|
f"circle(radius: {_f(r)}pt, fill: black))"
|
|
)
|
|
for x_in in top:
|
|
r = top_bar_db / 2.0 * s
|
|
add(
|
|
f" #place(dx: {_f(sx(x_in) - r)}pt, dy: {_f(sy(top_y) - r)}pt, "
|
|
f"circle(radius: {_f(r)}pt, fill: black))"
|
|
)
|
|
|
|
dim_y = oy + h_sec + 16.0
|
|
add(
|
|
f" #place(line(start: ({_f(ox)}pt, {_f(dim_y)}pt), end: ({_f(ox + w_sec)}pt, {_f(dim_y)}pt), "
|
|
f"stroke: 0.6pt + black))"
|
|
)
|
|
for tick in (ox, ox + w_sec):
|
|
add(
|
|
f" #place(line(start: ({_f(tick)}pt, {_f(dim_y - 3)}pt), end: ({_f(tick)}pt, {_f(dim_y + 3)}pt), "
|
|
f"stroke: 0.6pt + black))"
|
|
)
|
|
add(
|
|
f" #place(dx: {_f(ox)}pt, dy: {_f(dim_y + 3)}pt, "
|
|
f'box(width: {_f(w_sec)}pt, align(center, text(size: 7pt)[$b_w = {_f(bw)} "in"$])))'
|
|
)
|
|
|
|
x_h = ox - 6.0
|
|
add(
|
|
f" #place(line(start: ({_f(x_h)}pt, {_f(oy)}pt), end: ({_f(x_h)}pt, {_f(oy + h_sec)}pt), "
|
|
f"stroke: 0.6pt + black))"
|
|
)
|
|
for tick in (oy, oy + h_sec):
|
|
add(
|
|
f" #place(line(start: ({_f(x_h - 3)}pt, {_f(tick)}pt), end: ({_f(x_h + 3)}pt, {_f(tick)}pt), "
|
|
f"stroke: 0.6pt + black))"
|
|
)
|
|
add(
|
|
f" #place(dx: 0.5pt, dy: {_f(oy + h_sec / 2.0 - 3)}pt, "
|
|
f'text(size: 7pt)[$h = {_f(h)} "in"$])'
|
|
)
|
|
|
|
label_x = ox + w_sec + 8.0
|
|
lead_x = ox + w_sec + 5.0
|
|
|
|
def leader(fx: float, fy: float, lx: float, ly: float) -> None:
|
|
add(
|
|
f" #place(line(start: ({_f(fx)}pt, {_f(fy)}pt), end: ({_f(lx)}pt, {_f(ly)}pt), "
|
|
f"stroke: 0.5pt + {MUTED}))"
|
|
)
|
|
add(f" #place(dx: {_f(fx - 1.5)}pt, dy: {_f(fy - 1.5)}pt, circle(radius: 1.5pt, fill: black))")
|
|
|
|
leader(sx(top[-1]), sy(top_y), lead_x, oy + 14.0)
|
|
add(
|
|
f" #place(dx: {_f(label_x)}pt, dy: {_f(oy + 9)}pt, "
|
|
f'text(size: 7pt, "({n_top_bars}) #{top_bar_size}"))'
|
|
)
|
|
|
|
leader(sx(bw - inset), sy(h / 2.0), lead_x, oy + h_sec / 2.0 - 3.0)
|
|
add(
|
|
f" #place(dx: {_f(label_x)}pt, dy: {_f(oy + h_sec / 2.0 - 8)}pt, "
|
|
f'text(size: 7pt, "#{stirrup_size} @ {_f(stirrup_spacing)}″"))'
|
|
)
|
|
|
|
leader(sx(bottom[-1]), sy(y_bottom), lead_x, oy + h_sec - 14.0)
|
|
add(
|
|
f" #place(dx: {_f(label_x)}pt, dy: {_f(oy + h_sec - 19)}pt, "
|
|
f'text(size: 7pt, "({n_bars}) #{bar_size}"))'
|
|
)
|
|
|
|
add(" ]")
|
|
add("}")
|
|
return "\n".join(lines) + "\n"
|
|
|
|
|
|
def write_fragment(values: dict, path: Path) -> None:
|
|
path.write_text(render(values), encoding="utf-8")
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
argv = sys.argv[1:] if argv is None else argv
|
|
input_path = Path(argv[0]) if argv else HERE / "input.yaml"
|
|
output_path = Path(argv[1]) if len(argv) > 1 else HERE / "assets" / "beam-section.typ"
|
|
|
|
import yaml
|
|
import calc
|
|
|
|
with input_path.open(encoding="utf-8") as handle:
|
|
result = calc.compute(yaml.safe_load(handle))
|
|
write_fragment(result["values"], output_path)
|
|
print(output_path)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|