| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- # -*- coding: utf-8 -*-
- """
- Лаба 3, рисунок «Поперечное сечение обделки» (вариант 6).
- Геометрия по расчёту: l0 = 9550, f0 = 4244,4, r0 = 4808,2 мм (внутреннее
- очертание, центр под линией пяты); наружный свод r1 = 5836,8 из центра
- (0; f0 + hз - r1); пята hп = 980 по нормали, стена hст = 1120,
- обрез фундамента hо = 1400, обратный свод hл = 560, проезжая часть B = 8000.
- """
- import numpy as np
- import matplotlib
- matplotlib.use('Agg')
- import matplotlib.pyplot as plt
- # Чертёжный шрифт ГОСТ 2.304-81 тип А (прямой, из системных шрифтов Windows)
- import matplotlib.font_manager as fm
- fm.fontManager.addfont('C:/Windows/Fonts/GOST2304A.ttf')
- matplotlib.rcParams['font.family'] = 'GOST 2.304 type A'
- matplotlib.rcParams['mathtext.default'] = 'regular'
- matplotlib.rcParams['mathtext.fontset'] = 'custom'
- matplotlib.rcParams['mathtext.rm'] = 'GOST 2.304 type A'
- matplotlib.rcParams['mathtext.it'] = 'GOST 2.304 type A'
- matplotlib.rcParams['mathtext.bf'] = 'GOST 2.304 type A'
- L0, F0, R0 = 9550.0, 4244.4, 4808.2
- R1, HZ, HP, HST, HO, HL = 5836.8, 700.0, 1120.0 - 140.0, 1120.0, 1400.0, 560.0
- HP = 980.0
- G, HT = 8000.0, 80.0
- Y_OB = -600.0 # обрез фундамента
- Y_POD = Y_OB - HO # подошва выработки
- THR = np.arccos((R0 - F0) / R0) # угол пяты внутреннего контура (рад)
- C0 = np.array([0.0, F0 - R0])
- C1 = np.array([0.0, F0 + HZ - R1])
- U = np.array([np.sin(THR), np.cos(THR)]) # направление радиуса пяты
- P_IN = C0 + R0 * U
- P_OUT = C0 + (R0 + HP) * U
- X_WI, X_WO = P_IN[0], P_OUT[0] + HST * 0.0 + (HST - (P_OUT[0] - P_IN[0]))
- # наружная грань стены: от пяты (x = P_OUT[0], y = P_OUT[1]) вниз до обреза с
- # уширением до толщины HST по горизонтали у обреза
- X_WO_B = X_WI + HST
- F_IN, F_OUT = X_WI - 130.0, X_WO_B + 130.0 # грани фундамента
- EC = '#111111'
- def arc(c, r, t0, t1, n=140):
- t = np.linspace(np.radians(t0), np.radians(t1), n)
- return np.column_stack([c[0] + r * np.sin(t), c[1] + r * np.cos(t)])
- th_in = np.degrees(THR) # ~83.27
- th_out = np.degrees(np.arctan2(*(P_OUT - C1)[[1, 0]] * np.array([1, 1]))) if False else \
- np.degrees(np.arctan2(P_OUT[0] - C1[0], P_OUT[1] - C1[1]))
- inner_vault = arc(C0, R0, -th_in, th_in) # слева -> направо
- outer_vault = arc(C1, R1, -th_out, th_out)
- fig = plt.figure(figsize=(17.2 / 2.54, 9.6 / 2.54), dpi=250)
- matplotlib.rcParams['hatch.linewidth'] = 0.45
- ax = fig.add_axes([0, 0, 1, 1])
- ax.set_aspect('equal'); ax.axis('off')
- ax.set_xlim(-8600, 8900)
- ax.set_ylim(-2450, 5750)
- def poly(pts, hatch=None, fc='0.93', lw=1.7, z=2):
- p = np.asarray(pts)
- ax.fill(p[:, 0], p[:, 1], facecolor=fc, edgecolor=EC, lw=lw,
- hatch=hatch, zorder=z, closed=True)
- # --- А. кольцо свода со стенами ------------------------------------------------
- right_wall_out = np.array([P_OUT, [X_WO_B, Y_OB]])
- ring = np.vstack([
- outer_vault, # левая пята -> замок -> правая пята
- right_wall_out, # наружная грань правой стены
- [[X_WI, Y_OB]], # по обрезу внутрь
- [[P_IN[0], P_IN[1]]], # внутренняя грань правой стены вверх
- inner_vault[::-1], # внутренний свод справа -> налево
- [[-P_IN[0], P_IN[1]]], # левая стена вниз
- [[-X_WI, Y_OB]], # по обрезу наружу
- [[-X_WO_B, Y_OB], [-P_OUT[0], P_OUT[1]]] # наружная грань левой стены вверх
- ])
- poly(ring, hatch='////', z=2)
- # --- Б. фундаменты --------------------------------------------------------------
- poly([[F_IN, Y_OB], [F_OUT, Y_OB], [F_OUT, Y_POD], [F_IN, Y_POD]],
- hatch='\\\\\\\\', z=2)
- poly([[-F_IN, Y_OB], [-F_OUT, Y_OB], [-F_OUT, Y_POD], [-F_IN, Y_POD]],
- hatch='\\\\\\\\', z=2)
- # --- В. обратный свод ------------------------------------------------------------
- A_INV, F_INV = F_IN, 550.0 # полупролёт и стрела внутреннего свода
- R_INV = (A_INV ** 2 + F_INV ** 2) / (2 * F_INV)
- Y_INV_END = Y_OB - 100.0 # пята обратного свода на грани фундамента
- CY_INV = (Y_INV_END - F_INV) + R_INV # центр выше низа свода
- xi = np.linspace(-A_INV, A_INV, 120)
- inner_inv = np.column_stack([xi, CY_INV - np.sqrt(R_INV ** 2 - xi ** 2)])
- xo = np.linspace(-A_INV, A_INV, 120)
- outer_inv = np.column_stack([xo, inner_inv[:, 1][::-1] * 0 + (inner_inv[:, 1] - HL)[::-1]])
- outer_inv = np.column_stack([xo, inner_inv[:, 1] - HL])
- poly(np.vstack([inner_inv, [[A_INV, Y_INV_END]], outer_inv[::-1],
- [[-A_INV, Y_INV_END]]]), hatch='////', z=2)
- Y_BASE = Y_OB - 200.0 # низ основания проезжей части
- x_edge = np.sqrt(R_INV ** 2 - (CY_INV - Y_BASE) ** 2) # сопряжение с обратным сводом
- # щебёночная отсыпка между основанием проезжей части и обратным сводом:
- # линза с лёгкой заливкой и россыпью округлых камешков (как гравий на образце)
- m_lens = np.abs(xi) <= x_edge + 0.5
- lens = np.vstack([[-G / 2, Y_BASE], np.column_stack([xi[m_lens], inner_inv[m_lens, 1]]),
- [G / 2, Y_BASE]])
- poly(lens, fc='0.97', lw=0.9, z=2)
- rng = np.random.default_rng(6)
- def y_inv_at(x):
- return CY_INV - np.sqrt(R_INV ** 2 - x ** 2)
- for y_row, half, step, r_lo, r_hi in ((-875.0, 3400.0, 240.0, 40.0, 58.0),
- (-975.0, 2850.0, 260.0, 65.0, 105.0),
- (-1120.0, 1300.0, 240.0, 65.0, 100.0)):
- for xs in np.arange(-half, half + 1, step):
- xc = xs + rng.uniform(-60, 60)
- yc = y_row + rng.uniform(-25, 25)
- r0s = rng.uniform(r_lo, r_hi)
- hh = r0s * 0.72
- if yc - hh < y_inv_at(xc) + 12 or yc + hh > Y_BASE - 12:
- continue
- t = np.linspace(0, 2 * np.pi, 40)
- phi = rng.uniform(0, np.pi)
- rr = r0s * (1 + 0.05 * np.sin(2 * t + rng.uniform(0, 2 * np.pi)))
- px = xc + rr * np.cos(t) * np.cos(phi) - rr * 0.72 * np.sin(t) * np.sin(phi)
- py = yc + rr * np.cos(t) * np.sin(phi) + rr * 0.72 * np.sin(t) * np.cos(phi)
- ax.add_patch(plt.Polygon(np.column_stack([px, py]), closed=True,
- fc='white', ec=EC, lw=0.5, zorder=3))
- # --- Г. сточный треугольник и основание ------------------------------------------
- # проезжая часть доведена до внутренних граней фундаментов, низ повторяет свод
- y_in_full = CY_INV - np.sqrt(R_INV ** 2 - xi ** 2)
- bottom = np.maximum(y_in_full, Y_BASE)
- poly(np.vstack([[-F_IN, Y_OB], [F_IN, Y_OB],
- np.column_stack([xi[::-1], bottom[::-1]])]),
- hatch='....', fc='0.97', lw=1.1, z=2)
- poly([[-F_IN, Y_OB], [0, Y_OB + HT], [F_IN, Y_OB]], hatch='....', fc='0.97',
- lw=1.1, z=2)
- ax.plot([-F_IN, 0, F_IN], [Y_OB, Y_OB + HT, Y_OB], color=EC, lw=2.2, zorder=3)
- # --- ось тоннеля -------------------------------------------------------------------
- ax.plot([0, 0], [-2300, 5450], color='0.2', lw=0.7, ls=(0, (14, 4, 2, 4)), zorder=1)
- # --- размеры: засечки 45°, выносные с выступом, число у размерной линии ----------
- TICK = 120.0 # полудлина засечки
- EXT = 150.0 # выступ выносной линии за размерную
- GAP = 140.0 # зазор числа от размерной линии
- def tick(x, y, color=EC):
- ax.plot([x - TICK, x + TICK], [y - TICK, y + TICK], color=color, lw=1.5,
- solid_capstyle='butt', zorder=4)
- def dim_h(y, x1, x2, text, color=EC, above=True, fs=9.0):
- ax.plot([x1, x2], [y, y], color=color, lw=1.0, zorder=4)
- tick(x1, y, color); tick(x2, y, color)
- # белая подложка: ось тоннеля и выносные линии не проходят сквозь текст
- ax.text((x1 + x2) / 2, y + (GAP if above else -GAP), text, fontsize=fs,
- ha='center', va='bottom' if above else 'top', color=color,
- bbox=dict(facecolor='white', edgecolor='none', pad=1.2))
- def dim_v(x, y1, y2, text, color=EC, side='left', fs=9.0, gap=GAP):
- ax.plot([x, x], [y1, y2], color=color, lw=1.0, zorder=4)
- tick(x, y1, color); tick(x, y2, color)
- ax.text(x + (-gap if side == 'left' else gap), (y1 + y2) / 2, text, fontsize=fs,
- ha='center', va='center', color=color, rotation=90)
- def leader(xt, yt, xa, ya, text, ha='left', color=EC, fs=9.0):
- # выноска с полкой: единая ломаная от элемента к полке, текст над полкой
- shelf = 1050.0 if ha == 'left' else -1050.0
- ax.plot([xa, xt, xt + shelf], [ya, yt, yt], color=color, lw=0.7, zorder=3)
- ax.text(xt + (0.09 if ha == 'left' else -0.09) * shelf, yt + 90, text,
- fontsize=fs, ha=ha, va='bottom', color=color)
- # l0 — пролёт в свету: выносные от пят вниз с выступом
- dim_h(1050, -X_WI, X_WI, 'l$_0$ = 9550')
- ax.plot([X_WI, X_WI], [P_IN[1], 1050 - EXT], color='0.4', lw=0.5)
- ax.plot([-X_WI, -X_WI], [P_IN[1], 1050 - EXT], color='0.4', lw=0.5)
- # f0 — стрела подъёма в свету: выносные от пяты и замка влево с выступом
- dim_v(-2350, 0, F0, 'f$_0$ = 4244', side='right', gap=340)
- ax.plot([-X_WI, -2350 - EXT], [0, 0], color='0.4', lw=0.5)
- ax.plot([0, -2350 - EXT], [F0, F0], color='0.4', lw=0.5)
- # hз — замок: короткий размер, подпись над верхней засечкой; выносные от обоих
- # уровней замка (внутреннего и наружного очертаний)
- dim_v(-3450, F0, F0 + HZ, '')
- ax.text(-3450, F0 + HZ + 240, 'h$_з$ = 700', fontsize=9.0, ha='center', va='bottom')
- ax.plot([0, -3450 - EXT], [F0 + HZ, F0 + HZ], color='0.4', lw=0.5)
- ax.plot([0, -3450 - EXT], [F0, F0], color='0.4', lw=0.5)
- # B — проезжая часть: выносные от краёв вверх с выступом
- dim_h(-420, -G / 2, G / 2, 'B = 8000', above=True)
- ax.plot([-G / 2, -G / 2], [Y_OB, -420 + EXT], color='0.4', lw=0.5)
- ax.plot([G / 2, G / 2], [Y_OB, -420 + EXT], color='0.4', lw=0.5)
- # hт — сточный треугольник
- leader(3300, -120, 2400, Y_OB + HT * 0.55, 'h$_т$ = 80', ha='left')
- # r0, r1 — радиусы; тексты — вдоль своих радиусных линий
- rad0 = np.radians(38)
- u0 = np.array([np.sin(rad0), np.cos(rad0)])
- c0m = C0 + R0 * u0
- ax.plot([C0[0], c0m[0]], [C0[1], c0m[1]], color=EC, lw=0.8)
- ax.annotate('', xy=c0m, xytext=C0 + 780 * u0,
- arrowprops=dict(arrowstyle='-|>', color=EC, lw=0.9, mutation_scale=10))
- p_t0 = C0 + 3150 * u0 + 170 * np.array([-np.cos(rad0), np.sin(rad0)])
- ax.text(p_t0[0], p_t0[1], 'r$_0$ = 4808', fontsize=9.0, rotation=90 - 38,
- ha='center', va='center',
- bbox=dict(facecolor='white', edgecolor='none', pad=1.0))
- ax.plot(*C0, marker='+', ms=9, color=EC, mew=1.2)
- rad1 = np.radians(-63)
- u1 = np.array([np.sin(rad1), np.cos(rad1)])
- c1m = C1 + R1 * u1
- ax.plot([C1[0], c1m[0]], [C1[1], c1m[1]], color=EC, lw=0.8)
- ax.annotate('', xy=c1m, xytext=C1 + 900 * u1,
- arrowprops=dict(arrowstyle='-|>', color=EC, lw=0.9, mutation_scale=10))
- d1 = u1 # единичное направление радиуса r1
- x_t1 = -3900.0
- p_t1 = np.array([x_t1, C1[1] + (x_t1 - C1[0]) / d1[0] * d1[1]])
- p_t1 = p_t1 + 170 * np.array([-d1[1], -d1[0]])
- rot1 = np.degrees(np.arctan2(d1[1], d1[0])) - 180.0
- ax.text(p_t1[0], p_t1[1], 'r$_1$ = 5837', fontsize=9.0, rotation=rot1,
- ha='center', va='center',
- bbox=dict(facecolor='white', edgecolor='none', pad=1.0))
- ax.plot(*C1, marker='+', ms=9, color=EC, mew=1.2)
- # hп — пята по нормали (правая)
- n_off = np.array([np.cos(THR), -np.sin(THR)]) * 120
- a1 = C0 + (R0 + 60) * U + n_off
- a2 = C0 + (R0 + HP - 60) * U + n_off
- ax.plot([a1[0], a2[0]], [a1[1], a2[1]], color=EC, lw=0.8, zorder=4)
- tick(a1[0], a1[1]); tick(a2[0], a2[1])
- mid = (a1 + a2) / 2 + np.array([620, -80])
- ax.text(mid[0], mid[1], 'h$_п$ = 980', fontsize=9.0, ha='left', va='center',
- bbox=dict(facecolor='white', edgecolor='none', pad=1.0))
- # выносные: стена, фундамент, обратный свод
- # точка выноски h_ст — на наклонной наружной грани стены, выше засечек размера h_п
- t_w = 0.35
- w_pt = np.array([P_OUT[0] + t_w * (X_WO_B - P_OUT[0]), P_OUT[1] + t_w * (Y_OB - P_OUT[1])])
- leader(6800, 1100, w_pt[0], w_pt[1], 'h$_с$$_т$ = 1120', ha='left')
- # h_о — высота обреза фундамента: вертикальная размерная справа от фундамента
- xd_o = F_OUT + 300
- ax.plot([F_OUT, xd_o + EXT], [Y_OB, Y_OB], color='0.4', lw=0.5)
- ax.plot([F_OUT, xd_o + EXT], [Y_POD, Y_POD], color='0.4', lw=0.5)
- dim_v(xd_o, Y_POD, Y_OB, 'h$_о$ = 1400', side='right', gap=330)
- # h_л — толщина обратного свода: вертикальный размер, засечки на поверхностях свода
- x_l = 1500.0
- y_in = CY_INV - np.sqrt(R_INV ** 2 - x_l ** 2)
- dim_v(x_l, y_in - HL, y_in, '')
- ax.text(x_l + 180, y_in - HL - 60, 'h$_л$ = 560', fontsize=9.0, ha='left', va='top')
- fig.savefig('assets/images/laba3-obdelka.png', dpi=250, facecolor='white')
- print('сохранено: assets/images/laba3-obdelka.png')
|