Source code elsie/shapes/arrow.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import math

from ..render.backends.rcontext import RenderingContext
from ..utils.geom import segment_delta, segment_resize


class Arrow:
    """
    Represents an SVG arrow head.

    Can be attached to the start or end points of lines.

    Attributes
    ----------
    size : float
        Size of the arrow head in pixels.
    angle : float
        Angle of the arrow head.
    stroke_width : float
        Width of the arrow head edge.
    inner : float
        Shape of the arrow head.
        < 1.0 -> Sharper arrow.
        = 1.0 -> Normal arrow.
        > 1.0 -> Diamond shape arrow.
    """

    def __init__(self, size=10, angle=40, stroke_width=None, inner=None):
        self.size = size
        self.angle = angle * math.pi / 180
        self.stroke_width = stroke_width
        self.inner = inner

    def render(self, ctx: RenderingContext, p1, p2, color):
        dx, dy = segment_delta(p1, p2)
        a = math.atan2(dx, dy) + math.pi
        px, py = p2
        x1 = px + self.size * math.sin(a - self.angle)
        y1 = py + self.size * math.cos(a - self.angle)
        x2 = px + self.size * math.sin(a + self.angle)
        y2 = py + self.size * math.cos(a + self.angle)

        points = [(x1, y1), p2, (x2, y2)]

        if self.inner and not self.stroke_width:
            points.append(
                segment_resize(p1, p2, -self.inner * self.size * math.cos(self.angle))
            )

        if self.stroke_width is not None:
            ctx.draw_polyline(points, color=color, stroke_width=self.stroke_width)
        else:
            ctx.draw_polygon(points, bg_color=color)

    def move_end_point(self, p1, p2):
        if not self.stroke_width:
            shift = math.cos(self.angle) * self.size / 2
        else:
            shift = self.stroke_width / 2
        return segment_resize(p1, p2, -shift)