509 lines
25 KiB
Python
509 lines
25 KiB
Python
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()
|