Spaces:
Sleeping
Sleeping
Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,640 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from pint import UnitRegistry, set_application_registry
|
| 3 |
+
import matplotlib.pyplot as plt
|
| 4 |
+
import io
|
| 5 |
+
import base64
|
| 6 |
+
from sympy import symbols, Symbol, Eq, solve, Rational
|
| 7 |
+
from reportlab.lib.pagesizes import letter
|
| 8 |
+
from reportlab.pdfgen import canvas
|
| 9 |
+
from PIL import Image
|
| 10 |
+
import base64
|
| 11 |
+
import io
|
| 12 |
+
from reportlab.lib.utils import ImageReader
|
| 13 |
+
import os
|
| 14 |
+
import subprocess
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
# Initialize unit registry
|
| 19 |
+
u = UnitRegistry()
|
| 20 |
+
set_application_registry(u)
|
| 21 |
+
Q_ = u.Quantity
|
| 22 |
+
|
| 23 |
+
def generate_beam_diagram(n_spans, lengths, loads, moments, R_sx, R_dx,
|
| 24 |
+
cantilever_left_length=0 * u.meter, cantilever_left_load=0 * u.newton / u.meter,
|
| 25 |
+
cantilever_right_length=0 * u.meter, cantilever_right_load=0 * u.newton / u.meter,
|
| 26 |
+
unit_system='SI'):
|
| 27 |
+
# Define units and their abbreviations based on the unit system
|
| 28 |
+
if unit_system == 'SI':
|
| 29 |
+
length_unit = u.meter
|
| 30 |
+
load_unit = u.newton / u.meter
|
| 31 |
+
moment_unit = u.newton * u.meter
|
| 32 |
+
reaction_unit = u.newton
|
| 33 |
+
length_unit_str = 'm'
|
| 34 |
+
load_unit_str = 'N/m'
|
| 35 |
+
moment_unit_str = 'N·m'
|
| 36 |
+
reaction_unit_str = 'N'
|
| 37 |
+
length_display_unit = u.meter # For consistent plotting
|
| 38 |
+
else:
|
| 39 |
+
length_unit = u.foot
|
| 40 |
+
load_unit = u.pound_force / u.foot
|
| 41 |
+
moment_unit = u.pound_force * u.foot
|
| 42 |
+
reaction_unit = u.pound_force
|
| 43 |
+
length_unit_str = 'ft'
|
| 44 |
+
load_unit_str = 'lb/ft'
|
| 45 |
+
moment_unit_str = 'lb·ft'
|
| 46 |
+
reaction_unit_str = 'lb'
|
| 47 |
+
length_display_unit = u.foot # For consistent plotting
|
| 48 |
+
|
| 49 |
+
# Adjust lengths to include cantilevers
|
| 50 |
+
lengths_display = []
|
| 51 |
+
x_positions = [0]
|
| 52 |
+
# Left cantilever
|
| 53 |
+
if cantilever_left_length.magnitude > 0:
|
| 54 |
+
l_cant_left_display = cantilever_left_length.to(length_display_unit)
|
| 55 |
+
lengths_display.append(l_cant_left_display)
|
| 56 |
+
x_positions.append(x_positions[-1] + l_cant_left_display.magnitude)
|
| 57 |
+
# Main spans
|
| 58 |
+
for l in lengths:
|
| 59 |
+
l_display = l.to(length_display_unit)
|
| 60 |
+
lengths_display.append(l_display)
|
| 61 |
+
x_positions.append(x_positions[-1] + l_display.magnitude)
|
| 62 |
+
# Right cantilever
|
| 63 |
+
if cantilever_right_length.magnitude > 0:
|
| 64 |
+
l_cant_right_display = cantilever_right_length.to(length_display_unit)
|
| 65 |
+
lengths_display.append(l_cant_right_display)
|
| 66 |
+
x_positions.append(x_positions[-1] + l_cant_right_display.magnitude)
|
| 67 |
+
|
| 68 |
+
total_length = x_positions[-1]
|
| 69 |
+
|
| 70 |
+
fig, ax = plt.subplots(figsize=(10, 2))
|
| 71 |
+
|
| 72 |
+
# Draw the beam as a line
|
| 73 |
+
ax.hlines(0, 0, total_length, colors='black', linewidth=2)
|
| 74 |
+
|
| 75 |
+
# Draw supports
|
| 76 |
+
support_width = total_length / 50 # Adjust support width relative to total length
|
| 77 |
+
n_supports = n_spans + 1
|
| 78 |
+
support_positions = []
|
| 79 |
+
idx = 0
|
| 80 |
+
# Left support
|
| 81 |
+
if cantilever_left_length.magnitude > 0:
|
| 82 |
+
# Support at end of cantilever
|
| 83 |
+
x = x_positions[1]
|
| 84 |
+
support_positions.append(x)
|
| 85 |
+
ax.plot([x, x], [0, -0.1], color='black')
|
| 86 |
+
support = plt.Polygon([[x - support_width, -0.1],
|
| 87 |
+
[x + support_width, -0.1],
|
| 88 |
+
[x, -0.2]], color='black')
|
| 89 |
+
ax.add_patch(support)
|
| 90 |
+
idx = 2
|
| 91 |
+
else:
|
| 92 |
+
# Support at start
|
| 93 |
+
x = x_positions[0]
|
| 94 |
+
support_positions.append(x)
|
| 95 |
+
ax.plot([x, x], [0, -0.1], color='black')
|
| 96 |
+
support = plt.Polygon([[x - support_width, -0.1],
|
| 97 |
+
[x + support_width, -0.1],
|
| 98 |
+
[x, -0.2]], color='black')
|
| 99 |
+
ax.add_patch(support)
|
| 100 |
+
idx = 1
|
| 101 |
+
|
| 102 |
+
# Intermediate supports
|
| 103 |
+
for i in range(1, n_supports - 1):
|
| 104 |
+
x = x_positions[idx]
|
| 105 |
+
support_positions.append(x)
|
| 106 |
+
ax.plot([x, x], [0, -0.1], color='black')
|
| 107 |
+
support = plt.Polygon([[x - support_width, -0.1],
|
| 108 |
+
[x + support_width, -0.1],
|
| 109 |
+
[x, -0.2]], color='black')
|
| 110 |
+
ax.add_patch(support)
|
| 111 |
+
idx += 1
|
| 112 |
+
|
| 113 |
+
# Right support
|
| 114 |
+
if cantilever_right_length.magnitude > 0:
|
| 115 |
+
# Support before cantilever
|
| 116 |
+
x = x_positions[-2]
|
| 117 |
+
support_positions.append(x)
|
| 118 |
+
ax.plot([x, x], [0, -0.1], color='black')
|
| 119 |
+
support = plt.Polygon([[x - support_width, -0.1],
|
| 120 |
+
[x + support_width, -0.1],
|
| 121 |
+
[x, -0.2]], color='black')
|
| 122 |
+
ax.add_patch(support)
|
| 123 |
+
else:
|
| 124 |
+
# Support at end
|
| 125 |
+
x = x_positions[-1]
|
| 126 |
+
support_positions.append(x)
|
| 127 |
+
ax.plot([x, x], [0, -0.1], color='black')
|
| 128 |
+
support = plt.Polygon([[x - support_width, -0.1],
|
| 129 |
+
[x + support_width, -0.1],
|
| 130 |
+
[x, -0.2]], color='black')
|
| 131 |
+
ax.add_patch(support)
|
| 132 |
+
|
| 133 |
+
# Annotate reactions
|
| 134 |
+
for i, x in enumerate(support_positions):
|
| 135 |
+
# Left-side reaction
|
| 136 |
+
R_sx_value = R_sx[i]
|
| 137 |
+
R_sx_unit = R_sx_value.to(reaction_unit)
|
| 138 |
+
R_sx_num = round(R_sx_unit.magnitude, 6)
|
| 139 |
+
# Right-side reaction
|
| 140 |
+
R_dx_value = R_dx[i]
|
| 141 |
+
R_dx_unit = R_dx_value.to(reaction_unit)
|
| 142 |
+
R_dx_num = round(R_dx_unit.magnitude, 6)
|
| 143 |
+
# Display reactions with proper offsets to avoid overlap
|
| 144 |
+
ax.text(x, 0.15, f'$R_{{{i+1},\, \\mathrm{{sx}}}} = {R_sx_num}$ {reaction_unit_str}',
|
| 145 |
+
ha='center', va='bottom', color='green')
|
| 146 |
+
ax.text(x, 0.25, f'$R_{{{i+1},\, \\mathrm{{dx}}}} = {R_dx_num}$ {reaction_unit_str}',
|
| 147 |
+
ha='center', va='bottom', color='green')
|
| 148 |
+
|
| 149 |
+
# Annotate internal moments
|
| 150 |
+
for i, x in enumerate(support_positions):
|
| 151 |
+
M_value = moments[i]
|
| 152 |
+
M_unit = M_value.to(moment_unit)
|
| 153 |
+
M_num = round(M_unit.magnitude, 6)
|
| 154 |
+
ax.text(x, -0.25, f'$M_{{{i+1}}} = {M_num}$ {moment_unit_str}',
|
| 155 |
+
ha='center', va='top', color='blue')
|
| 156 |
+
|
| 157 |
+
# Remove axes
|
| 158 |
+
ax.axis('off')
|
| 159 |
+
plt.xlim(-0.05 * total_length, total_length * 1.05)
|
| 160 |
+
plt.ylim(-0.4, 0.4)
|
| 161 |
+
|
| 162 |
+
# Save plot to a buffer
|
| 163 |
+
buf = io.BytesIO()
|
| 164 |
+
plt.savefig(buf, format='png', bbox_inches='tight', dpi=150)
|
| 165 |
+
plt.close(fig)
|
| 166 |
+
buf.seek(0)
|
| 167 |
+
img_base64 = base64.b64encode(buf.getvalue()).decode('utf-8')
|
| 168 |
+
return f'<img src="data:image/png;base64,{img_base64}" alt="Beam Diagram"/>'
|
| 169 |
+
|
| 170 |
+
def calculate_reactions(n_spans, lengths, distributed_loads, moments,
|
| 171 |
+
cantilever_left_length=Q_(0.0, u.meter), cantilever_left_load=Q_(0.0, u.newton / u.meter),
|
| 172 |
+
cantilever_right_length=Q_(0.0, u.meter), cantilever_right_load=Q_(0.0, u.newton / u.meter)):
|
| 173 |
+
"""
|
| 174 |
+
Calculate reactions using Excel formulas and print torques:
|
| 175 |
+
r1_sx = (sx cantilever * weight)
|
| 176 |
+
r1_dx = (ln-1 * weight)/2 + (torque1 - torque2)/ln-1
|
| 177 |
+
r2_sx = (ln-1 * weight) - r(m-1)_dx
|
| 178 |
+
r2_dx = (ln-1 * weight)/2 + (torque_m - torque_m+1)/ln-1
|
| 179 |
+
And so on...
|
| 180 |
+
"""
|
| 181 |
+
n_supports = n_spans + 1
|
| 182 |
+
|
| 183 |
+
# Print all torques (moments)
|
| 184 |
+
print("\nTorques at each support:")
|
| 185 |
+
for i, moment in enumerate(moments):
|
| 186 |
+
print(f"Torque {i+1}: {moment}")
|
| 187 |
+
print("\n")
|
| 188 |
+
|
| 189 |
+
# Initialize reaction lists
|
| 190 |
+
R_sx = [Q_(0.0, 'newton') for _ in range(n_supports)]
|
| 191 |
+
R_dx = [Q_(0.0, 'newton') for _ in range(n_supports)]
|
| 192 |
+
|
| 193 |
+
# ---------------------------
|
| 194 |
+
# First support (m = 0)
|
| 195 |
+
# ---------------------------
|
| 196 |
+
print(f"Calculating R1:")
|
| 197 |
+
# r1_sx = (sx cantilever * weight)
|
| 198 |
+
if cantilever_left_length.magnitude > 0:
|
| 199 |
+
R_sx[0] = cantilever_left_load * cantilever_left_length
|
| 200 |
+
print(f"R1_sx = cantilever_load * cantilever_length = {R_sx[0]}")
|
| 201 |
+
|
| 202 |
+
# r1_dx = (l0 * w0)/2 + (torque1 - torque2)/l0
|
| 203 |
+
R_dx[0] = (distributed_loads[0] * lengths[0]) / 2 + \
|
| 204 |
+
(moments[0] - moments[1]) / lengths[0]
|
| 205 |
+
print(f"R1_dx = ({distributed_loads[0]} * {lengths[0]})/2 + ({moments[0]} - {moments[1]})/{lengths[0]} = {R_dx[0]}")
|
| 206 |
+
|
| 207 |
+
# ---------------------------
|
| 208 |
+
# Middle supports (1..n-1)
|
| 209 |
+
# ---------------------------
|
| 210 |
+
for m in range(1, n_supports - 1):
|
| 211 |
+
print(f"\nCalculating R{m+1}:")
|
| 212 |
+
# r(m)_sx = (l(m-1)*w(m-1)) - r(m-1)_dx
|
| 213 |
+
R_sx[m] = distributed_loads[m-1] * lengths[m-1] - R_dx[m-1]
|
| 214 |
+
print(f"R{m+1}_sx = {distributed_loads[m-1]} * {lengths[m-1]} - {R_dx[m-1]} = {R_sx[m]}")
|
| 215 |
+
|
| 216 |
+
# r(m)_dx = (l(m)*w(m))/2 + (torque_m - torque_(m+1))/l(m)
|
| 217 |
+
R_dx[m] = (distributed_loads[m] * lengths[m]) / 2 + \
|
| 218 |
+
(moments[m] - moments[m+1]) / lengths[m]
|
| 219 |
+
print(f"R{m+1}_dx = ({distributed_loads[m]} * {lengths[m]})/2 + ({moments[m]} - {moments[m+1]})/{lengths[m]} = {R_dx[m]}")
|
| 220 |
+
|
| 221 |
+
# ---------------------------
|
| 222 |
+
# Last support (m = n_supports-1)
|
| 223 |
+
# ---------------------------
|
| 224 |
+
m = n_supports - 1
|
| 225 |
+
print(f"\nCalculating R{m+1}:")
|
| 226 |
+
|
| 227 |
+
# Last left reaction
|
| 228 |
+
R_sx[m] = distributed_loads[m-1] * lengths[m-1] - R_dx[m-1]
|
| 229 |
+
print(f"R{m+1}_sx = {distributed_loads[m-1]} * {lengths[m-1]} - {R_dx[m-1]} = {R_sx[m]}")
|
| 230 |
+
|
| 231 |
+
# --- Key Fix: Force R_dx at the last support to always be 0 ---
|
| 232 |
+
R_dx[m] = Q_(0.0, 'newton')
|
| 233 |
+
print(f"R{m+1}_dx is forced to 0: {R_dx[m]}")
|
| 234 |
+
# --------------------------------------------------------------
|
| 235 |
+
|
| 236 |
+
# Print final summary of all reactions
|
| 237 |
+
print("\nFinal Reactions Summary:")
|
| 238 |
+
for i in range(n_supports):
|
| 239 |
+
print(f"R{i+1}_sx = {R_sx[i]}")
|
| 240 |
+
print(f"R{i+1}_dx = {R_dx[i]}")
|
| 241 |
+
print(f"R{i+1}_total = {R_sx[i] + R_dx[i]}\n")
|
| 242 |
+
|
| 243 |
+
return R_sx, R_dx
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
def continuous_beam_solver(unit_system, n_spans, lengths_str, loads_str,
|
| 249 |
+
cantilever_left_length_str='0', cantilever_left_load_str='0',
|
| 250 |
+
cantilever_right_length_str='0', cantilever_right_load_str='0'):
|
| 251 |
+
# Parse the input strings into lists
|
| 252 |
+
try:
|
| 253 |
+
n_spans = int(n_spans)
|
| 254 |
+
l_values = [float(val.strip()) for val in lengths_str.split(',')]
|
| 255 |
+
p_values = [float(val.strip()) for val in loads_str.split(',')]
|
| 256 |
+
cantilever_left_length = float(cantilever_left_length_str.strip())
|
| 257 |
+
cantilever_left_load = float(cantilever_left_load_str.strip())
|
| 258 |
+
cantilever_right_length = float(cantilever_right_length_str.strip())
|
| 259 |
+
cantilever_right_load = float(cantilever_right_load_str.strip())
|
| 260 |
+
except ValueError:
|
| 261 |
+
return "Invalid input. Please ensure all inputs are numbers.", "", "", "", "", ""
|
| 262 |
+
|
| 263 |
+
if len(l_values) != n_spans or len(p_values) != n_spans:
|
| 264 |
+
return "The number of lengths and loads must match the number of spans.", "", "", "", "", ""
|
| 265 |
+
|
| 266 |
+
n_supports = n_spans + 1 # Total number of supports
|
| 267 |
+
|
| 268 |
+
# Define units based on the selected unit system
|
| 269 |
+
if unit_system == 'SI':
|
| 270 |
+
length_unit = u.meter
|
| 271 |
+
load_unit = u.newton / u.meter
|
| 272 |
+
moment_unit = u.newton * u.meter
|
| 273 |
+
reaction_unit = u.newton
|
| 274 |
+
else:
|
| 275 |
+
length_unit = u.foot
|
| 276 |
+
load_unit = u.pound_force / u.foot
|
| 277 |
+
moment_unit = u.pound_force * u.foot
|
| 278 |
+
reaction_unit = u.pound_force
|
| 279 |
+
|
| 280 |
+
# Convert lengths and loads to quantities with units
|
| 281 |
+
l = [Q_(length, length_unit) for length in l_values]
|
| 282 |
+
p = [Q_(load, load_unit) for load in p_values]
|
| 283 |
+
|
| 284 |
+
# Convert lengths and loads to SI units for calculation
|
| 285 |
+
l_SI = [length.to(u.meter) for length in l]
|
| 286 |
+
p_SI = [load.to(u.newton / u.meter) for load in p]
|
| 287 |
+
|
| 288 |
+
# Process cantilever inputs
|
| 289 |
+
cantilever_left_length = Q_(cantilever_left_length, length_unit)
|
| 290 |
+
cantilever_left_load = Q_(cantilever_left_load, load_unit)
|
| 291 |
+
cantilever_right_length = Q_(cantilever_right_length, length_unit)
|
| 292 |
+
cantilever_right_load = Q_(cantilever_right_load, load_unit)
|
| 293 |
+
|
| 294 |
+
# Convert to SI units for calculations
|
| 295 |
+
cantilever_left_length_SI = cantilever_left_length.to(u.meter)
|
| 296 |
+
cantilever_left_load_SI = cantilever_left_load.to(u.newton / u.meter)
|
| 297 |
+
cantilever_right_length_SI = cantilever_right_length.to(u.meter)
|
| 298 |
+
cantilever_right_load_SI = cantilever_right_load.to(u.newton / u.meter)
|
| 299 |
+
|
| 300 |
+
# Initialize moments at supports
|
| 301 |
+
M_values_SI = []
|
| 302 |
+
M_values_Imperial = []
|
| 303 |
+
|
| 304 |
+
# Handle single-span beam separately
|
| 305 |
+
if n_spans == 1:
|
| 306 |
+
# Moments at supports A and B for a single span
|
| 307 |
+
M_cantilever_left = 0.0
|
| 308 |
+
if cantilever_left_length_SI.magnitude > 0 and cantilever_left_load_SI.magnitude != 0:
|
| 309 |
+
M_cantilever_left = (cantilever_left_load_SI * cantilever_left_length_SI**2 / 2).to(u.newton * u.meter).magnitude
|
| 310 |
+
|
| 311 |
+
M_cantilever_right = 0.0
|
| 312 |
+
if cantilever_right_length_SI.magnitude > 0 and cantilever_right_load_SI.magnitude != 0:
|
| 313 |
+
M_cantilever_right = (cantilever_right_load_SI * cantilever_right_length_SI**2 / 2).to(u.newton * u.meter).magnitude
|
| 314 |
+
|
| 315 |
+
# Assign moments for supports A and B
|
| 316 |
+
M_A = M_cantilever_left
|
| 317 |
+
M_B = M_cantilever_right
|
| 318 |
+
|
| 319 |
+
# Store the moments in lists
|
| 320 |
+
M_values_SI = [Q_(M_A, u.newton * u.meter), Q_(M_B, u.newton * u.meter)]
|
| 321 |
+
M_values_Imperial = [M.to(u.pound_force * u.foot) for M in M_values_SI]
|
| 322 |
+
|
| 323 |
+
# Calculate reactions
|
| 324 |
+
R_sx_SI, R_dx_SI = calculate_reactions(n_spans, l_SI, p_SI, M_values_SI)
|
| 325 |
+
|
| 326 |
+
# Convert reactions to Imperial units
|
| 327 |
+
R_sx_Imperial = [R.to(u.pound_force) for R in R_sx_SI]
|
| 328 |
+
R_dx_Imperial = [R.to(u.pound_force) for R in R_dx_SI]
|
| 329 |
+
|
| 330 |
+
# Prepare results
|
| 331 |
+
results_SI = ""
|
| 332 |
+
results_Imperial = ""
|
| 333 |
+
for i in range(n_supports):
|
| 334 |
+
M_value_SI = M_values_SI[i]
|
| 335 |
+
M_value_Imperial = M_values_Imperial[i]
|
| 336 |
+
results_SI += f"M_{i+1} = {M_value_SI.magnitude:.6f} N·m\n"
|
| 337 |
+
results_Imperial += f"M_{i+1} = {M_value_Imperial.magnitude:.6f} lb·ft\n"
|
| 338 |
+
|
| 339 |
+
# Generate beam diagrams for SI and Imperial units
|
| 340 |
+
beam_diagram_SI = generate_beam_diagram(
|
| 341 |
+
n_spans, l, p, M_values_SI, R_sx_SI, R_dx_SI,
|
| 342 |
+
cantilever_left_length=cantilever_left_length,
|
| 343 |
+
cantilever_left_load=cantilever_left_load,
|
| 344 |
+
cantilever_right_length=cantilever_right_length,
|
| 345 |
+
cantilever_right_load=cantilever_right_load,
|
| 346 |
+
unit_system='SI'
|
| 347 |
+
)
|
| 348 |
+
beam_diagram_Imperial = generate_beam_diagram(
|
| 349 |
+
n_spans, l, p, M_values_Imperial, R_sx_Imperial, R_dx_Imperial,
|
| 350 |
+
cantilever_left_length=cantilever_left_length,
|
| 351 |
+
cantilever_left_load=cantilever_left_load,
|
| 352 |
+
cantilever_right_length=cantilever_right_length,
|
| 353 |
+
cantilever_right_load=cantilever_right_load,
|
| 354 |
+
unit_system='Imperial'
|
| 355 |
+
)
|
| 356 |
+
|
| 357 |
+
# There are no complex equations for the single-span beam, so leave the equations blank.
|
| 358 |
+
equations_md = ""
|
| 359 |
+
return results_SI, results_Imperial, beam_diagram_SI, beam_diagram_Imperial, equations_md, ""
|
| 360 |
+
|
| 361 |
+
# For multiple spans
|
| 362 |
+
else:
|
| 363 |
+
# Compute fixed-end moments due to cantilever loads
|
| 364 |
+
M_cantilever_left = 0.0
|
| 365 |
+
if cantilever_left_length_SI.magnitude > 0 and cantilever_left_load_SI.magnitude != 0:
|
| 366 |
+
M_cantilever_left = (cantilever_left_load_SI * cantilever_left_length_SI**2 / 2).to(u.newton * u.meter).magnitude
|
| 367 |
+
|
| 368 |
+
M_cantilever_right = 0.0
|
| 369 |
+
if cantilever_right_length_SI.magnitude > 0 and cantilever_right_load_SI.magnitude != 0:
|
| 370 |
+
M_cantilever_right = (cantilever_right_load_SI * cantilever_right_length_SI**2 / 2).to(u.newton * u.meter).magnitude
|
| 371 |
+
|
| 372 |
+
# Initialize moments M_i (M_1 to M_{n_supports})
|
| 373 |
+
M_symbols = []
|
| 374 |
+
M_symbols.append(M_cantilever_left) # M_1
|
| 375 |
+
|
| 376 |
+
for i in range(1, n_supports - 1):
|
| 377 |
+
M_symbols.append(symbols(f'M_{i+1}')) # M_2 to M_{n_supports-1}
|
| 378 |
+
|
| 379 |
+
M_symbols.append(M_cantilever_right) # M_n
|
| 380 |
+
|
| 381 |
+
# Set up the system of equations
|
| 382 |
+
equations = []
|
| 383 |
+
equations_latex = []
|
| 384 |
+
for k in range(1, n_supports - 1):
|
| 385 |
+
# Indices for spans and supports
|
| 386 |
+
l_prev = l_SI[k - 1].magnitude # l_{k} in meters
|
| 387 |
+
l_curr = l_SI[k].magnitude # l_{k+1} in meters
|
| 388 |
+
p_prev = p_SI[k - 1].magnitude # p_{k} in N/m
|
| 389 |
+
p_curr = p_SI[k].magnitude # p_{k+1} in N/m
|
| 390 |
+
M_prev = M_symbols[k - 1] # M_{k}
|
| 391 |
+
M_curr = M_symbols[k] # M_{k+1}
|
| 392 |
+
M_next = M_symbols[k + 1] # M_{k+2}
|
| 393 |
+
|
| 394 |
+
# Left-hand side of the equation (N·m²)
|
| 395 |
+
lhs = (1/24) * (l_prev**3 * p_prev + l_curr**3 * p_curr)
|
| 396 |
+
|
| 397 |
+
# Right-hand side of the equation (N·m²)
|
| 398 |
+
rhs = (1/6) * (l_prev * M_prev + l_curr * M_next) + (1/3) * (l_prev + l_curr) * M_curr
|
| 399 |
+
|
| 400 |
+
# Form the equation
|
| 401 |
+
equation = Eq(lhs, rhs)
|
| 402 |
+
equations.append(equation)
|
| 403 |
+
|
| 404 |
+
# Convert equation to LaTeX for display
|
| 405 |
+
equation_latex = f"\\frac{{1}}{{24}}(l_{{{k}}}^3 p_{{{k}}} + l_{{{k+1}}}^3 p_{{{k+1}}}) = \\frac{{1}}{{6}}(l_{{{k}}} M_{{{k}}} + l_{{{k+1}}} M_{{{k+2}}}) + \\frac{{1}}{{3}}(l_{{{k}}} + l_{{{k+1}}}) M_{{{k+1}}}"
|
| 406 |
+
equations_latex.append(equation_latex)
|
| 407 |
+
|
| 408 |
+
# Solve the system of equations
|
| 409 |
+
unknown_M_symbols = [M_symbols[i] for i in range(
|
| 410 |
+
1, n_supports - 1) if isinstance(M_symbols[i], Symbol)]
|
| 411 |
+
|
| 412 |
+
solution = solve(equations, unknown_M_symbols, dict=True)
|
| 413 |
+
|
| 414 |
+
# Prepare results and collect moments for diagrams
|
| 415 |
+
if solution:
|
| 416 |
+
solution = solution[0] # Extract the solution dictionary
|
| 417 |
+
results_SI = ""
|
| 418 |
+
results_Imperial = ""
|
| 419 |
+
M_values_SI = []
|
| 420 |
+
M_values_Imperial = []
|
| 421 |
+
for i in range(n_supports):
|
| 422 |
+
M_i_value = M_symbols[i]
|
| 423 |
+
if isinstance(M_i_value, Symbol):
|
| 424 |
+
M_i_value = float(solution.get(M_i_value, 0))
|
| 425 |
+
else:
|
| 426 |
+
M_i_value = float(M_i_value)
|
| 427 |
+
|
| 428 |
+
# SI Units
|
| 429 |
+
M_quantity_SI = Q_(M_i_value, u.newton * u.meter)
|
| 430 |
+
M_values_SI.append(M_quantity_SI)
|
| 431 |
+
results_SI += f"M_{i+1} = {M_quantity_SI.magnitude:.6f} N·m\n"
|
| 432 |
+
# Imperial Units
|
| 433 |
+
M_quantity_Imperial = M_quantity_SI.to(u.pound_force * u.foot)
|
| 434 |
+
M_values_Imperial.append(M_quantity_Imperial)
|
| 435 |
+
results_Imperial += f"M_{i+1} = {M_quantity_Imperial.magnitude:.6f} lb·ft\n"
|
| 436 |
+
else:
|
| 437 |
+
return "No solution found.", "", "", "", "", ""
|
| 438 |
+
|
| 439 |
+
# Calculate reactions
|
| 440 |
+
R_sx_SI, R_dx_SI = calculate_reactions(n_spans, l_SI, p_SI, M_values_SI)
|
| 441 |
+
|
| 442 |
+
# Convert reactions to Imperial units
|
| 443 |
+
R_sx_Imperial = [R.to(u.pound_force) for R in R_sx_SI]
|
| 444 |
+
R_dx_Imperial = [R.to(u.pound_force) for R in R_dx_SI]
|
| 445 |
+
|
| 446 |
+
# Generate beam diagrams
|
| 447 |
+
beam_diagram_SI = generate_beam_diagram(
|
| 448 |
+
n_spans, l, p, M_values_SI, R_sx_SI, R_dx_SI,
|
| 449 |
+
cantilever_left_length=cantilever_left_length,
|
| 450 |
+
cantilever_left_load=cantilever_left_load,
|
| 451 |
+
cantilever_right_length=cantilever_right_length,
|
| 452 |
+
cantilever_right_load=cantilever_right_load,
|
| 453 |
+
unit_system='SI')
|
| 454 |
+
beam_diagram_Imperial = generate_beam_diagram(
|
| 455 |
+
n_spans, l, p, M_values_Imperial, R_sx_Imperial, R_dx_Imperial,
|
| 456 |
+
cantilever_left_length=cantilever_left_length,
|
| 457 |
+
cantilever_left_load=cantilever_left_load,
|
| 458 |
+
cantilever_right_length=cantilever_right_length,
|
| 459 |
+
cantilever_right_load=cantilever_right_load,
|
| 460 |
+
unit_system='Imperial')
|
| 461 |
+
|
| 462 |
+
# Prepare equations in LaTeX
|
| 463 |
+
equations_md = "\n\n".join(
|
| 464 |
+
[f"**Equation {i+1}:**\n\n$$ {eq} $$" for i, eq in enumerate(equations_latex)])
|
| 465 |
+
|
| 466 |
+
return results_SI, results_Imperial, beam_diagram_SI, beam_diagram_Imperial, equations_md, ""
|
| 467 |
+
|
| 468 |
+
|
| 469 |
+
|
| 470 |
+
# def add_image_to_pdf(canvas, image_data, x, y, max_width, max_height):
|
| 471 |
+
# """Helper function to add an image to the PDF canvas while preserving aspect ratio."""
|
| 472 |
+
# # Decode the base64 image data
|
| 473 |
+
# # image_data is like "data:image/png;base64,iVBOR..." so split off the header
|
| 474 |
+
# base64_data = image_data.split(",")[1]
|
| 475 |
+
# img_bytes = base64.b64decode(base64_data)
|
| 476 |
+
# img = Image.open(io.BytesIO(img_bytes))
|
| 477 |
+
|
| 478 |
+
# # Get the original size
|
| 479 |
+
# orig_width, orig_height = img.size
|
| 480 |
+
|
| 481 |
+
# # Compute a scale factor so that the image fits within max_width x max_height
|
| 482 |
+
# # while preserving aspect ratio
|
| 483 |
+
# scale = min(max_width / orig_width, max_height / orig_height)
|
| 484 |
+
|
| 485 |
+
# # Scaled dimensions
|
| 486 |
+
# display_width = orig_width * scale
|
| 487 |
+
# display_height = orig_height * scale
|
| 488 |
+
|
| 489 |
+
# # Convert the (scaled) PIL image to something reportlab can draw
|
| 490 |
+
# buffer = io.BytesIO()
|
| 491 |
+
# img.save(buffer, format="PNG")
|
| 492 |
+
# buffer.seek(0)
|
| 493 |
+
# img_reader = ImageReader(buffer)
|
| 494 |
+
|
| 495 |
+
# # Draw the image onto the canvas at (x, y), with the scaled width/height
|
| 496 |
+
# canvas.drawImage(img_reader, x, y, width=display_width, height=display_height)
|
| 497 |
+
|
| 498 |
+
|
| 499 |
+
# def create_pdf_report(filename, results_SI, results_Imperial, beam_diagram_SI, beam_diagram_Imperial, equations_md):
|
| 500 |
+
# """
|
| 501 |
+
# Creates a multi-page PDF:
|
| 502 |
+
# - Page 1: Title, summary, internal moments (SI & Imperial)
|
| 503 |
+
# - Page 2: SI beam diagram
|
| 504 |
+
# - Page 3: Imperial beam diagram
|
| 505 |
+
# - Page 4: Equations in LaTeX syntax (un-rendered, but still readable).
|
| 506 |
+
# """
|
| 507 |
+
# c = canvas.Canvas(filename, pagesize=letter)
|
| 508 |
+
# page_width, page_height = letter
|
| 509 |
+
|
| 510 |
+
# # -------------
|
| 511 |
+
# # PAGE 1: Title & Moments
|
| 512 |
+
# # -------------
|
| 513 |
+
# c.setFont("Helvetica-Bold", 16)
|
| 514 |
+
# c.drawString(30, page_height - 40, "Continuous Beam Analysis Report")
|
| 515 |
+
|
| 516 |
+
# # Description
|
| 517 |
+
# c.setFont("Helvetica", 12)
|
| 518 |
+
# c.drawString(30, page_height - 70, "This report contains a detailed analysis of a continuous beam, including:")
|
| 519 |
+
# c.drawString(50, page_height - 90, "- Internal moments at supports")
|
| 520 |
+
# c.drawString(50, page_height - 110, "- Beam diagrams (SI and Imperial)")
|
| 521 |
+
# c.drawString(50, page_height - 130, "- Equations used (in LaTeX)")
|
| 522 |
+
|
| 523 |
+
# # Internal Moments (SI)
|
| 524 |
+
# y_offset = page_height - 170
|
| 525 |
+
# c.setFont("Helvetica-Bold", 14)
|
| 526 |
+
# c.drawString(30, y_offset, "Internal Moments at Supports (SI Units):")
|
| 527 |
+
# y_offset -= 20
|
| 528 |
+
# c.setFont("Helvetica", 12)
|
| 529 |
+
# text_obj = c.beginText(30, y_offset)
|
| 530 |
+
# text_obj.textLines(results_SI)
|
| 531 |
+
# c.drawText(text_obj)
|
| 532 |
+
|
| 533 |
+
# # Internal Moments (Imperial)
|
| 534 |
+
# y_offset -= 20 + 14 * (results_SI.count("\n") + 1) # move down after SI text
|
| 535 |
+
# c.setFont("Helvetica-Bold", 14)
|
| 536 |
+
# c.drawString(30, y_offset, "Internal Moments at Supports (Imperial Units):")
|
| 537 |
+
# y_offset -= 20
|
| 538 |
+
# c.setFont("Helvetica", 12)
|
| 539 |
+
# text_obj = c.beginText(30, y_offset)
|
| 540 |
+
# text_obj.textLines(results_Imperial)
|
| 541 |
+
# c.drawText(text_obj)
|
| 542 |
+
|
| 543 |
+
# # Finish Page 1
|
| 544 |
+
# c.showPage()
|
| 545 |
+
|
| 546 |
+
# # -------------
|
| 547 |
+
# # PAGE 2: SI Diagram
|
| 548 |
+
# # -------------
|
| 549 |
+
# c.setFont("Helvetica-Bold", 14)
|
| 550 |
+
# c.drawString(30, page_height - 40, "Beam Diagram (SI Units)")
|
| 551 |
+
# c.setFont("Helvetica", 12)
|
| 552 |
+
# # You could add more descriptive text here if desired.
|
| 553 |
+
|
| 554 |
+
# # Place the SI diagram, preserving aspect ratio
|
| 555 |
+
# if beam_diagram_SI:
|
| 556 |
+
# max_w = 500
|
| 557 |
+
# max_h = 400
|
| 558 |
+
# # 30 points from left, 100 points from bottom
|
| 559 |
+
# add_image_to_pdf(c, beam_diagram_SI, 30, page_height - 100 - max_h, max_w, max_h)
|
| 560 |
+
|
| 561 |
+
# c.showPage()
|
| 562 |
+
|
| 563 |
+
# # -------------
|
| 564 |
+
# # PAGE 3: Imperial Diagram
|
| 565 |
+
# # -------------
|
| 566 |
+
# c.setFont("Helvetica-Bold", 14)
|
| 567 |
+
# c.drawString(30, page_height - 40, "Beam Diagram (Imperial Units)")
|
| 568 |
+
# c.setFont("Helvetica", 12)
|
| 569 |
+
|
| 570 |
+
# # Place the Imperial diagram, preserving aspect ratio
|
| 571 |
+
# if beam_diagram_Imperial:
|
| 572 |
+
# max_w = 500
|
| 573 |
+
# max_h = 400
|
| 574 |
+
# add_image_to_pdf(c, beam_diagram_Imperial, 30, page_height - 100 - max_h, max_w, max_h)
|
| 575 |
+
|
| 576 |
+
# c.showPage()
|
| 577 |
+
|
| 578 |
+
# # -------------
|
| 579 |
+
# # PAGE 4: Equations in LaTeX
|
| 580 |
+
# # -------------
|
| 581 |
+
# c.setFont("Helvetica-Bold", 16)
|
| 582 |
+
# c.drawString(30, page_height - 40, "Equations Used in Analysis (LaTeX):")
|
| 583 |
+
# c.setFont("Helvetica", 12)
|
| 584 |
+
|
| 585 |
+
# y_offset = page_height - 70
|
| 586 |
+
# text_obj = c.beginText(30, y_offset)
|
| 587 |
+
|
| 588 |
+
# # Here, we do NOT strip out the $$ or **, so the raw LaTeX is visible
|
| 589 |
+
# lines = equations_md.split("\n")
|
| 590 |
+
# text_obj.textLines(lines)
|
| 591 |
+
# c.drawText(text_obj)
|
| 592 |
+
|
| 593 |
+
# # Finish the PDF
|
| 594 |
+
# c.save()
|
| 595 |
+
|
| 596 |
+
def gradio_interface(unit_system, n_spans, lengths_str, loads_str,
|
| 597 |
+
cantilever_left_length, cantilever_left_load,
|
| 598 |
+
cantilever_right_length, cantilever_right_load):
|
| 599 |
+
# Call continuous beam solver to get results
|
| 600 |
+
results_SI, results_Imperial, beam_diagram_SI, beam_diagram_Imperial, equations_md, pdf_filename = continuous_beam_solver(
|
| 601 |
+
unit_system, n_spans, lengths_str, loads_str,
|
| 602 |
+
cantilever_left_length, cantilever_left_load,
|
| 603 |
+
cantilever_right_length, cantilever_right_load)
|
| 604 |
+
|
| 605 |
+
# # Create the PDF report
|
| 606 |
+
# pdf_filename = "continuous_beam_analysis_report.pdf"
|
| 607 |
+
# create_pdf_report(pdf_filename, results_SI, results_Imperial, beam_diagram_SI, beam_diagram_Imperial, equations_md)
|
| 608 |
+
|
| 609 |
+
return results_SI, results_Imperial, beam_diagram_SI, beam_diagram_Imperial, equations_md # ,pdf_filename
|
| 610 |
+
|
| 611 |
+
iface = gr.Interface(
|
| 612 |
+
fn=gradio_interface,
|
| 613 |
+
inputs=[
|
| 614 |
+
gr.Radio(['SI', 'Imperial'], label="Unit System", value='SI'),
|
| 615 |
+
gr.Number(label="Number of Spans (n)", value=3, precision=0),
|
| 616 |
+
gr.Textbox(label="Lengths l_i (comma-separated)", placeholder="e.g., 5, 5, 5", value='7.91667,7.91667,7.91667'),
|
| 617 |
+
gr.Textbox(label="Loads p_i (comma-separated)", placeholder="e.g., 10000, 10000, 10000", value='200,200,200'),
|
| 618 |
+
gr.Textbox(label="Cantilever Left Length", placeholder="e.g., 2.0", value='6.66667'),
|
| 619 |
+
gr.Textbox(label="Cantilever Left Load", placeholder="e.g., 5000", value='200'),
|
| 620 |
+
gr.Textbox(label="Cantilever Right Length", placeholder="e.g., 0", value='6.66667'),
|
| 621 |
+
gr.Textbox(label="Cantilever Right Load", placeholder="e.g., 0", value='200'),
|
| 622 |
+
],
|
| 623 |
+
outputs=[
|
| 624 |
+
gr.Textbox(label="Internal Moments at Supports (SI Units)"),
|
| 625 |
+
gr.Textbox(label="Internal Moments at Supports (Imperial Units)"),
|
| 626 |
+
gr.HTML(label="Beam Diagram (SI Units)"),
|
| 627 |
+
gr.HTML(label="Beam Diagram (Imperial Units)"),
|
| 628 |
+
gr.Markdown(label="Equations Used"),
|
| 629 |
+
# gr.File(label="Download Report")
|
| 630 |
+
],c
|
| 631 |
+
title="Continuous Beam Solver with Cantilevers",
|
| 632 |
+
description="Solve for internal moments at supports of a continuous beam with multiple spans, including cantilevers.\n"
|
| 633 |
+
"Select the unit system for input. The results will be displayed in both SI and Imperial units.\n\n"
|
| 634 |
+
"The beam diagrams and equations used will be displayed below.",
|
| 635 |
+
allow_flagging="never",
|
| 636 |
+
)
|
| 637 |
+
|
| 638 |
+
|
| 639 |
+
if __name__ == "__main__":
|
| 640 |
+
iface.launch()
|