# -*- 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' 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')