예제 #1
0
    def __init__(self, surface, *al, **ad):
        self._renderer = self._dwg = surface

        self._bounds = Extents()
        self._padding = PADDING

        self._stack = []
        self._m = Affine.translation(0, 0)
        self._xy = (0, 0)
        self._mxy = self._m * self._xy
        self._lw = 0
        self._rgb = (0, 0, 0)
        self._ff = "sans-serif"
        self._fs = 10
        self._last_path = None
예제 #2
0
    def _adjust_coordinates(self):
        extents = self.extents()
        extents.xmin -= PADDING
        extents.ymin -= PADDING
        extents.xmax += PADDING
        extents.ymax += PADDING

        m = Affine.translation(-extents.xmin, -extents.ymin)
        if self.invert_y:
            m = Affine.scale(self.scale, -self.scale) * m
            m = Affine.translation(0, self.scale*extents.height) * m
        else:
            m = Affine.scale(self.scale, self.scale) * m

        self.transform(m, self.invert_y)

        return Extents(0, 0, extents.width * self.scale, extents.height * self.scale)
예제 #3
0
 def extents(self):
     e = Extents()
     for p in self.path:
         e.add(*p[1:3])
         if p[0] == 'T':
             m, text, params = p[3:]
             h = params['fs']
             l = len(text) * h * 0.7
             align = params.get('align', 'left')
             start, end = {
                 'left': (0, 1),
                 'middle': (-0.5, 0.5),
                 'end': (-1, 0),
             }[align]
             for x in (start * l, end * l):
                 for y in (0, h):
                     x_, y_ = m * (x, y)
                     e.add(x_, y_)
     return e
예제 #4
0
 def extents(self):
     if not self.parts:
         return Extents()
     return sum([p.extents() for p in self.parts])
예제 #5
0
class Context:
    def __init__(self, surface, *al, **ad):
        self._renderer = self._dwg = surface

        self._bounds = Extents()
        self._padding = PADDING

        self._stack = []
        self._m = Affine.translation(0, 0)
        self._xy = (0, 0)
        self._mxy = self._m * self._xy
        self._lw = 0
        self._rgb = (0, 0, 0)
        self._ff = "sans-serif"
        self._fs = 10
        self._last_path = None

    def _update_bounds_(self, mx, my):
        self._bounds.update(mx, my)

    def save(self):
        self._stack.append((self._m, self._xy, self._lw, self._rgb, self._mxy,
                            self._last_path))
        self._xy = (0, 0)

    def restore(self):
        (
            self._m,
            self._xy,
            self._lw,
            self._rgb,
            self._mxy,
            self._last_path,
        ) = self._stack.pop()

    ## transformations

    def translate(self, x, y):
        self._m *= Affine.translation(x, y)
        self._xy = (0, 0)

    def scale(self, sx, sy):
        self._m *= Affine.scale(sx, sy)

    def rotate(self, r):
        self._m *= Affine.rotation(180 * r / math.pi)

    def set_line_width(self, lw):
        self._lw = lw

    def set_source_rgb(self, r, g, b):
        self._rgb = (r, g, b)

    ## path methods

    def _line_to(self, x, y):
        self._add_move()
        x1, y1 = self._mxy
        self._xy = x, y
        x2, y2 = self._mxy = self._m * self._xy
        if not points_equal(x1, y1, x2, y2):
            self._dwg.append("L", x2, y2)

    def _add_move(self):
        self._dwg.move_to(*self._mxy)

    def move_to(self, x, y):
        self._xy = (x, y)
        self._mxy = self._m * self._xy

    def line_to(self, x, y):
        self._line_to(x, y)

    def _arc(self, xc, yc, radius, angle1, angle2, direction):
        if abs(angle1 - angle2) < EPS or radius < EPS:
            return
        x1, y1 = radius * math.cos(angle1) + xc, radius * math.sin(angle1) + yc
        x4, y4 = radius * math.cos(angle2) + xc, radius * math.sin(angle2) + yc

        # XXX direction seems not needed for small arcs
        ax = x1 - xc
        ay = y1 - yc
        bx = x4 - xc
        by = y4 - yc
        q1 = ax * ax + ay * ay
        q2 = q1 + ax * bx + ay * by
        k2 = 4 / 3 * ((2 * q1 * q2)**0.5 - q2) / (ax * by - ay * bx)

        x2 = xc + ax - k2 * ay
        y2 = yc + ay + k2 * ax
        x3 = xc + bx + k2 * by
        y3 = yc + by - k2 * bx

        mx1, my1 = self._m * (x1, y1)
        mx2, my2 = self._m * (x2, y2)
        mx3, my3 = self._m * (x3, y3)
        mx4, my4 = self._m * (x4, y4)
        mxc, myc = self._m * (xc, yc)

        self._add_move()
        self._dwg.append("C", mx4, my4, mx2, my2, mx3, my3)
        self._xy = (x4, y4)
        self._mxy = (mx4, my4)

    def arc(self, xc, yc, radius, angle1, angle2):
        self._arc(xc, yc, radius, angle1, angle2, 1)

    def arc_negative(self, xc, yc, radius, angle1, angle2):
        self._arc(xc, yc, radius, angle1, angle2, -1)

    def curve_to(self, x1, y1, x2, y2, x3, y3):
        # mx0,my0 = self._m*self._xy
        mx1, my1 = self._m * (x1, y1)
        mx2, my2 = self._m * (x2, y2)
        mx3, my3 = self._m * (x3, y3)
        self._add_move()
        self._dwg.append("C", mx3, my3, mx1, my1, mx2,
                         my2)  # destination first!
        self._xy = (x3, y3)

    def stroke(self):
        # print('stroke stack-level=',len(self._stack),'lastpath=',self._last_path,)
        self._last_path = self._dwg.stroke(rgb=self._rgb, lw=self._lw)
        self._xy = (0, 0)

    def fill(self):
        self._xy = (0, 0)
        raise NotImplementedError()

    def set_font(self, style, bold=False, italic=False):
        if style not in ("serif", "sans-serif", "monospaced"):
            raise ValueError("Unknown font style")
        self._ff = (style, bold, italic)

    def set_font_size(self, fs):
        self._fs = fs

    def show_text(self, text, **args):
        params = {
            "ff": self._ff,
            "fs": self._fs,
            "lw": self._lw,
            "rgb": self._rgb
        }
        params.update(args)
        mx0, my0 = self._m * self._xy
        m = self._m
        self._dwg.append("T", mx0, my0, m, text, params)

    def text_extents(self, text):
        fs = self._fs
        # XXX ugly hack! Fix Boxes.text() !
        return (0, 0, 0.6 * fs * len(text), 0.65 * fs, fs * 0.1, 0)

    def rectangle(self, x, y, width, height):

        # todo: better check for empty path?
        self.stroke()

        self.move_to(x, y)
        self.line_to(x + width, y)
        self.line_to(x + width, y + height)
        self.line_to(x, y + height)
        self.line_to(x, y)
        self.stroke()

    def get_current_point(self):
        return self._xy

    def flush(self):
        pass
        # todo: check, if needed
        # self.stroke()

    ## additional methods
    def new_part(self):
        self._dwg.new_part()