예제 #1
0
def ellipse(ctx: cairo.Context,
            cell_structure: mat.CellStructure,
            r: float = 2) -> None:
    """
    Draw an ellipse in the given context.

    Drawing is centered relative to cell structure, and semi-major is aligned 
    with vertical coordinate axis.

    :param ctx: Current context.
    :param cell_structure: Assumptions about structure of the cell being drawn.
    :param r: Semi-major over semi-minor, must be > 2.
    """

    if not 2 <= r:
        raise ValueError()

    width, height = _get_dims(cell_structure)

    ctx.save()
    ctx.translate(cell_structure.width / 2., cell_structure.height / 2.)
    ctx.scale(width / (2 * r), height / 2)
    ctx.new_sub_path()
    ctx.arc(0., 0., 1., 0., 2 * math.pi)
    ctx.restore()
예제 #2
0
def rounded_rect(ctx: Context, x, y, width, height, radius):
    def deg(value):
        return value * math.pi / 180.0

    ctx.new_sub_path()
    ctx.arc(x + width - radius, y + radius, radius, deg(-90), deg(0))
    ctx.arc(x + width - radius, y + height - radius, radius, deg(0), deg(90))
    ctx.arc(x + radius, y + height - radius, radius, deg(90), deg(180))
    ctx.arc(x + radius, y + radius, radius, deg(180), deg(270))
    ctx.close_path()
예제 #3
0
 def _show_hand(self, cr: cairo.Context, x: float, y: float, angle: float, radius: float) -> None:
     if radius == 0.0:
         return
     cr.move_to(x, y)
     cr.rel_line_to(radius * math.cos(angle), radius * math.sin(angle))
     cr.new_sub_path()
예제 #4
0
class Canvas:
    def __init__(self,
                 width: int,
                 height: Optional[int] = None,
                 *,
                 normalise: bool = True):
        if height is None:
            height = width
        self._width = width
        self._height = height
        self._surface = ImageSurface(FORMAT_ARGB32, width, height)
        self._context = Context(self._surface)
        self._normalise = normalise
        if self._normalise:
            self.scale(self._width, self._height)

    @property
    def width(self) -> int:
        return self._width if not self._normalise else 1

    @property
    def height(self) -> int:
        return self._height if not self._normalise else 1

    # TODO depreciate
    @property
    def context(self) -> Context:  # pragma: no cover
        return self._context

    def save(self) -> None:
        self._context.save()

    def restore(self) -> None:
        self._context.restore()

    # Transformation
    def rotate(self, angle: float) -> None:
        self._context.rotate(angle)

    def translate(self, x: float, y: float) -> None:
        self._context.translate(x, y)

    def scale(self, width: int, height: int) -> None:
        self._context.scale(width, height)

    def set_line_width(self, width: float) -> None:
        self._context.set_line_width(width)

    # Colour functionality
    def set_colour(self, colour: Colour) -> None:
        self._context.set_source_rgba(colour.red, colour.blue, colour.green,
                                      colour.alpha)

    def set_grey(self, colour_value: float, alpha: float = 1) -> None:
        colour = Colour(*(colour_value, ) * 3, alpha)
        self.set_colour(colour)

    def set_black(self) -> None:
        self.set_colour(BLACK)

    def set_white(self) -> None:
        self.set_colour(WHITE)

    def set_background(self, colour: Colour) -> None:
        self._context.rectangle(0, 0, self.width, self.height)
        self.set_colour(colour)
        self._context.fill()

    def set_line_cap(self, line_cap: LineCap) -> None:
        self._context.set_line_cap(line_cap.value)

    def set_line_join(self, line_join: LineJoin) -> None:
        self._context.set_line_join(line_join.value)

    def set_fill_rule(self, file_rule: FillRule) -> None:
        self._context.set_fill_rule(file_rule.value)

    # Render methods
    def fill(self, preserve: bool = False) -> None:
        if not preserve:
            self._context.fill()
        else:
            self._context.fill_preserve()

    def stroke(self, preserve: bool = False) -> None:
        if not preserve:
            self._context.stroke()
        else:
            self._context.stroke_preserve()

    def clip(self) -> None:
        self._context.clip()

    def _draw_path(self, path: Iterable[Point], close_path: bool) -> None:
        self._context.new_sub_path()
        for p in path:
            self._context.line_to(*p)
        if close_path:
            self._context.close_path()

    def draw_path(self,
                  path: Iterable[PointType],
                  close_path: bool = False) -> None:
        points = (p if isinstance(p, Point) else Point(*p) for p in path)
        self._draw_path(points, close_path)

    def draw_polygon(self, polygon: Polygon) -> None:
        self._draw_path(polygon.points, close_path=True)

    def draw_circle(self,
                    circle: Circle,
                    fill: bool = False,
                    stroke: bool = True) -> None:
        self._context.new_sub_path()
        self._context.arc(*circle.centre, circle.radius, 0, 2 * pi)

    def write_to_png(self, file_name: str) -> None:
        self._surface.write_to_png(file_name)