def output_to_svg(circle: Circle, config): style = style_from_config(config) label_style = label_style_from_config(config) return [ svg.circle(circle, style), svg.text(f'O {circle.center}', circle.center, Vector(0, 0), label_style), svg.text(f'r = {circle.radius}', circle.center, Vector(0, 20), label_style) ]
def caption_to_svg(caption: str, position: Point, angle: float, color: str, config): """ Creates the SVG caption with the `caption` text, located at `position` and rotated `angle` radians. :param caption: caption's text :param position: caption's position :param angle: caption's rotated angle :param color: caption's color :param config: configuration dictionary :return: `SVG` """ font = config['font']['family'] size = config['font']['size'] rotation = make_rotation(angle, position) scale = make_scale(1, -1, position) transform = rotation.then(scale) return svg.text(caption, position, Vector(0, 0), [ attributes.fill_color(color), attributes.affine_transform(transform), attributes.font_family(font), attributes.font_size(size) ])
def reaction_for_node(self, node: StrNodeSolution): """ Computes the external reaction force for a given node. To compute the reaction, it takes into account the external loads and the internal forces from the bars connected to the node. A node that isn't externally constrained has no reaction force. :param node: node to compute the reaction force :return: reaction force on the node """ if not node.is_constrained: return Vector(0, 0) forces = [ bar.force_in_node(node) for bar in self.bars if bar.has_node(node) ] if node.is_loaded: forces.append(node.net_load.opposite()) return reduce(operator.add, forces)
def net_load(self): """ The net load vector: the result of adding all the applied external load vectors. :return: `Vector` net load """ return reduce(operator.add, self.loads, Vector(0, 0))
def input_to_svg(points: [Point], point_radius: float, config): style = style_from_config(config) label_style = label_style_from_config(config) [a, b, c] = points disp = Vector(1.25 * point_radius, 0) return [ svg.circle(Circle(a, point_radius), style), svg.circle(Circle(b, point_radius), style), svg.circle(Circle(c, point_radius), style), svg.text(f'A {a}', a, disp, label_style), svg.text(f'B {b}', b, disp, label_style), svg.text(f'C {c}', c, disp, label_style) ]
def setUp(self): section = 5 young = 10 load = Vector(500, -1000) self.n_1 = StrNode(1, Point(0, 0)) self.n_2 = StrNode(2, Point(0, 200)) self.n_3 = StrNode(3, Point(400, 200), [load]) self.b_12 = StrBar(1, self.n_1, self.n_2, section, young) self.b_23 = StrBar(2, self.n_2, self.n_3, section, young) self.b_13 = StrBar(3, self.n_1, self.n_3, section, young) self.structure = Structure([self.n_1, self.n_2, self.n_3], [self.b_12, self.b_23, self.b_13])
def node_to_svg(node: StrNodeSolution): radius = config['sizes']['node_radius'] stroke_size = config['sizes']['stroke'] stroke_color = config['colors']['node_stroke'] fill_color = config['colors']['back'] position = node.displaced_pos_scaled(settings.disp_scale) caption_pos = position.displaced(Vector(radius, radius)) return svg.group([ svg.circle(Circle(position, radius), [ attributes.stroke_width(stroke_size), attributes.stroke_color(stroke_color), attributes.fill_color(fill_color) ]), caption_to_svg(f'{node.id}', caption_pos, 0, stroke_color, config) ])
def parse_load(load_str: str): """ Parses a load vector from a string or raises a `ValueError` if the given string doesn't follow the expected format. :param load_str: definition string :return: tuple of node id and load vector """ match = re.match(__LOAD_REGEX, load_str) if not match: raise ValueError( f'Cannot parse load from string: "{load_str}"' ) node_id = int(match.group('node_id')) [fx, fy] = [ float(num) for num in match.group('vec').split(',') ] return node_id, Vector(fx, fy)
def __generate_upper_horizontal_bars(spans: int, cross_sec: float, young: float): print('# upper horizontal bars') current_id = 7 * spans for i in range(3 * spans + 2, 4 * spans): __print_bar(current_id, i, i + 1, cross_sec, young) current_id += 1 def __print_bar(bar_id, id_from, id_to, cross_sec, young): print(f'{bar_id}: ({id_from} -> {id_to}) {cross_sec} {young}') if __name__ == '__main__': if len(sys.argv) < 8: print('Usage:') print('\tgen_baltimore <spans> <span> <height> <section> ' + '<young> <Fx> <Fy>') sys.exit(1) generate_baltimore_structure(spans=int(sys.argv[1]), span=float(sys.argv[2]), height=float(sys.argv[3]), cross_sec=float(sys.argv[4]), young=float(sys.argv[5]), node_load=Vector(float(sys.argv[6]), float(sys.argv[7])))
def test_net_load(self): loads = [Vector(10, 20), Vector(30, 40)] node = StrNode(1, Point(2, 5), loads) expected = Vector(40, 60) self.assertEqual(expected, node.net_load)
from math import sqrt from typing import List from geom2d import Segment, Vector from graphic import svg from graphic.svg import attributes from structures.solution.bar import StrBarSolution from .captions_svg import caption_to_svg __I_VERSOR = Vector(1, 0) __STRESS_DISP = 10 __DECIMAL_POS = 4 def bars_to_svg(bars: List[StrBarSolution], settings, config): """ Creates the list of SVG elements representing the bars. :param bars: list of `StrBarSolution` :param settings: :param config: :return: list of SVG elements """ def original_bar_to_svg(_bar: StrBarSolution): color = config['colors']['original'] return __bar_svg(_bar.original_geometry, color, _bar.cross_section) def bar_to_svg(_bar: StrBarSolution): return __bar_svg( _bar.final_geometry_scaling_displacement(settings.disp_scale), bar_color(_bar), _bar.cross_section)
def test_parse_load_vector(self): expected = Vector(250.0, -3500.0) self.assertEqual(expected, self.load)
def test_text(self): actual = primitives.text('foo bar', Point(2, 3), Vector(4, 5)) props = 'x="2" y="3" dx="4" dy="5"' expected = f'<text {props} >\n foo bar\n</text>' self.assertEqual(expected, actual)
def __node_to_solution(self, node: StrNode) -> StrNodeSolution: (dof_x, dof_y) = self.__dofs_dict[node.id] disp = Vector(self.__global_displacements.value_at(dof_x), self.__global_displacements.value_at(dof_y)) return StrNodeSolution(node, disp)
def test_apply_load_to_node(self): node = self.structure._Structure__nodes[1] self.assertEqual(Vector(2500, -3500), node.net_load)