def draw_crosshair(plane, center, radius): circle = Circle(center, radius) plane.draw_circle(circle, geom2d.BLACK) plane.draw_line(Point(center.x, center.y - radius), Point(center.x, center.y + radius), geom2d.RED) plane.draw_line(Point(center.x - radius, center.y), Point(center.x + radius, center.y), geom2d.RED)
class StructureSolutionTest(unittest.TestCase): p_one = Point(2, 3) p_two = Point(5, 1) def setUp(self): self.n_one = Mock(spec=StrNodeSolution) self.n_one.displaced_pos_scaled.return_value = self.p_one self.n_two = Mock(spec=StrNodeSolution) self.n_two.displaced_pos_scaled.return_value = self.p_two def test_node_displaced_scaled_positions_called(self): solution = StructureSolution([self.n_one, self.n_two], []) solution.bounds_rect(margin=10, scale=4) self.n_one.displaced_pos_scaled.assert_called_once_with(4) self.n_two.displaced_pos_scaled.assert_called_once_with(4) @patch('structures.solution.structure.make_rect_containing_with_margin') def test_make_rect_called(self, make_rect_mock): solution = StructureSolution([self.n_one, self.n_two], []) solution.bounds_rect(margin=10, scale=4) make_rect_mock.assert_called_once_with( [self.p_one, self.p_two], 10 )
class BarTest(unittest.TestCase): section = sqrt(5) young = 5 node_a = StrNode(1, Point(0, 0)) node_b = StrNode(2, Point(2, 1)) bar = StrBar(1, node_a, node_b, section, young) def test_global_stiffness_matrix(self): expected = Matrix(4, 4).set_data( [4, 2, -4, -2, 2, 1, -2, -1, -4, -2, 4, 2, -2, -1, 2, 1]) actual = self.bar.global_stiffness_matrix() self.assertEqual(expected, actual)
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 parse_node(node_str: str): """ Parses a `StrNode` from a string or raises a `ValueError` if the given string doesn't follow the expected format. :param node_str: definition string :return: `StrNode` """ match = re.match(__NODE_REGEX, node_str) if not match: raise ValueError( f'Cannot parse node from string: {node_str}' ) _id = int(match.group('id')) [x, y] = [ float(num) for num in match.group('pos').split(',') ] ext_const = match.group('ec') return StrNode( _id, Point(x, y), None, 'x' in ext_const, 'y' in ext_const )
def draw_circle(self, circle, color): step = 1.0 / self._wratio**2 x = circle.center.x - circle.radius while x < circle.center.x - (circle.radius * 0.9): ys = circle.eval_at_x(x) for y in ys: self._draw_point(Point(x, y), color) self._draw_point( Point((circle.center.x - x) + circle.center.x, y), color) x += step step *= self._wratio / 2.0 while x <= circle.center.x: ys = circle.eval_at_x(x) for y in ys: self._draw_point(Point(x, y), color) self._draw_point( Point((circle.center.x - x) + circle.center.x, y), color) x += step
def vector_to_svg( position: Point, vector: Vector, scale: float, color: str, config ): """ Creates an SVG representation of the given vector using an arrow and a label aligned with the arrow. :param position: origin of the vector :param vector: `Vector` :param scale: scale to use in the drawing :param color: color to use for the arrow and label :param config: configuration dictionary :return: SVG arrow and label """ segment = Segment( position.displaced(vector, -scale), position ) caption_origin = segment.start.displaced( segment.normal_versor, __CAPTION_DISP ) def svg_arrow(): width = config['sizes']['stroke'] arrow_size = config['sizes']['arrow'] return svg.arrow( segment, arrow_size, arrow_size, [ attributes.stroke_color(color), attributes.stroke_width(width), attributes.fill_color('none') ] ) def svg_caption(): return caption_to_svg( vector.to_formatted_str(__DECIMAL_POS), caption_origin, vector.angle_to(__I_VERSOR), color, config ) return svg.group([ svg_arrow(), svg_caption() ])
def draw_line(self, start, end, color): delta_x = end.x - start.x delta_y = end.y - start.y npoints = self._line_span(start.distance_to(end)) x = start.x if delta_x == 0: step = float(delta_y) / npoints y = start.y for i in range(npoints): self._draw_point(Point(x, y), color) y += step else: slope = delta_y / delta_x step = float(delta_x) / npoints c = start.y - x * slope for i in range(npoints): y = x * slope + c self._draw_point(Point(x, y), color) x += step
def draw_circle_arc(self, circle, start, extent, color): start_rad = (start % 1.0) * 2 * pi delta = (extent % 1.0) * 2 * pi step = delta / (max(self._wratio, self._hratio)**2) npoints = int(abs(delta / step)) current_rad = start_rad for i in range(npoints): point = Point(circle.center.x + circle.radius * cos(current_rad), circle.center.y - circle.radius * sin(current_rad)) self._draw_point(point, color) current_rad += step
def make_polygon_from_coords(coords: [float]): """ Creates a `Polygon` instance using the passed in coordinates: `[x1 y1 x2 y2 ... xn yn]`. It raises a `ValueError` if the coordinates list does't have an even number of entries. :param coords: list of the coordinates of the vertices :return: `Polygon` """ if len(coords) % 2 != 0: raise ValueError('Need an even number of coordinates') indices = range(0, len(coords), 2) return Polygon([Point(coords[i], coords[i + 1]) for i in indices])
class TestSvgImage(unittest.TestCase): size = Size(200, 350) viewbox = Rect(Point(4, 5), Size(180, 230)) def test_parse_width(self): svg = svg_content(self.size, []) self.assertTrue('width="200"' in svg) def test_parse_height(self): svg = svg_content(self.size, []) self.assertTrue('height="350"' in svg) def test_parse_default_viewbox(self): svg = svg_content(self.size, []) self.assertTrue('viewBox="0 0 200 350"' in svg) def test_parse_viewbox(self): svg = svg_content(self.size, [], self.viewbox) self.assertTrue('viewBox="4 5 180 230"' in svg)
def _circle_to_rect(self, circle): x1, y1 = self._transform(Point(circle.center.x - circle.radius, circle.center.y - circle.radius)) x2, y2 = self._transform(Point(circle.center.x + circle.radius, circle.center.y + circle.radius)) return (x1, y1, x2, y2)
plane.draw_line(Point(center.x, center.y - radius), Point(center.x, center.y + radius), geom2d.RED) plane.draw_line(Point(center.x - radius, center.y), Point(center.x + radius, center.y), geom2d.RED) top = Tkinter.Tk() planes = [] canvas = Tkinter.Canvas(top, bg="white", height=600, width=800) tk_plane = TkinterCanvasPlane(PLANE_WIDTH, PLANE_HEIGHT, canvas) planes.append(tk_plane) image_raster = ImageRaster(IMAGE_WIDTH, IMAGE_HEIGHT, geom2d.WHITE) image_plane = RasterPlane(PLANE_WIDTH, PLANE_HEIGHT, image_raster) planes.append(image_plane) svg_plane = SVGPlane(PLANE_WIDTH, PLANE_HEIGHT, 'crosshair.svg') planes.append(svg_plane) for plane in planes: draw_crosshair(plane, Point(PLANE_WIDTH / 2.0, PLANE_HEIGHT / 2.0), CROSSHAIR_RADIUS) canvas.pack() image_raster.save('crosshair.png') svg_plane.save() top.mainloop()
def __default_viewbox_rect(size: Size): return Rect(Point(0, 0), size)
from geom2d import Point, Circle, AffineTransform from graphic.simulation.draw import CanvasDrawing from graphic.simulation.loop import main_loop tk = Tk() tk.title("Hello Motion") canvas = Canvas(tk, width=600, height=600) canvas.grid(row=0, column=0) max_frames = 100 transform = AffineTransform(sx=1, sy=-1, tx=150, ty=600, shx=-0.5, shy=0) drawing = CanvasDrawing(canvas, transform) circle = Circle(Point(300, 300), 0) def update_system(time_delta_s, time_s, frame): circle.radius = (circle.radius + 15) % 450 tk.update() def redraw(): drawing.clear_drawing() drawing.draw_circle(circle, 50) def should_continue(frame, time_s): return frame <= max_frames
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)
def test_rectangle(self): rect = Rect(Point(2, 3), Size(4, 5)) actual = primitives.rectangle(rect) expected = '<rect x="2" y="3" width="4" height="5" />' self.assertEqual(expected, actual)
def test_circle(self): circle = Circle(Point(1, 2), 5) actual = primitives.circle(circle) expected = '<circle cx="1" cy="2" r="5" />' self.assertEqual(expected, actual)
def test_parse_nodes(self): nodes = self.structure._Structure__nodes self.assertEqual(Point(0, 0), nodes[0].position) self.assertEqual(Point(200, 150), nodes[1].position) self.assertEqual(Point(400, 0), nodes[2].position)
def parse_segment(line): match = re.match(__SEGM_RE, line) return Segment(start=Point(float(match.group('sx')), float(match.group('sy'))), end=Point(float(match.group('ex')), float(match.group('ey'))))
def parse_circle(line): match = re.match(__CIRC_RE, line) return Circle(center=Point(float(match.group('cx')), float(match.group('cy'))), radius=float(match.group('r')))
def test_segment(self): segment = Segment(Point(2, 3), Point(4, 5)) actual = primitives.segment(segment) expected = '<line x1="2" y1="3" x2="4" y2="5" />' self.assertEqual(expected, actual)
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 test_polygon(self): polygon = Polygon([Point(2, 3), Point(4, 5), Point(6, 7)]) actual = primitives.polygon(polygon) expected = '<polygon points="2,3 4,5 6,7" />' self.assertEqual(expected, actual)
def parse_rect(line): match = re.match(__RECT_RE, line) return Rect(origin=Point(float(match.group('ox')), float(match.group('oy'))), size=Size(float(match.group('w')), float(match.group('h'))))
def simulate(transform, primitives, config): # ---------- UI DEFINITION ---------- # tk = Tk() tk.title("Affine Transformations") tk.minsize(width=400, height=400) canvas = Canvas(tk) canvas.pack(fill='both', side='top', expand=True) def start_simulation(): tk.update() main_loop(update_system, redraw, should_continue) button = Button(tk, text='Play', command=start_simulation) button.pack(anchor='center', side='bottom') # ---------- UPDATE, DRAW & CONTINUE ---------- # frames = config['frames'] transform_seq = __make_transform_sequence(transform, frames) axis_length = config['axes']['length'] x_axis = Segment(Point(0, 0), Point(axis_length, 0)) y_axis = Segment(Point(0, 0), Point(0, axis_length)) drawing = CanvasDrawing(canvas, transform_seq[0]) def update_system(time_delta_s, time_s, frame): drawing.transform = transform_seq[frame - 1] tk.update() def redraw(): drawing.clear_drawing() drawing.outline_width = config['axes']['stroke-width'] drawing.outline_color = config['axes']['x-color'] drawing.draw_arrow(x_axis, config['axes']['arrow-length'], config['axes']['arrow-height']) drawing.outline_color = config['axes']['y-color'] drawing.draw_arrow(y_axis, config['axes']['arrow-length'], config['axes']['arrow-height']) drawing.outline_width = config['geometry']['stroke-width'] drawing.outline_color = config['geometry']['stroke-color'] for circle in primitives['circs']: drawing.draw_circle(circle) for rect in primitives['rects']: drawing.draw_rectangle(rect) for polygon in primitives['polys']: drawing.draw_polygon(polygon) for segment in primitives['segs']: drawing.draw_segment(segment) def should_continue(frame, time_s): return frame <= frames # ---------- MAIN LOOP ---------- # redraw() tk.mainloop()
def __point_from_string(string): matches = re.match(r'(?P<x>\d+)\s(?P<y>\d+)', string) return Point( int(matches.group('x')), int(matches.group('y')) )
def test_parse_position(self): expected = Point(25.0, 45.0) self.assertEqual(expected, self.node.position)