'rectangular_cs.py' in 'hoehenberechnungstool.py' umbenannt. 'rectangular_cs' war ursprünglich nur für die Berechnung der Höhen von rechteckigen Querschnitten ('rectangular cross sections') gedacht. Im Laufe der Entwicklung des Rietergerüstes haben sich rechteckige Profilquerschnitte jedoch nicht als zielführend erwiesen.
This commit is contained in:
@@ -0,0 +1,508 @@
|
||||
from matplotlib import pyplot as plt
|
||||
from matplotlib.widgets import Slider
|
||||
from matplotlib.ticker import FormatStrFormatter
|
||||
from math import floor, ceil
|
||||
import ctypes
|
||||
|
||||
|
||||
class ProfileHeights:
|
||||
|
||||
# Ortsfaktor = Universalwert
|
||||
_location_factor = 9.81 # m/s^2
|
||||
|
||||
# Sicherheitsfaktor gemäß Bauvorschrift
|
||||
safety_factor = 1.7
|
||||
|
||||
# Fahrstreckengewichte nach Produktprogramm "OMNIFLO"
|
||||
_rail_masses = {"AP110": 1.94, # K: Art-Nr. 821106001 - V: in kg
|
||||
"APG110": 1.66, # K: Art-Nr. 821106002 - V: in kg
|
||||
"APS110": 3.89, # K: Art-Nr. 821716001 - V: in kg
|
||||
"AP60": 1.46 # K: Art-Nr. 821096001 - V: in kg
|
||||
}
|
||||
|
||||
# Spulenzugsegment-Gewichte nach CAD
|
||||
_train_segment_masses = {"T165": 0.38, # K: Art.-Nr. 826906201 - V: in kg
|
||||
"T210": 0.248, # K: Art.-Nr. 826906213 - V: in kg
|
||||
"T225": 0.355 # K: Art.-Nr. 826906200 - V: in kg
|
||||
}
|
||||
|
||||
def __init__(self,
|
||||
cross_section_type,
|
||||
cross_section_width,
|
||||
cross_section_thickness,
|
||||
has_two_supports,
|
||||
beam_length,
|
||||
individual_rail_positions=None,
|
||||
individual_rail_forces=None,
|
||||
rail_type="AP110",
|
||||
min_rail_distance=200,
|
||||
min_pillar_distance=300,
|
||||
material_yield_strength=235,
|
||||
bobbin_train_segment_type="T165",
|
||||
bobbin_mass=4,
|
||||
colum_row_distance=3600,
|
||||
pillar_width=100
|
||||
):
|
||||
|
||||
self.min_rail_distance = min_rail_distance
|
||||
self.min_dist_first_rail_to_pillar = min_pillar_distance
|
||||
self.cross_section_type = cross_section_type
|
||||
self.cross_section_width = cross_section_width
|
||||
self.cross_section_thickness = cross_section_thickness
|
||||
self.individual_rail_forces = individual_rail_forces
|
||||
self.has_two_supports = has_two_supports
|
||||
self.beam_length = beam_length
|
||||
self.material_yield_strength = material_yield_strength
|
||||
self.column_row_distance = colum_row_distance
|
||||
self.rail_type = rail_type
|
||||
self.individual_rail_positions = individual_rail_positions
|
||||
self.pillar_width = pillar_width
|
||||
self.rail_dist_from_support_a = self._set_rail_dist_from_support_a(individual_rail_positions)
|
||||
self.train_segment_type = bobbin_train_segment_type
|
||||
self.single_bobbin_mass = bobbin_mass
|
||||
self.train_segment_mass = self._set_train_segment_mass()
|
||||
self.rail_mass = self._set_rail_mass()
|
||||
self.rail_forces = self._set_rail_forces()
|
||||
self.bend_moments_from_a = self._summed_bend_moment_from_a()
|
||||
self.support_bending_moment = self._set_support_a_bending_moment()
|
||||
self.transverse_force_support_b = self._set_transverse_force_support_b()
|
||||
self.transverse_force_support_a = self._set_transverse_force_support_a()
|
||||
self._section_starts = self._set_beam_section_start_positions()
|
||||
self.all_force_positions = self._set_all_force_positions()
|
||||
self._beam_section_lengths = self._set_beam_section_lengths()
|
||||
self._beam_section_forces = self._set_section_forces()
|
||||
self.allowed_bend_stress = self._set_allowed_bend_stress()
|
||||
self.bending_moments = self._set_bending_moments()
|
||||
self.heights = self.all_profile_heights()
|
||||
|
||||
def _set_rail_dist_from_support_a(self, individual_rail_positions):
|
||||
# Gibt Abstände zwischen den einzelnen AP-Profilen am Träger und der Säule zurück.
|
||||
# Wenn 2 Säulen gegeben → Abstände zur "linken" Säule
|
||||
|
||||
# Fall 1: Es wurden keine individuellen Abstände zwischen den AP-Profilen und der Säule definiert.
|
||||
# In diesem Fall berechnet die Methode die Abstände der AP-Schienen vom Lager "A" ausgehend unter
|
||||
# Berücksichtigung der Mindestabstände zwischen den Schienen sowie zur Säule am Träger hängen kann.
|
||||
|
||||
if individual_rail_positions is None:
|
||||
|
||||
if self.has_two_supports:
|
||||
distance_first_to_last_rail = (self.beam_length - self.pillar_width - 2 * self.min_dist_first_rail_to_pillar)
|
||||
rail_amount = ceil(distance_first_to_last_rail / self.min_rail_distance)
|
||||
distance_two_rails = distance_first_to_last_rail / (rail_amount - 1)
|
||||
else:
|
||||
distance_first_to_last_rail = self.beam_length - self.pillar_width / 2 - self.min_dist_first_rail_to_pillar
|
||||
rail_amount = ceil(distance_first_to_last_rail / self.min_rail_distance)
|
||||
distance_two_rails = distance_first_to_last_rail / (rail_amount - 1)
|
||||
return [(self.min_dist_first_rail_to_pillar + self.pillar_width / 2) + (i * distance_two_rails) for i in range(rail_amount)]
|
||||
|
||||
# Fall 2: Es wurden individuelle Abstände zwischen den Lasten und der Säule definiert.
|
||||
return self.individual_rail_positions
|
||||
|
||||
def _set_rail_forces(self):
|
||||
# Gibt die Kräfte der einzelnen Fahrschienen am Träger zurück
|
||||
|
||||
# Fall 1: Es wurden keine individuellen Kräfte für die einzelnen Fahrschienen definiert.
|
||||
# Methode berechnet dann für alle Fahrstrecken dieselbe Kraft.
|
||||
if self.individual_rail_forces is None:
|
||||
single_rail_force = ((self.train_segment_mass + self.rail_mass) * ProfileHeights._location_factor)
|
||||
return [single_rail_force] * len(self.rail_dist_from_support_a)
|
||||
|
||||
# Fall 2: Es wurden individuelle Kräfte für die einzelnen Fahrstrecken definiert.
|
||||
# Methode gibt die individuellen Kräfte unverändert zurück
|
||||
return self.individual_rail_forces
|
||||
|
||||
def _set_train_segment_mass(self):
|
||||
# Methode ermittelt das Spulenzuggewicht zwischen zwei Säulenreihen
|
||||
|
||||
bobbin_amount_per_meter = floor(1000 / int(self.train_segment_type.replace("T", ""))) # Anzahl Spulen pro Meter
|
||||
|
||||
bobbin_mass_per_meter = self.single_bobbin_mass * bobbin_amount_per_meter # Gesamtes Spulengewicht pro Meter
|
||||
total_segment_mass_per_meter = 2 * ProfileHeights._train_segment_masses[self.train_segment_type] + bobbin_mass_per_meter
|
||||
return total_segment_mass_per_meter * (self.column_row_distance / 1000) / 2 # kg pro Säulenreihe
|
||||
|
||||
def _set_rail_mass(self):
|
||||
# Berechnet gesamtes Fahrstreckengewicht für Länge (Abstand) zwischen Säulenreihen zurück.
|
||||
return ProfileHeights._rail_masses[self.rail_type] * self.column_row_distance / 1000
|
||||
|
||||
def _summed_bend_moment_from_a(self):
|
||||
# Berechnet Gesamtmoment (Summe der Einzelmomente) am Balken vom Lager "A" ausgehend
|
||||
return sum([force * distance for force, distance in zip(self.rail_forces, self.rail_dist_from_support_a)])
|
||||
|
||||
def _set_support_a_bending_moment(self):
|
||||
# Berechnet Biegemoment im Lager "A", wenn Lager "A" ein dreiwertiges Lager ist (feste Einspannung)
|
||||
if not self.has_two_supports:
|
||||
return self.bend_moments_from_a
|
||||
return 0
|
||||
|
||||
def _set_transverse_force_support_a(self):
|
||||
# Berechnet Querkraft im Lager "A"
|
||||
return abs(self.transverse_force_support_b - sum(self.rail_forces))
|
||||
|
||||
def _set_transverse_force_support_b(self):
|
||||
# Berechnet Querkraft im Lager "B", wenn sowohl Lager "A", als auch Lager "B" existiert (nur bei Stützträgern)
|
||||
if self.has_two_supports:
|
||||
return self.bend_moments_from_a / self.beam_length
|
||||
return 0
|
||||
|
||||
def _set_beam_section_start_positions(self):
|
||||
# Bestimmt den Abstand der Bereichsanfänge zum Lager "A"
|
||||
section_start_positions = self.rail_dist_from_support_a.copy()
|
||||
section_start_positions.insert(0, 0)
|
||||
return section_start_positions
|
||||
|
||||
def _set_section_forces(self):
|
||||
# Fügt Querkraft im Lager "A" hinzu, da immer linkes Schnittufer betrachtet wird.
|
||||
# Dies ist notwendig, da Querkraft "A" im Flächenschwerpunkt des Schnittes in allen Trägerbereichen ein
|
||||
# Moment erzeugt
|
||||
section_forces = self.rail_forces.copy()
|
||||
section_forces.insert(0, self.transverse_force_support_a)
|
||||
return section_forces
|
||||
|
||||
def _set_all_force_positions(self):
|
||||
if self.has_two_supports:
|
||||
all_force_positions = self._section_starts.copy()
|
||||
all_force_positions.insert(len(all_force_positions), self.beam_length)
|
||||
return all_force_positions
|
||||
return self._section_starts
|
||||
|
||||
def all_forces(self):
|
||||
all_forces = self._beam_section_forces.copy()
|
||||
all_forces.insert(len(self.all_force_positions), self.transverse_force_support_b)
|
||||
return all_forces
|
||||
|
||||
def _set_beam_section_lengths(self):
|
||||
# Bereichslänge = Differenz zwischen nächster Kraftposition und vorherigen Kraftposition
|
||||
return [new_pos - old_pos for new_pos, old_pos in zip(self.all_force_positions[1:], self.all_force_positions)]
|
||||
|
||||
def _set_bending_moments(self):
|
||||
# Methode unterteilt Träger in Bereiche (vom linken Lager "A" ausgehend zum rechten Lager "b") und gibt die
|
||||
# Schnittreaktionen (konkret Biegemomente) zurück. Aus diesen wird der Momentenverlauf gebildet.
|
||||
|
||||
section_bending_moments = []
|
||||
subsection_lengths = self._beam_section_lengths.copy()
|
||||
|
||||
for i, (section_start, section_length) in enumerate(zip(self._section_starts, self._beam_section_lengths)):
|
||||
|
||||
section_moment = (self._beam_section_forces[0] * (section_start + section_length) - self.support_bending_moment)
|
||||
summed_subsection_lengths = 0
|
||||
|
||||
for subsection_length, force in zip(subsection_lengths[:i], self._beam_section_forces[1:]):
|
||||
summed_subsection_lengths += subsection_length
|
||||
section_moment -= force * (section_start - summed_subsection_lengths + section_length)
|
||||
|
||||
section_bending_moments.append(abs(round((section_moment / 1000), 2)))
|
||||
|
||||
if self.has_two_supports:
|
||||
section_bending_moments.insert(0, 0.0)
|
||||
else:
|
||||
section_bending_moments.insert(0, self.support_bending_moment / 1000)
|
||||
|
||||
return section_bending_moments
|
||||
|
||||
def reference_moment_of_resistance(self, bending_moment):
|
||||
# Funktion berechnet Referenz-Widerstandsmoment für die aktuelle Trägerlänge
|
||||
return bending_moment / self.allowed_bend_stress
|
||||
|
||||
def _set_allowed_bend_stress(self):
|
||||
return (self.material_yield_strength * 1.2) / ProfileHeights.safety_factor
|
||||
|
||||
def recalculated_moment_of_resistance(self, height):
|
||||
# Aktuelle Profilhöhe wird zur Ermittlung des derzeitigen Widerstandsmoments in die Widerstandsmoment-Formeln
|
||||
# der unterschiedlichen Querschnittsarten eingesetzt.
|
||||
|
||||
inner_width = self.cross_section_width - 2 * self.cross_section_thickness
|
||||
inner_height = height - 2 * self.cross_section_thickness
|
||||
bar_width = self.cross_section_width - self.cross_section_thickness
|
||||
|
||||
# 1. Idealisiertes rechteckiges Hohlprofil:
|
||||
if self.cross_section_type == "Hohlprofil":
|
||||
return (self.cross_section_width * height ** 3 - inner_width * inner_height ** 3) / (6 * height)
|
||||
|
||||
# 2. Idealisiertes IPE-Profil / C-Profil:
|
||||
elif self.cross_section_type in ["C-Profil", "IPE"]:
|
||||
return (self.cross_section_width * height ** 3 - bar_width * inner_height ** 3) / (6 * height)
|
||||
|
||||
def all_profile_heights(self):
|
||||
heights = []
|
||||
|
||||
bending_moments_converted = [i * 1000 for i in self.bending_moments] # Umrechnung von Nm in Nmm
|
||||
|
||||
for bending_moment, force_position in zip(bending_moments_converted, self.all_force_positions):
|
||||
reference_moment_of_resistance = self.reference_moment_of_resistance(abs(bending_moment))
|
||||
recalculated_moment_of_resistance = 0
|
||||
height = 2 * self.cross_section_thickness
|
||||
|
||||
while recalculated_moment_of_resistance < reference_moment_of_resistance:
|
||||
recalculated_moment_of_resistance = self.recalculated_moment_of_resistance(height)
|
||||
height += 0.01
|
||||
heights.append(height)
|
||||
return heights
|
||||
|
||||
def current_value(self, current_beam_length, elements):
|
||||
for i, force_position in enumerate(self.all_force_positions):
|
||||
if current_beam_length <= force_position:
|
||||
# m = Steigung, x = aktuelle Länge im derzeitigen Bereich, t = Höhe bei Bereichsbeginn
|
||||
m = (elements[i] - elements[i - 1]) / self._beam_section_lengths[i - 1]
|
||||
x = current_beam_length - self.all_force_positions[i - 1]
|
||||
t = elements[i - 1]
|
||||
return m * x + t
|
||||
|
||||
|
||||
height_1 = ProfileHeights(cross_section_type="Hohlprofil",
|
||||
cross_section_width=50,
|
||||
cross_section_thickness=3,
|
||||
individual_rail_positions=[200, 500, 700, 1100],
|
||||
individual_rail_forces=[500, 500, 500, 500],
|
||||
beam_length=1200,
|
||||
min_rail_distance=200,
|
||||
has_two_supports=True)
|
||||
|
||||
|
||||
# ===========================================================================================================================
|
||||
# = PLOTTEN =
|
||||
# ===========================================================================================================================
|
||||
|
||||
# Monitordaten für Figure-Größe
|
||||
user32 = ctypes.windll.user32
|
||||
user32.SetProcessDPIAware()
|
||||
monitor_width = user32.GetSystemMetrics(0)
|
||||
monitor_height = user32.GetSystemMetrics(1)
|
||||
dpi = 120
|
||||
|
||||
fig, (ax_drawing, ax_bending_moment, ax_heights) = plt.subplots(nrows=3, ncols=1, sharex=True, figsize=(monitor_width / dpi, monitor_height / dpi))
|
||||
|
||||
# Globale Einstellungen
|
||||
ax_drawing.set_title("Tool zur Bestimmung der Mindestquerschnittshöhe eines Profilträgers", fontsize=20)
|
||||
subplot_adjust_left = 0.1
|
||||
plt.subplots_adjust(left=subplot_adjust_left, right=1 - subplot_adjust_left, top=1 - subplot_adjust_left, bottom=subplot_adjust_left, hspace=0)
|
||||
|
||||
# Abszisseneinstellungen
|
||||
x_min_val = -(max(height_1.all_force_positions) * 0.1)
|
||||
x_max_val = max(height_1.all_force_positions) * 1.1
|
||||
|
||||
ax_heights.set_xlim(x_min_val, x_max_val)
|
||||
ax_heights.set_xticks(height_1.all_force_positions)
|
||||
ax_heights.xaxis.set_major_formatter(FormatStrFormatter("%.1f"))
|
||||
|
||||
# Einstellungen Biegemoment-Plot
|
||||
ax_bending_moment.set_ylabel("Biegemoment [Nm]")
|
||||
ax_bending_moment_y_max = max(height_1.bending_moments) * 1.25
|
||||
ax_bending_moment.set_ylim(0, ax_bending_moment_y_max)
|
||||
|
||||
# Einstellungen Profilhöhen-Plot
|
||||
ax_heights.set_xlabel("Kraftpositionen [mm]")
|
||||
ax_heights.set_ylabel("Benötigte Profilhöhe [mm]")
|
||||
|
||||
ax_heights_y_max = max(height_1.heights) * 1.25
|
||||
ax_heights.set_ylim(0, ax_heights_y_max)
|
||||
ax_heights.set_xticks(height_1.all_force_positions)
|
||||
|
||||
# Berechnet horizontale Pixelanzahl der Plots
|
||||
x_plot_px_count = monitor_width * (1 - 2 * subplot_adjust_left)
|
||||
|
||||
# Rechnet Längen der x-Achse in Pixel um (wie viele Pixel sind 1 mm?).
|
||||
# Wichtig, damit die Pfeillängen der Kräfte unabhängig von der Länge des Balkens immer gleich lang dargestellt werden.
|
||||
mm_in_px_converter = (abs(x_min_val) + abs(x_max_val)) / x_plot_px_count
|
||||
|
||||
|
||||
# ===========================================================================================================================
|
||||
# = Zeichnung =
|
||||
# ===========================================================================================================================
|
||||
|
||||
# Extremwerte der Zeichnungsordinate:
|
||||
y_max_drawing = 300
|
||||
ax_drawing.set_ylim(0, y_max_drawing)
|
||||
ax_drawing.set_yticks([])
|
||||
|
||||
# Darstellung eines schematischen Trägers:
|
||||
beam_y_pos_in_plot = y_max_drawing * 0.35
|
||||
ax_drawing.hlines(beam_y_pos_in_plot, height_1.all_force_positions[0], height_1.all_force_positions[len(height_1.all_force_positions) - 1],
|
||||
color="black", linewidth=3)
|
||||
|
||||
force_arrow_length = 0.5 * beam_y_pos_in_plot
|
||||
|
||||
|
||||
def draw_transverse_force(x_pos, y_beam_pos, arrow_length, support_name):
|
||||
|
||||
# Darstellung des Balkenendes als Punkt mit Lagerbenennung
|
||||
ax_drawing.plot(x_pos, y_beam_pos, "o", color="black")
|
||||
|
||||
# Pfeildarstellung für Querkraft
|
||||
ax_drawing.annotate('', xytext=(x_pos, y_beam_pos), xycoords='data', xy=(x_pos, y_beam_pos - arrow_length), textcoords='data',
|
||||
arrowprops=dict(color="red", width=1, headwidth=6))
|
||||
|
||||
# Pfeilbeschreibung:
|
||||
if support_name == "A":
|
||||
txt_alignment = "left"
|
||||
txt_x_offset = -120
|
||||
name_x_offset = -50
|
||||
name_y_offset = 15
|
||||
transverse_force = height_1.transverse_force_support_a
|
||||
else:
|
||||
txt_alignment = "left"
|
||||
txt_x_offset = 20
|
||||
name_x_offset = 20
|
||||
name_y_offset = 15
|
||||
transverse_force = height_1.transverse_force_support_b
|
||||
|
||||
# Plottet Querkraft-Wert entweder am Festlager "A", oder am Loslager "B"
|
||||
ax_drawing.annotate(f"F{support_name}y: {transverse_force:.0f}N", xy=(x_pos, y_beam_pos - arrow_length),
|
||||
xycoords='data', xytext=(txt_x_offset, 0), textcoords='offset pixels', horizontalalignment=txt_alignment)
|
||||
|
||||
# Plottet Lagerbezeichnung
|
||||
ax_drawing.annotate(f"{support_name}", xy=(x_pos, y_beam_pos), xycoords='data', xytext=(name_x_offset, name_y_offset),
|
||||
textcoords='offset pixels', ha=txt_alignment, fontsize=20)
|
||||
|
||||
|
||||
def draw_fixed_support(y_beam_pos, px_amount_per_mm, arrow_length, support_name):
|
||||
# Querkraft:
|
||||
draw_transverse_force(x_pos=height_1.all_force_positions[0], y_beam_pos=y_beam_pos,
|
||||
arrow_length=arrow_length, support_name=support_name)
|
||||
|
||||
# Normalkraft:
|
||||
x_arrow_length = px_amount_per_mm * arrow_length
|
||||
ax_drawing.annotate('', xycoords='data', xytext=(height_1.all_force_positions[0], y_beam_pos), xy=(-x_arrow_length, y_beam_pos),
|
||||
textcoords='data', arrowprops=dict(color="red", width=1, headwidth=6))
|
||||
|
||||
|
||||
def draw_couple(y_beam_pos, px_amount_per_mm, arrow_length, support_name):
|
||||
# Feste Einspannung
|
||||
draw_fixed_support(y_beam_pos=y_beam_pos, px_amount_per_mm=px_amount_per_mm, arrow_length=arrow_length, support_name=support_name)
|
||||
|
||||
# Plottet Querkraft-Pfeil entweder am Festlager "A", oder am Loslager "B"
|
||||
ax_drawing.annotate(f"M1: {(height_1.support_bending_moment / 1000):.0f} Nm", xy=(height_1.all_force_positions[0], y_beam_pos - arrow_length),
|
||||
xycoords='data', xytext=(-120, -20), textcoords='offset pixels', horizontalalignment="left")
|
||||
|
||||
ax_drawing.plot([height_1.all_force_positions[0] - 2.5], [y_beam_pos], marker=r'$\circlearrowright$', ms=30, color="red")
|
||||
|
||||
|
||||
def drawing_dimensions(y_pos_beam, px_amount_per_mm, arrow_length):
|
||||
dim_line_distance_from_beam = 70
|
||||
dim_line_y_pos = y_pos_beam + dim_line_distance_from_beam
|
||||
dim_leader_extension = 20
|
||||
|
||||
for i, (force_pos, force) in enumerate(zip(height_1.all_force_positions, height_1.all_forces())):
|
||||
# Darstellung Maßhilfslinien
|
||||
ax_drawing.vlines(force_pos, y_pos_beam, dim_line_y_pos + dim_leader_extension, colors="black", linewidth=1)
|
||||
|
||||
if height_1.has_two_supports:
|
||||
end_index = len(height_1.all_force_positions) - 1
|
||||
else:
|
||||
end_index = len(height_1.all_force_positions)
|
||||
|
||||
if 0 < i < end_index:
|
||||
# Kraftpfeile
|
||||
# Pfeildarstellung
|
||||
ax_drawing.annotate('', xycoords='data', xytext=(height_1.all_force_positions[i], beam_y_pos_in_plot + arrow_length),
|
||||
xy=(height_1.all_force_positions[i], beam_y_pos_in_plot), textcoords='data',
|
||||
arrowprops=dict(color="red", width=1, headwidth=6))
|
||||
|
||||
# Pfeilbeschreibung
|
||||
ax_drawing.annotate(f'F{i}:\n{force:.1f}N', xy=(force_pos, y_pos_beam - arrow_length), xycoords='data', xytext=(0, 0),
|
||||
textcoords='offset pixels', horizontalalignment="center", fontsize=10)
|
||||
|
||||
if i < (len(height_1.all_force_positions) - 1):
|
||||
# Darstellung Maßlinien
|
||||
ax_drawing.annotate('', xy=(height_1.all_force_positions[i], dim_line_y_pos), xycoords='data',
|
||||
xytext=(height_1.all_force_positions[i + 1], dim_line_y_pos), textcoords='data', arrowprops={'arrowstyle': '<->'})
|
||||
|
||||
# Darstellung Maße (Bereichslängen)
|
||||
section_length = (height_1.all_force_positions[i + 1] - force_pos)
|
||||
dim_x_pos = (section_length / 2) / px_amount_per_mm
|
||||
ax_drawing.annotate(f'{section_length:.1f}', xy=(force_pos, dim_line_y_pos), xycoords='data', xytext=(dim_x_pos, 5),
|
||||
textcoords='offset pixels', horizontalalignment="center")
|
||||
|
||||
|
||||
drawing_dimensions(y_pos_beam=beam_y_pos_in_plot, px_amount_per_mm=mm_in_px_converter, arrow_length=force_arrow_length)
|
||||
|
||||
if height_1.has_two_supports:
|
||||
draw_transverse_force(x_pos=height_1.all_force_positions[len(height_1.all_force_positions) - 1], y_beam_pos=beam_y_pos_in_plot,
|
||||
arrow_length=force_arrow_length, support_name="B")
|
||||
|
||||
draw_fixed_support(y_beam_pos=beam_y_pos_in_plot, px_amount_per_mm=mm_in_px_converter, arrow_length=force_arrow_length, support_name="A")
|
||||
else:
|
||||
draw_couple(y_beam_pos=beam_y_pos_in_plot, px_amount_per_mm=mm_in_px_converter, arrow_length=force_arrow_length, support_name="A")
|
||||
|
||||
|
||||
# ===========================================================================================================================
|
||||
# = Höhe und Biegemoment =
|
||||
# ===========================================================================================================================
|
||||
|
||||
|
||||
def text_alignment():
|
||||
if height_1.has_two_supports:
|
||||
return "center"
|
||||
return "left"
|
||||
|
||||
|
||||
def plot_bending_moment():
|
||||
|
||||
# Momentenlinie
|
||||
ax_bending_moment.plot(height_1.all_force_positions, height_1.bending_moments, color="black")
|
||||
ax_bending_moment.fill_between(height_1.all_force_positions, height_1.bending_moments, hatch="/", facecolor="#FFFFFF")
|
||||
|
||||
# Maximalmoment
|
||||
bending_moments_and_beam_lengths = dict(zip(height_1.bending_moments, height_1.all_force_positions))
|
||||
max_bending_moment = max(bending_moments_and_beam_lengths.keys())
|
||||
len_at_max_bending_moment = bending_moments_and_beam_lengths[max_bending_moment]
|
||||
text = f"max: {round(max_bending_moment, 2)} Nm"
|
||||
|
||||
ax_bending_moment.plot(len_at_max_bending_moment, max_bending_moment, "o", color="black")
|
||||
|
||||
ax_bending_moment.annotate(text, xy=(len_at_max_bending_moment, max_bending_moment), xytext=(0, 10), textcoords='offset points',
|
||||
horizontalalignment=text_alignment())
|
||||
|
||||
|
||||
def plot_heights():
|
||||
|
||||
# Hauptplot
|
||||
ax_heights.plot(height_1.all_force_positions, height_1.heights, color="black",
|
||||
label=f"{height_1.cross_section_type} - Breite: {height_1.cross_section_width} mm")
|
||||
ax_heights.fill_between(height_1.all_force_positions, height_1.heights, hatch="/", facecolor="#FFFFFF")
|
||||
|
||||
# Plot Maximalhöhe
|
||||
heights_and_beam_lengths = dict(zip(height_1.heights, height_1.all_force_positions))
|
||||
max_height = max(heights_and_beam_lengths.keys())
|
||||
beam_length_at_max_height = heights_and_beam_lengths[max_height]
|
||||
text = f"max: {max_height:.2f} mm"
|
||||
|
||||
ax_heights.plot(beam_length_at_max_height, max_height, "o", color="black")
|
||||
ax_heights.annotate(text, xy=(beam_length_at_max_height, max_height), xytext=(0, 10), textcoords='offset points',
|
||||
horizontalalignment=text_alignment())
|
||||
|
||||
ax_heights.legend(loc=1)
|
||||
|
||||
|
||||
def update_slider_length(current_length):
|
||||
ax_heights.clear()
|
||||
ax_bending_moment.clear()
|
||||
|
||||
plot_heights()
|
||||
current_height = round(height_1.current_value(current_length, height_1.heights), 2)
|
||||
current_bending_moment = round(height_1.current_value(current_length, height_1.bending_moments), 2)
|
||||
|
||||
# Plot aktuelle Höhe
|
||||
plot_bending_moment()
|
||||
ax_heights.plot(current_length, current_height, "o", color="black")
|
||||
ax_heights.annotate(current_height, xy=(current_length, current_height), xytext=(0, 7), textcoords='offset points',
|
||||
horizontalalignment="center")
|
||||
|
||||
# Plot aktuelles Moment
|
||||
ax_bending_moment.plot(current_length, current_bending_moment, "o", color="black")
|
||||
ax_bending_moment.annotate(current_bending_moment, xy=(current_length, current_bending_moment), xytext=(0, 7), textcoords='offset points',
|
||||
horizontalalignment="center")
|
||||
|
||||
ax_heights.vlines(current_length, 0, max(height_1.heights) * 1.25, color="gray", linewidth=1)
|
||||
ax_bending_moment.vlines(current_length, 0, max(height_1.bending_moments) * 1.25, color="gray", linewidth=1)
|
||||
|
||||
plt.draw()
|
||||
|
||||
|
||||
plot_bending_moment()
|
||||
plot_heights()
|
||||
|
||||
ax_slider = plt.axes([0.125, 0.0025, 0.775, 0.05], facecolor="blue")
|
||||
slider = Slider(ax_slider, "Trägerlänge", valmin=0, valmax=height_1.beam_length, valstep=1, valinit=0)
|
||||
slider.on_changed(update_slider_length)
|
||||
|
||||
plt.show()
|
||||
Reference in New Issue
Block a user