def _generate_shapes(self) -> Dict[str, Shape]: arrow1 = Arrow( self._edge + (self._edge - self._center) * self._offset, self._edge ) text = LineAnnotation(self._text, arrow1, TextPosition.START) text.style.font_size = 24 ret_dict = {"arrow1": arrow1, "text": text} if self._diameter: inward_vector = self._center - self._edge offset_vector = inward_vector.unit_vector * self._offset start = self._edge + inward_vector * 2 + offset_vector end = self._edge + inward_vector * 2 ret_dict["arrow2"] = Arrow(start, end) if self._center_mark: ret_dict["center_mark_h"] = Line( self._center - Point(-self._offset * 0.5, 0), self._center - Point(self._offset * 0.5, 0), ) ret_dict["center_mark_v"] = Line( self._center - Point(0, -self._offset * 0.5), self._center - Point(0, self._offset * 0.5), ) if self._center_line: ret_dict["center_line"] = Line(self._edge, self._center) if self._center_line and self._diameter: ret_dict["center_line2"] = Line( self._center, self._center + (self._center - self._edge) ) return ret_dict
def _generate_extension_lines(self) -> Dict[str, Shape]: extension_lines = {} def extension_line_vector(p: Point, c: Point): if self._orientation == self.Orientation.EXTERNAL: vec = (p - c).unit_vector elif self._orientation == self.Orientation.INTERNAL: vec = (p - c).unit_vector * -1 else: raise ValueError( f"Invalid value for Orientation: {self._orientation}") return vec if self._extension_lines: extension_line1_vector = extension_line_vector( self._start, self._center) extension_lines["extension_line_1"] = Line( self._start + extension_line1_vector * self._minor_offset, self._start + extension_line1_vector * (self._offset + self._minor_offset), ) extension_line2_vector = extension_line_vector( self._end, self._center) extension_lines["extension_line_2"] = Line( self._end + extension_line2_vector * self._minor_offset, self._end + extension_line2_vector * (self._offset + self._minor_offset), ) return extension_lines
def __init__( self, start: Point, length: float, width: float = None, bar_length: float = None, num_windings: int = 11, teeth: bool = False, ): B = start n = num_windings - 1 # n counts teeth intervals if n <= 6: n = 7 # n must be odd: if n % 2 == 0: n = n + 1 L = length if width is None: w = L / 10.0 else: w = width / 2.0 s = bar_length shapes = {} if s is None: f = Spring.spring_fraction s = L * (1 - f) / 2.0 # start of spring self.bar_length = s # record self.width = 2 * w p0 = Point(B.x, B.y + s) p1 = Point(B.x, B.y + L - s) p2 = Point(B.x, B.y + L) if s >= L: raise ValueError( "length of first bar: %g is larger than total length: %g" % (s, L)) shapes["bar1"] = Line(B, p0) spring_length = L - 2 * s t = spring_length / n # height increment per winding if teeth: resolution = 4 else: resolution = 90 q = np.linspace(0, n, n * resolution + 1) xs = p0.x + w * np.sin(2 * np.pi * q) ys = p0.y + q * t points = Point.from_coordinate_lists(xs, ys) shapes["spiral"] = Curve(points) shapes["bar2"] = Line(p1, p2) super().__init__(shapes)
def __init__( self, center: Point, radius: float, inner_radius: float = None, nlines: int = 10 ): self._center = center self._radius = radius self._inner_radius = inner_radius self._nlines = nlines if inner_radius is None: self._inner_radius = radius / 5.0 outer = Circle(center, radius) inner = Circle(center, inner_radius) lines = [] # Draw nlines+1 since the first and last coincide # (then nlines lines will be visible) t = np.linspace(0, 2 * np.pi, nlines + 1) xinner = self._center.x + self._inner_radius * np.cos(t) yinner = self._center.y + self._inner_radius * np.sin(t) xouter = self._center.x + self._radius * np.cos(t) youter = self._center.y + self._radius * np.sin(t) lines = [ Line(Point(xi, yi), Point(xo, yo)) for xi, yi, xo, yo in zip(xinner, yinner, xouter, youter) ] super().__init__( { "inner": inner, "outer": outer, "spokes": Composition( {"spoke%d" % i: lines[i] for i in range(len(lines))} ), } )
def __init__( self, start: Point, height: float, profile: Callable[[float], Point], num_arrows: int, scaling: float = 1, ): self._start = start self._height = height self._profile = profile self._num_arrows = num_arrows self._scaling = scaling shapes = dict() # Draw left line shapes["start line"] = Line(self._start, (self._start + Point(0, self._height))) # Draw velocity arrows dy = float(self._height) / (self._num_arrows - 1) end_points = [] for i in range(self._num_arrows): start_position = Point(start.x, start.y + i * dy) end_position = start_position + profile( start_position.y) * self._scaling end_points += [end_position] if start_position == end_position: continue shapes["arrow%d" % i] = Arrow(start_position, end_position) shapes["smooth curve"] = Spline(end_points) super().__init__(shapes)
def __init__( self, start: Point, total_length: float, bar_length: float = None, width: float = None, dashpot_length: float = None, piston_pos: float = None, ): B = start L = total_length if width is None: w = L / 10.0 # total width 1/5 of length else: w = width / 2.0 s = bar_length shapes = {} # dashpot is p0-p1 in y and width 2*w if dashpot_length is None: if s is None: f = Dashpot._dashpot_fraction s = L * (1 - f) / 2.0 # default p1 = Point(B.x, B.y + L - s) dashpot_length = f * L else: if s is None: f = 1.0 / 2 # the bar lengths are taken as f*dashpot_length s = f * dashpot_length # default p1 = Point(B.x, B.y + s + dashpot_length) p0 = Point(B.x, B.y + s) p2 = Point(B.x, B.y + L) if not (p2.y > p1.y > p0.y): raise ValueError( ("Dashpot has inconsistent dimensions! start: %g, " "dashpot begin: %g, dashpot end: %g, very end: %g" % (B.y, p0.y, p1.y, p2.y))) shapes["line start"] = Line(B, p0) shapes["pot"] = Curve([ Point(p1.x - w, p1.y), Point(p0.x - w, p0.y), Point(p0.x + w, p0.y), Point(p1.x + w, p1.y), ]) piston_thickness = dashpot_length * Dashpot._piston_thickness_fraction if piston_pos is None: piston_pos = 1 / 3.0 * dashpot_length if piston_pos < 0: piston_pos = 0 elif piston_pos > dashpot_length: piston_pos = dashpot_length - piston_thickness abs_piston_pos = p0.y + piston_pos gap = w * Dashpot._piston_gap_fraction shapes["piston"] = Composition({ "line": Line(p2, Point(B.x, abs_piston_pos + piston_thickness)), "rectangle": Rectangle( Point(B.x - w + gap, abs_piston_pos), 2 * w - 2 * gap, piston_thickness, ), }) shapes["piston"]["rectangle"].set_fill_pattern(Style.FillPattern.CROSS) super().__init__(shapes)
def extension_line(start: Point, end: Point) -> Line: return Line( start + (end - start) * self._minor_offset, end + (end - start) * self._minor_offset, )