src/reportlab/pdfgen/pathobject.py
author robin <robin@reportlab.com>
Tue, 07 Mar 2017 10:00:34 +0000
changeset 4330 617ffa6bbdc8
parent 4252 fe660f227cac
child 4370 823a8c33ce43
permissions -rwxr-xr-x
changes for release 3.4.0
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
4330
617ffa6bbdc8 changes for release 3.4.0
robin <robin@reportlab.com>
parents: 4252
diff changeset
     1
#Copyright ReportLab Europe Ltd. 2000-2017
494
54257447cfe9 Changed to indirect copyright
rgbecker
parents: 365
diff changeset
     2
#see license.txt for license details
2332
2a7ab4405e18 Remove $Header:, fix CopyRight & history
rgbecker
parents: 1683
diff changeset
     3
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/pdfgen/pathobject.py
4252
fe660f227cac changes for release 3.3.0
robin
parents: 3781
diff changeset
     4
__version__='3.3.0'
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 979
diff changeset
     5
__doc__="""
6
eb791971b252 Added license, __version__ and Logi comment
rgbecker
parents: 0
diff changeset
     6
PDFPathObject is an efficient way to draw paths on a Canvas. Do not
eb791971b252 Added license, __version__ and Logi comment
rgbecker
parents: 0
diff changeset
     7
instantiate directly, obtain one from the Canvas instead.
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
     8
6
eb791971b252 Added license, __version__ and Logi comment
rgbecker
parents: 0
diff changeset
     9
Progress Reports:
3030
8bc2e0f9c080 docstring fixes for pdfgen
damian
parents: 2964
diff changeset
    10
8.83, 2000-01-13, gmcm: created from pdfgen.py
8bc2e0f9c080 docstring fixes for pdfgen
damian
parents: 2964
diff changeset
    11
6
eb791971b252 Added license, __version__ and Logi comment
rgbecker
parents: 0
diff changeset
    12
"""
562
6c9408ec3302 Minor neglectable changes.
dinu_gherman
parents: 494
diff changeset
    13
365
2a6ac05b39e8 fixed nameerror and path.circle bug
aaron_watters
parents: 261
diff changeset
    14
from reportlab.pdfgen import pdfgeom
3781
df8b57380768 import from reportlab.lib.lib.rl_accel
robin
parents: 3766
diff changeset
    15
from reportlab.lib.rl_accel import fp_str
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    16
562
6c9408ec3302 Minor neglectable changes.
dinu_gherman
parents: 494
diff changeset
    17
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    18
class PDFPathObject:
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    19
    """Represents a graphic path.  There are certain 'modes' to PDF
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    20
    drawing, and making a separate object to expose Path operations
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    21
    ensures they are completed with no run-time overhead.  Ask
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    22
    the Canvas for a PDFPath with getNewPathObject(); moveto/lineto/
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    23
    curveto wherever you want; add whole shapes; and then add it back
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    24
    into the canvas with one of the relevant operators.
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 979
diff changeset
    25
3572
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    26
    Path objects are probably not long, so we pack onto one line
562
6c9408ec3302 Minor neglectable changes.
dinu_gherman
parents: 494
diff changeset
    27
3572
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    28
    the code argument allows a canvas to get the operatiosn appended directly so
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    29
    avoiding the final getCode
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    30
    """
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    31
    def __init__(self,code=None):
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    32
        self._code = (code,[])[code is None]
2462
f3e51de1cf07 pathobject: speed improvements and initial assertion
rgbecker
parents: 2332
diff changeset
    33
        self._code_append = self._init_code_append
f3e51de1cf07 pathobject: speed improvements and initial assertion
rgbecker
parents: 2332
diff changeset
    34
f3e51de1cf07 pathobject: speed improvements and initial assertion
rgbecker
parents: 2332
diff changeset
    35
    def _init_code_append(self,c):
f3e51de1cf07 pathobject: speed improvements and initial assertion
rgbecker
parents: 2332
diff changeset
    36
        assert c.endswith(' m') or c.endswith(' re'), 'path must start with a moveto or rect'
f3e51de1cf07 pathobject: speed improvements and initial assertion
rgbecker
parents: 2332
diff changeset
    37
        code_append = self._code.append
f3e51de1cf07 pathobject: speed improvements and initial assertion
rgbecker
parents: 2332
diff changeset
    38
        code_append('n')
f3e51de1cf07 pathobject: speed improvements and initial assertion
rgbecker
parents: 2332
diff changeset
    39
        code_append(c)
f3e51de1cf07 pathobject: speed improvements and initial assertion
rgbecker
parents: 2332
diff changeset
    40
        self._code_append = code_append
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 979
diff changeset
    41
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    42
    def getCode(self):
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    43
        "pack onto one line; used internally"
3766
4fa0f4494409 ttfonts.py: py33 branch at least can draw to PDF
robin
parents: 3617
diff changeset
    44
        return ' '.join(self._code)
562
6c9408ec3302 Minor neglectable changes.
dinu_gherman
parents: 494
diff changeset
    45
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    46
    def moveTo(self, x, y):
2462
f3e51de1cf07 pathobject: speed improvements and initial assertion
rgbecker
parents: 2332
diff changeset
    47
        self._code_append('%s m' % fp_str(x,y))
562
6c9408ec3302 Minor neglectable changes.
dinu_gherman
parents: 494
diff changeset
    48
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    49
    def lineTo(self, x, y):
2462
f3e51de1cf07 pathobject: speed improvements and initial assertion
rgbecker
parents: 2332
diff changeset
    50
        self._code_append('%s l' % fp_str(x,y))
562
6c9408ec3302 Minor neglectable changes.
dinu_gherman
parents: 494
diff changeset
    51
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    52
    def curveTo(self, x1, y1, x2, y2, x3, y3):
2462
f3e51de1cf07 pathobject: speed improvements and initial assertion
rgbecker
parents: 2332
diff changeset
    53
        self._code_append('%s c' % fp_str(x1, y1, x2, y2, x3, y3))
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 979
diff changeset
    54
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    55
    def arc(self, x1,y1, x2,y2, startAng=0, extent=90):
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    56
        """Contributed to piddlePDF by Robert Kern, 28/7/99.
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    57
        Draw a partial ellipse inscribed within the rectangle x1,y1,x2,y2,
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    58
        starting at startAng degrees and covering extent degrees.   Angles
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    59
        start with 0 to the right (+x) and increase counter-clockwise.
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    60
        These should have x1<x2 and y1<y2.
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    61
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    62
        The algorithm is an elliptical generalization of the formulae in
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    63
        Jim Fitzsimmon's TeX tutorial <URL: http://www.tinaja.com/bezarc1.pdf>."""
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    64
3572
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    65
        self._curves(pdfgeom.bezierArc(x1,y1, x2,y2, startAng, extent))
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    66
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    67
    def arcTo(self, x1,y1, x2,y2, startAng=0, extent=90):
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    68
        """Like arc, but draws a line from the current point to
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    69
        the start if the start is not the current point."""
3572
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    70
        self._curves(pdfgeom.bezierArc(x1,y1, x2,y2, startAng, extent),'lineTo')
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 979
diff changeset
    71
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    72
    def rect(self, x, y, width, height):
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    73
        """Adds a rectangle to the path"""
2462
f3e51de1cf07 pathobject: speed improvements and initial assertion
rgbecker
parents: 2332
diff changeset
    74
        self._code_append('%s re' % fp_str((x, y, width, height)))
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    75
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    76
    def ellipse(self, x, y, width, height):
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    77
        """adds an ellipse to the path"""
3572
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    78
        self._curves(pdfgeom.bezierArc(x, y, x + width,y + height, 0, 360))
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    79
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    80
    def _curves(self,curves,initial='moveTo'):
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    81
        getattr(self,initial)(*curves[0][:2])
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    82
        for curve in curves:
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    83
            self.curveTo(*curve[2:])
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 979
diff changeset
    84
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    85
    def circle(self, x_cen, y_cen, r):
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    86
        """adds a circle to the path"""
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    87
        x1 = x_cen - r
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    88
        y1 = y_cen - r
365
2a6ac05b39e8 fixed nameerror and path.circle bug
aaron_watters
parents: 261
diff changeset
    89
        width = height = 2*r
2a6ac05b39e8 fixed nameerror and path.circle bug
aaron_watters
parents: 261
diff changeset
    90
        self.ellipse(x1, y1, width, height)
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 979
diff changeset
    91
3572
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    92
    def roundRect(self, x, y, width, height, radius):
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    93
        """Draws a rectangle with rounded corners. The corners are
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    94
        approximately quadrants of a circle, with the given radius."""
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    95
        #use a precomputed set of factors for the bezier approximation
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    96
        #to a circle. There are six relevant points on the x axis and y axis.
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    97
        #sketch them and it should all make sense!
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    98
        t = 0.4472 * radius
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
    99
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   100
        x0 = x
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   101
        x1 = x0 + t
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   102
        x2 = x0 + radius
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   103
        x3 = x0 + width - radius
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   104
        x4 = x0 + width - t
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   105
        x5 = x0 + width
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   106
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   107
        y0 = y
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   108
        y1 = y0 + t
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   109
        y2 = y0 + radius
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   110
        y3 = y0 + height - radius
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   111
        y4 = y0 + height - t
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   112
        y5 = y0 + height
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   113
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   114
        self.moveTo(x2, y0)
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   115
        self.lineTo(x3, y0) #bottom row
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   116
        self.curveTo(x4, y0, x5, y1, x5, y2) #bottom right
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   117
        self.lineTo(x5, y3) #right edge
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   118
        self.curveTo(x5, y4, x4, y5, x3, y5) #top right
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   119
        self.lineTo(x2, y5) #top row
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   120
        self.curveTo(x1, y5, x0, y4, x0, y3) #top left
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   121
        self.lineTo(x0, y2) #left edge
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   122
        self.curveTo(x0, y1, x1, y0, x2, y0) #bottom left
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   123
        self.close()
d88eb970b7be textobject.py: attempt to fix semantics of PDFTextObject.setTextRender for pdf >=1.4
rgbecker
parents: 3030
diff changeset
   124
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   125
    def close(self):
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   126
        "draws a line back to where it started"
2462
f3e51de1cf07 pathobject: speed improvements and initial assertion
rgbecker
parents: 2332
diff changeset
   127
        self._code_append('h')