def draw_beams(self, bridge: BridgeCalculator): for beam, beam_property in bridge.bridge.beams.items(): self.draw_line(self.scale_point(beam.joint1), self.scale_point(beam.joint2), color=beam_property.beam_group.color) if beam_property.member_force is not None: label_position = Vector.from_point( self.scale_point( beam.joint2)) + BridgeGUI.flip_vector_on_y( Vector.from_a_to_b(beam.joint2, beam.joint1) ) / 2 * self.scale_factor self.draw_label(label_position, beam_property.member_force.rescale(kN))
def get_direction_vector(self) -> Vector: """ Note that this function can return different direction vectors depending on the order of joint1 and joint2 """ return Vector.from_a_to_b(self.joint1, self.joint2)
def calculate_member_forces(self): # Loop through every joint repeatedly. # At each joint look for member forces + external forces + joint load # In each component, verify if there's only one unknown_opposing_joints. Repeat in other component if solved # Repeat for other joints passes = 0 calculated_joints = set() while passes < len(self.bridge.joints) * 2 and len(calculated_joints) < len(self.bridge.joints): for joint, joint_property in self.bridge.joints.items(): if joint in calculated_joints: continue sum_of_forces = Vector(0 * pq.N, 0 * pq.N) unknown_opposing_joints = [] # Get forces in members for connected_joint in joint_property.connected_joints: direction_vector = Vector.from_a_to_b(joint, connected_joint) member_force = self.bridge.beams[Beam(joint, connected_joint)].member_force if member_force is None: unknown_opposing_joints.append(connected_joint) else: sum_of_forces += direction_vector.get_unit_vector() * member_force if joint_property.external_force is not None: sum_of_forces += joint_property.external_force if len(unknown_opposing_joints) > 3: continue # If all forces are known make sure sum is zero and you're done elif len(unknown_opposing_joints) == 0: if sum_of_forces != Vector(0, 0): print(f"ERROR: Sum of forces at joint, {joint}, is {sum_of_forces} not (0, 0).") calculated_joints.add(joint) # If only one force make sure it's opposite to the current sum of forces. elif len(unknown_opposing_joints) == 1: unknown_opposing_joint = unknown_opposing_joints[0] direction_vector = Vector.from_a_to_b(joint, unknown_opposing_joint) if sum_of_forces == Vector(0, 0): self.bridge.beams[Beam(unknown_opposing_joint, joint)].member_force = 0 * pq.N elif sum_of_forces.is_collinear(direction_vector): self.bridge.beams[Beam(unknown_opposing_joint, joint)].member_force = sum_of_forces.cos_theta( direction_vector) * sum_of_forces.get_magnitude() * -1 else: print( f"Error. Sum of forces ({sum_of_forces})" f" is not in the same direction as the only unknown beam (dir: {direction_vector})" f" for joint {joint}.") calculated_joints.add(joint) elif len(unknown_opposing_joints) == 2: unknown_joint_1 = unknown_opposing_joints.pop() unknown_joint_2 = unknown_opposing_joints.pop() unknown_force_1 = Vector.from_a_to_b(joint, unknown_joint_1) unknown_force_2 = Vector.from_a_to_b(joint, unknown_joint_2) if unknown_force_1.is_collinear(unknown_force_2): continue (force_1, force_2) = BridgeCalculator.solve_for_two_unknowns(sum_of_forces, unknown_force_1, unknown_force_2) self.bridge.beams[Beam(joint, unknown_joint_1)].member_force = force_1 self.bridge.beams[Beam(joint, unknown_joint_2)].member_force = force_2 calculated_joints.add(joint) elif len(unknown_opposing_joints) == 3: unknown_joint_1 = unknown_opposing_joints.pop() unknown_joint_2 = unknown_opposing_joints.pop() unknown_joint_3 = unknown_opposing_joints.pop() unknown_force_1 = Vector.from_a_to_b(joint, unknown_joint_1) unknown_force_2 = Vector.from_a_to_b(joint, unknown_joint_2) unknown_force_3 = Vector.from_a_to_b(joint, unknown_joint_3) if unknown_force_1.is_collinear(unknown_force_2): (force_1, force_3) = BridgeCalculator.solve_for_two_unknowns(sum_of_forces, unknown_force_1, unknown_force_3) self.bridge.beams[Beam(joint, unknown_joint_3)].member_force = force_3 elif unknown_force_2.is_collinear(unknown_force_3): (force_1, force_2) = BridgeCalculator.solve_for_two_unknowns(sum_of_forces, unknown_force_1, unknown_force_2) self.bridge.beams[Beam(joint, unknown_joint_1)].member_force = force_1 elif unknown_force_3.is_collinear(unknown_force_1): (force_1, force_2) = BridgeCalculator.solve_for_two_unknowns(sum_of_forces, unknown_force_1, unknown_force_2) self.bridge.beams[Beam(joint, unknown_joint_2)].member_force = force_2 passes += 1