def _draw_segment(self, cur_drawing):
        """Draw a half circle representing the end of a linear chromosome."""
        # set the coordinates of the segment -- it'll take up the MIDDLE part
        # of the space we have.
        width = (self.end_x_position - self.start_x_position) \
            * self.chr_percent
        height = self.start_y_position - self.end_y_position
        center_x = 0.5 * (self.end_x_position + self.start_x_position)
        start_x = center_x - 0.5 * width
        if self._inverted:
            center_y = self.start_y_position
            start_angle = 180
            end_angle = 360
        else:
            center_y = self.end_y_position
            start_angle = 0
            end_angle = 180

        cap_wedge = Wedge(center_x, center_y, width / 2,
                          start_angle, end_angle, height)
        cap_wedge.strokeColor = None
        cap_wedge.fillColor = self.fill_color
        cur_drawing.add(cap_wedge)

        # Now draw an arc for the curved edge of the wedge,
        # omitting the flat end.
        cap_arc = ArcPath()
        cap_arc.addArc(center_x, center_y, width / 2,
                       start_angle, end_angle, height)
        cur_drawing.add(cap_arc)
Exemple #2
0
    def _draw_segment(self, cur_drawing):
        """Draw a half circle representing the end of a linear chromosome.
        """
        # set the coordinates of the segment -- it'll take up the MIDDLE part
        # of the space we have.
        width = (self.end_x_position - self.start_x_position) \
                * self.chr_percent
        height = self.start_y_position - self.end_y_position
        center_x = 0.5 * (self.end_x_position + self.start_x_position)
        start_x = center_x - 0.5 * width
        if self._inverted:
            center_y = self.start_y_position
            start_angle = 180
            end_angle = 360
        else:
            center_y = self.end_y_position
            start_angle = 0
            end_angle = 180

        cap_wedge = Wedge(center_x, center_y, width / 2,
                          start_angle, end_angle, height)
        cap_wedge.strokeColor = None
        cap_wedge.fillColor = self.fill_color
        cur_drawing.add(cap_wedge)

        # Now draw an arc for the curved edge of the wedge,
        # omitting the flat end.
        cap_arc = ArcPath()
        cap_arc.addArc(center_x, center_y, width / 2,
                       start_angle, end_angle, height)
        cur_drawing.add(cap_arc)
Exemple #3
0
    def draw(self):
        slices = self.slices
        _3d_angle = self.angle_3d
        _3dva = self._3dva = _360(_3d_angle+90)
        a0 = _2rad(_3dva)
        self._xdepth_3d = cos(a0)*self.depth_3d
        self._ydepth_3d = sin(a0)*self.depth_3d
        self._cx = self.x+self.width/2.0
        self._cy = self.y+(self.height - self._ydepth_3d)/2.0
        radiusx = radiusy = self._cx-self.x
        if self.xradius: radiusx = self.xradius
        if self.yradius: radiusy = self.yradius
        self._radiusx = radiusx
        self._radiusy = radiusy = (1.0 - self.perspective/100.0)*radiusy
        data = self.normalizeData()
        sum = self._sum

        CX = self.CX
        CY = self.CY
        OX = self.OX
        OY = self.OY
        rad_dist = self.rad_dist
        _fillSide = self._fillSide
        self._seriesCount = n = len(data)
        _sl3d = self._sl3d = []
        g = Group()
        last = _360(self.startAngle)
        a0 = self.direction=='clockwise' and -1 or 1
        for v in data:
            v *= a0
            angle1, angle0 = last, v+last
            last = angle0
            if a0>0: angle0, angle1 = angle1, angle0
            _sl3d.append(_SL3D(angle0,angle1))

        labels = _fixLabels(self.labels,n)
        a0 = _3d_angle
        a1 = _3d_angle+180
        T = []
        S = []
        L = []

        class WedgeLabel3d(WedgeLabel):
            _ydepth_3d = self._ydepth_3d
            def _checkDXY(self,ba):
                if ba[0]=='n':
                    if not hasattr(self,'_ody'):
                        self._ody = self.dy
                        self.dy = -self._ody + self._ydepth_3d
    
        checkLabelOverlap = self.checkLabelOverlap

        for i in xrange(n):
            style = slices[i]
            if not style.visible: continue
            sl = _sl3d[i]
            lo = angle0 = sl.lo
            hi = angle1 = sl.hi
            if abs(hi-lo)<=1e-7: continue
            fillColor = _getShaded(style.fillColor,style.fillColorShaded,style.shading)
            strokeColor = _getShaded(style.strokeColor,style.strokeColorShaded,style.shading) or fillColor
            strokeWidth = style.strokeWidth
            cx0 = CX(i,0)
            cy0 = CY(i,0)
            cx1 = CX(i,1)
            cy1 = CY(i,1)
            #background shaded pie bottom
            g.add(Wedge(cx1,cy1,radiusx, lo, hi,yradius=radiusy,
                            strokeColor=strokeColor,strokeWidth=strokeWidth,fillColor=fillColor,
                            strokeLineJoin=1))
            #connect to top
            if lo < a0 < hi: angle0 = a0
            if lo < a1 < hi: angle1 = a1
            if 1:
                p = ArcPath(strokeColor=strokeColor, fillColor=fillColor,strokeWidth=strokeWidth,strokeLineJoin=1)
                p.addArc(cx1,cy1,radiusx,angle0,angle1,yradius=radiusy,moveTo=1)
                p.lineTo(OX(i,angle1,0),OY(i,angle1,0))
                p.addArc(cx0,cy0,radiusx,angle0,angle1,yradius=radiusy,reverse=1)
                p.closePath()
                if angle0<=_3dva and angle1>=_3dva:
                    rd = 0
                else:
                    rd = min(rad_dist(angle0),rad_dist(angle1))
                S.append((rd,p))
            _fillSide(S,i,lo,strokeColor,strokeWidth,fillColor)
            _fillSide(S,i,hi,strokeColor,strokeWidth,fillColor)

            #bright shaded top
            fillColor = style.fillColor
            strokeColor = style.strokeColor or fillColor
            T.append(Wedge(cx0,cy0,radiusx,lo,hi,yradius=radiusy,
                            strokeColor=strokeColor,strokeWidth=strokeWidth,fillColor=fillColor,strokeLineJoin=1))

            text = labels[i]
            if style.label_visible and text:
                rat = style.labelRadius
                self._radiusx *= rat
                self._radiusy *= rat
                mid = sl.mid
                labelX = OX(i,mid,0)
                labelY = OY(i,mid,0)
                _addWedgeLabel(self,text,L.append,mid,labelX,labelY,style,labelClass=WedgeLabel3d)
                if checkLabelOverlap:
                    l = L[-1]
                    l._origdata = { 'x': labelX, 'y':labelY, 'angle': mid,
                                    'rx': self._radiusx, 'ry':self._radiusy, 'cx':CX(i,0), 'cy':CY(i,0),
                                    'bounds': l.getBounds(),
                                    }
                self._radiusx = radiusx
                self._radiusy = radiusy

        S.sort(lambda a,b: -cmp(a[0],b[0]))
        if checkLabelOverlap and L:
            fixLabelOverlaps(L)
        map(g.add,map(lambda x:x[1],S)+T+L)
        return g
Exemple #4
0
    def draw(self):
        slices = self.slices
        _3d_angle = self.angle_3d
        _3dva = self._3dva = _360(_3d_angle+90)
        a0 = _2rad(_3dva)
        self._xdepth_3d = cos(a0)*self.depth_3d
        self._ydepth_3d = sin(a0)*self.depth_3d
        self._cx = self.x+self.width/2.0
        self._cy = self.y+(self.height - self._ydepth_3d)/2.0
        radius = self._radius = self._cx-self.x
        self._radiusx = radiusx = radius
        self._radiusy = radiusy = (1.0 - self.perspective/100.0)*radius
        data = self.normalizeData()
        sum = self._sum

        CX = self.CX
        CY = self.CY
        OX = self.OX
        OY = self.OY
        rad_dist = self.rad_dist
        _fillSide = self._fillSide
        n = len(data)
        _sl3d = self._sl3d = []
        g = Group()
        last = _360(self.startAngle)
        a0 = self.direction=='clockwise' and -1 or 1
        for v in data:
            v *= a0
            angle1, angle0 = last, v+last
            last = angle0
            if a0>0: angle0, angle1 = angle1, angle0
            _sl3d.append(_SL3D(angle0,angle1))
            #print '%d: %.2f %.2f --> %s' %(len(_sl3d)-1,angle0,angle1,_sl3d[-1])

        labels = _fixLabels(self.labels,n)
        a0 = _3d_angle
        a1 = _3d_angle+180
        T = []
        S = []
        L = []

        class WedgeLabel3d(WedgeLabel):
            def _checkDXY(self,ba):
                if ba[0]=='n':
                    if not hasattr(self,'_ody'):
                        self._ody = self.dy
                        self.dy = -self._ody + self._ydepth_3d
        WedgeLabel3d._ydepth_3d = self._ydepth_3d

        for i in xrange(n):
            style = slices[i]
            if not style.visible: continue
            sl = _sl3d[i]
            lo = angle0 = sl.lo
            hi = angle1 = sl.hi
            if abs(hi-lo)<=1e-7: continue
            fillColor = _getShaded(style.fillColor,style.fillColorShaded,style.shading)
            strokeColor = _getShaded(style.strokeColor,style.strokeColorShaded,style.shading) or fillColor
            strokeWidth = style.strokeWidth
            cx0 = CX(i,0)
            cy0 = CY(i,0)
            cx1 = CX(i,1)
            cy1 = CY(i,1)
            #background shaded pie bottom
            g.add(Wedge(cx1,cy1,radiusx, lo, hi,yradius=radiusy,
                            strokeColor=strokeColor,strokeWidth=strokeWidth,fillColor=fillColor,
                            strokeLineJoin=1))
            #connect to top
            if lo < a0 < hi: angle0 = a0
            if lo < a1 < hi: angle1 = a1
            if 1:
                p = ArcPath(strokeColor=strokeColor, fillColor=fillColor,strokeWidth=strokeWidth,strokeLineJoin=1)
                p.addArc(cx1,cy1,radiusx,angle0,angle1,yradius=radiusy,moveTo=1)
                p.lineTo(OX(i,angle1,0),OY(i,angle1,0))
                p.addArc(cx0,cy0,radiusx,angle0,angle1,yradius=radiusy,reverse=1)
                p.closePath()
                if angle0<=_3dva and angle1>=_3dva:
                    rd = 0
                else:
                    rd = min(rad_dist(angle0),rad_dist(angle1))
                S.append((rd,p))
            _fillSide(S,i,lo,strokeColor,strokeWidth,fillColor)
            _fillSide(S,i,hi,strokeColor,strokeWidth,fillColor)

            #bright shaded top
            fillColor = style.fillColor
            strokeColor = style.strokeColor or fillColor
            T.append(Wedge(cx0,cy0,radiusx,lo,hi,yradius=radiusy,
                            strokeColor=strokeColor,strokeWidth=strokeWidth,fillColor=fillColor,strokeLineJoin=1))

            text = labels[i]
            if text:
                rat = style.labelRadius
                self._radiusx *= rat
                self._radiusy *= rat
                mid = sl.mid
                _addWedgeLabel(self,text,L.append,mid,OX(i,mid,0),OY(i,mid,0),style,labelClass=WedgeLabel3d)
                self._radiusx = radiusx
                self._radiusy = radiusy

        S.sort(lambda a,b: -cmp(a[0],b[0]))
        map(g.add,map(lambda x:x[1],S)+T+L)
        return g
Exemple #5
0
    def _draw_arc(self, inner_radius, outer_radius, startangle, endangle,
                 color, border=None, colour=None, **kwargs):
        """ draw_arc(self, inner_radius, outer_radius, startangle, endangle, color)
                -> Group

            o inner_radius  Float distance of inside of arc from drawing center

            o outer_radius  Float distance of outside of arc from drawing center

            o startangle    Float angle subtended by start of arc at drawing center
                            (in radians)

            o endangle      Float angle subtended by end of arc at drawing center
                            (in radians)

            o color        colors.Color object for arc (overridden by backwards
                           compatible argument with UK spelling, colour).

            Returns a closed path object describing an arced box corresponding to
            the passed values.  For very small angles, a simple four sided
            polygon is used.
        """
        #Let the UK spelling (colour) override the USA spelling (color)
        if colour is not None:
            color = colour

        if border is None:
            border = color

        if color is None:
            color = colour
        if color == colors.white and border is None:   # Force black border on 
            strokecolor = colors.black                 # white boxes with
        elif border is None:                           # undefined border, else
            strokecolor = color                        # use fill colour
        elif border is not None:
            strokecolor = border

        if abs(float(endangle - startangle))>.01:
            # Wide arc, must use full curves
            p = ArcPath(strokeColor=strokecolor,
                        fillColor=color,
                        strokewidth=0)
            #Note reportlab counts angles anti-clockwise from the horizontal
            #(as in mathematics, e.g. complex numbers and polar coordinates)
            #but we use clockwise from the vertical.  Also reportlab uses
            #degrees, but we use radians.
            p.addArc(self.xcenter, self.ycenter, inner_radius,
                     90 - (endangle * 180 / pi), 90 - (startangle * 180 / pi),
                     moveTo=True)
            p.addArc(self.xcenter, self.ycenter, outer_radius,
                     90 - (endangle * 180 / pi), 90 - (startangle * 180 / pi),
                     reverse=True)
            p.closePath()
            return p
        else:
            #Cheat and just use a four sided polygon.
            # Calculate trig values for angle and coordinates
            startcos, startsin = cos(startangle), sin(startangle)
            endcos, endsin = cos(endangle), sin(endangle)
            x0,y0 = self.xcenter, self.ycenter      # origin of the circle
            x1,y1 = (x0+inner_radius*startsin, y0+inner_radius*startcos)
            x2,y2 = (x0+inner_radius*endsin, y0+inner_radius*endcos)
            x3,y3 = (x0+outer_radius*endsin, y0+outer_radius*endcos)
            x4,y4 = (x0+outer_radius*startsin, y0+outer_radius*startcos)
            return draw_polygon([(x1,y1),(x2,y2),(x3,y3),(x4,y4)], color, border)
Exemple #6
0
    def _draw_arc_arrow(self, inner_radius, outer_radius, startangle, endangle,
                  color, border=None,
                  shaft_height_ratio=0.4, head_length_ratio=0.5, orientation='right',
                  colour=None, **kwargs):
        """Draw an arrow along an arc."""
        #Let the UK spelling (colour) override the USA spelling (color)
        if colour is not None:
            color = colour

        if border is None:
            border = color

        if color is None:
            color = colour
        if color == colors.white and border is None:   # Force black border on 
            strokecolor = colors.black                 # white boxes with
        elif border is None:                           # undefined border, else
            strokecolor = color                        # use fill colour
        elif border is not None:
            strokecolor = border

        #if orientation == 'right':
        #    startangle, endangle = min(startangle, endangle), max(startangle, endangle)
        #elif orientation == 'left':
        #    startangle, endangle = max(startangle, endangle), min(startangle, endangle)
        #else:
        startangle, endangle = min(startangle, endangle), max(startangle, endangle)
        if orientation <> "left" and orientation <> "right":
            raise ValueError("Invalid orientation %s, should be 'left' or 'right'" \
                             % repr(orientation))

        angle = float(endangle - startangle)    # angle subtended by arc
        middle_radius = 0.5*(inner_radius+outer_radius)
        boxheight = outer_radius - inner_radius
        shaft_height = boxheight*shaft_height_ratio
        shaft_inner_radius = middle_radius - 0.5*shaft_height
        shaft_outer_radius = middle_radius + 0.5*shaft_height
        headangle_delta = max(0.0,min(abs(boxheight)*head_length_ratio/middle_radius, abs(angle)))
        if angle < 0:
            headangle_delta *= -1 #reverse it
        if orientation=="right":
            headangle = endangle-headangle_delta
        else:
            headangle = startangle+headangle_delta
        if startangle <= endangle:
            headangle = max(min(headangle, endangle), startangle)
        else:
            headangle = max(min(headangle, startangle), endangle)
        assert startangle <= headangle <= endangle \
            or endangle <= headangle <= startangle, \
            (startangle, headangle, endangle, angle)
        

        # Calculate trig values for angle and coordinates
        startcos, startsin = cos(startangle), sin(startangle)
        headcos, headsin = cos(headangle), sin(headangle)
        endcos, endsin = cos(endangle), sin(endangle)
        x0,y0 = self.xcenter, self.ycenter      # origin of the circle
        if 0.5 >= abs(angle) and abs(headangle_delta) >= abs(angle):
            #If the angle is small, and the arrow is all head,
            #cheat and just use a triangle.
            if orientation=="right":
                x1,y1 = (x0+inner_radius*startsin, y0+inner_radius*startcos)
                x2,y2 = (x0+outer_radius*startsin, y0+outer_radius*startcos)
                x3,y3 = (x0+middle_radius*endsin, y0+middle_radius*endcos)
            else:
                x1,y1 = (x0+inner_radius*endsin, y0+inner_radius*endcos)
                x2,y2 = (x0+outer_radius*endsin, y0+outer_radius*endcos)
                x3,y3 = (x0+middle_radius*startsin, y0+middle_radius*startcos)
            #return draw_polygon([(x1,y1),(x2,y2),(x3,y3)], color, border,
            #                    stroke_line_join=1)
            return Polygon([x1,y1,x2,y2,x3,y3],
                           strokeColor=border or color,
                           fillColor=color,
                           strokeLineJoin=1, #1=round, not mitre!
                           strokewidth=0)
        elif orientation=="right":
            p = ArcPath(strokeColor=strokecolor,
                        fillColor=color,
                        #default is mitre/miter which can stick out too much:
                        strokeLineJoin=1, #1=round
                        strokewidth=0,
                        **kwargs)
            #Note reportlab counts angles anti-clockwise from the horizontal
            #(as in mathematics, e.g. complex numbers and polar coordinates)
            #but we use clockwise from the vertical.  Also reportlab uses
            #degrees, but we use radians.
            p.addArc(self.xcenter, self.ycenter, shaft_inner_radius,
                     90 - (headangle * 180 / pi), 90 - (startangle * 180 / pi),
                     moveTo=True)
            p.addArc(self.xcenter, self.ycenter, shaft_outer_radius,
                     90 - (headangle * 180 / pi), 90 - (startangle * 180 / pi),
                     reverse=True)
            p.lineTo(x0+outer_radius*headsin, y0+outer_radius*headcos)
            if abs(angle) < 0.5:
                p.lineTo(x0+middle_radius*endsin, y0+middle_radius*endcos)
                p.lineTo(x0+inner_radius*headsin, y0+inner_radius*headcos)
            else:
                dx = min(0.1, abs(angle)/50.0) #auto-scale number of steps
                x = dx
                while x < 1:
                    r = outer_radius - x*(outer_radius-middle_radius)
                    a = headangle + x*(endangle-headangle)
                    p.lineTo(x0+r*sin(a), y0+r*cos(a))
                    x += dx
                p.lineTo(x0+middle_radius*endsin, y0+middle_radius*endcos)
                x = dx
                while x < 1:
                    r = middle_radius - x*(middle_radius-inner_radius)
                    a = headangle + (1-x)*(endangle-headangle)
                    p.lineTo(x0+r*sin(a), y0+r*cos(a))
                    x += dx
                p.lineTo(x0+inner_radius*headsin, y0+inner_radius*headcos)
            p.closePath()
            return p
        else:
            p = ArcPath(strokeColor=strokecolor,
                        fillColor=color,
                        #default is mitre/miter which can stick out too much:
                        strokeLineJoin=1, #1=round
                        strokewidth=0,
                        **kwargs)
            #Note reportlab counts angles anti-clockwise from the horizontal
            #(as in mathematics, e.g. complex numbers and polar coordinates)
            #but we use clockwise from the vertical.  Also reportlab uses
            #degrees, but we use radians.
            p.addArc(self.xcenter, self.ycenter, shaft_inner_radius,
                     90 - (endangle * 180 / pi), 90 - (headangle * 180 / pi),
                     moveTo=True, reverse=True)
            p.addArc(self.xcenter, self.ycenter, shaft_outer_radius,
                     90 - (endangle * 180 / pi), 90 - (headangle * 180 / pi),
                     reverse=False)
            p.lineTo(x0+outer_radius*headsin, y0+outer_radius*headcos)
            #TODO - two staight lines is only a good approximation for small
            #head angle, in general will need to curved lines here:
            if abs(angle) < 0.5:
                p.lineTo(x0+middle_radius*startsin, y0+middle_radius*startcos)
                p.lineTo(x0+inner_radius*headsin, y0+inner_radius*headcos)
            else:
                dx = min(0.1, abs(angle)/50.0) #auto-scale number of steps
                x = dx
                while x < 1:
                    r = outer_radius - x*(outer_radius-middle_radius)
                    a = headangle + x*(startangle-headangle)
                    p.lineTo(x0+r*sin(a), y0+r*cos(a))
                    x += dx
                p.lineTo(x0+middle_radius*startsin, y0+middle_radius*startcos)
                x = dx
                while x < 1:
                    r = middle_radius - x*(middle_radius-inner_radius)
                    a = headangle + (1-x)*(startangle-headangle)
                    p.lineTo(x0+r*sin(a), y0+r*cos(a))
                    x += dx
                p.lineTo(x0+inner_radius*headsin, y0+inner_radius*headcos)
            p.closePath()
            return p
Exemple #7
0
    def draw(self):
        slices = self.slices
        _3d_angle = self.angle_3d
        _3dva = self._3dva = _360(_3d_angle+90)
        a0 = _2rad(_3dva)
        self._xdepth_3d = cos(a0)*self.depth_3d
        self._ydepth_3d = sin(a0)*self.depth_3d
        self._cx = self.x+self.width/2.0
        self._cy = self.y+(self.height - self._ydepth_3d)/2.0
        radiusx = radiusy = self._cx-self.x
        if self.xradius: radiusx = self.xradius
        if self.yradius: radiusy = self.yradius
        self._radiusx = radiusx
        self._radiusy = radiusy = (1.0 - self.perspective/100.0)*radiusy
        data = self.normalizeData()
        sum = self._sum

        CX = self.CX
        CY = self.CY
        OX = self.OX
        OY = self.OY
        rad_dist = self.rad_dist
        _fillSide = self._fillSide
        self._seriesCount = n = len(data)
        _sl3d = self._sl3d = []
        g = Group()
        last = _360(self.startAngle)
        a0 = self.direction=='clockwise' and -1 or 1
        for v in data:
            v *= a0
            angle1, angle0 = last, v+last
            last = angle0
            if a0>0: angle0, angle1 = angle1, angle0
            _sl3d.append(_SL3D(angle0,angle1))

        labels = _fixLabels(self.labels,n)
        a0 = _3d_angle
        a1 = _3d_angle+180
        T = []
        S = []
        L = []

        class WedgeLabel3d(WedgeLabel):
            _ydepth_3d = self._ydepth_3d
            def _checkDXY(self,ba):
                if ba[0]=='n':
                    if not hasattr(self,'_ody'):
                        self._ody = self.dy
                        self.dy = -self._ody + self._ydepth_3d
    
        checkLabelOverlap = self.checkLabelOverlap

        for i in xrange(n):
            style = slices[i]
            if not style.visible: continue
            sl = _sl3d[i]
            lo = angle0 = sl.lo
            hi = angle1 = sl.hi
            if abs(hi-lo)<=1e-7: continue
            fillColor = _getShaded(style.fillColor,style.fillColorShaded,style.shading)
            strokeColor = _getShaded(style.strokeColor,style.strokeColorShaded,style.shading) or fillColor
            strokeWidth = style.strokeWidth
            cx0 = CX(i,0)
            cy0 = CY(i,0)
            cx1 = CX(i,1)
            cy1 = CY(i,1)
            #background shaded pie bottom
            g.add(Wedge(cx1,cy1,radiusx, lo, hi,yradius=radiusy,
                            strokeColor=strokeColor,strokeWidth=strokeWidth,fillColor=fillColor,
                            strokeLineJoin=1))
            #connect to top
            if lo < a0 < hi: angle0 = a0
            if lo < a1 < hi: angle1 = a1
            if 1:
                p = ArcPath(strokeColor=strokeColor, fillColor=fillColor,strokeWidth=strokeWidth,strokeLineJoin=1)
                p.addArc(cx1,cy1,radiusx,angle0,angle1,yradius=radiusy,moveTo=1)
                p.lineTo(OX(i,angle1,0),OY(i,angle1,0))
                p.addArc(cx0,cy0,radiusx,angle0,angle1,yradius=radiusy,reverse=1)
                p.closePath()
                if angle0<=_3dva and angle1>=_3dva:
                    rd = 0
                else:
                    rd = min(rad_dist(angle0),rad_dist(angle1))
                S.append((rd,p))
            _fillSide(S,i,lo,strokeColor,strokeWidth,fillColor)
            _fillSide(S,i,hi,strokeColor,strokeWidth,fillColor)

            #bright shaded top
            fillColor = style.fillColor
            strokeColor = style.strokeColor or fillColor
            T.append(Wedge(cx0,cy0,radiusx,lo,hi,yradius=radiusy,
                            strokeColor=strokeColor,strokeWidth=strokeWidth,fillColor=fillColor,strokeLineJoin=1))

            text = labels[i]
            if style.label_visible and text:
                rat = style.labelRadius
                self._radiusx *= rat
                self._radiusy *= rat
                mid = sl.mid
                labelX = OX(i,mid,0)
                labelY = OY(i,mid,0)
                l=_addWedgeLabel(self,text,mid,labelX,labelY,style,labelClass=WedgeLabel3d)
                L.append(l)
                if checkLabelOverlap:
                    l._origdata = { 'x': labelX, 'y':labelY, 'angle': mid,
                                    'rx': self._radiusx, 'ry':self._radiusy, 'cx':CX(i,0), 'cy':CY(i,0),
                                    'bounds': l.getBounds(),
                                    }
                self._radiusx = radiusx
                self._radiusy = radiusy

        S.sort(lambda a,b: -cmp(a[0],b[0]))
        if checkLabelOverlap and L:
            fixLabelOverlaps(L)
        for x in ([s[1] for s in S]+T+L):
            g.add(x)
        return g
Exemple #8
0
    def draw_scale(self, track):
        """ draw_scale(self, track) -> ([element, element,...], [element, element,...])

            o track     Track object

            Returns a tuple of (list of elements in the scale, list of labels
            in the scale)
        """
        scale_elements = []     # holds axes and ticks
        scale_labels = []       # holds labels

        if not track.scale:     # no scale required, exit early
            return [], []

        # Get track locations
        btm, ctr, top = self.track_radii[self.current_track_level]
        trackheight = (top-ctr)
        
        # X-axis
        if self.sweep < 1:
            #Draw an arc, leaving out the wedge
            p = ArcPath(strokeColor=track.scale_color, fillColor=None)
            #Note reportlab counts angles anti-clockwise from the horizontal
            #(as in mathematics, e.g. complex numbers and polar coordinates)
            #in degrees.
            p.addArc(self.xcenter, self.ycenter, ctr,
                     startangledegrees=90-360*self.sweep,
                     endangledegrees=90)
            scale_elements.append(p)
            del p
        else:
            #Draw a full circle
            scale_elements.append(Circle(self.xcenter, self.ycenter, ctr,
                                         strokeColor=track.scale_color,
                                         fillColor=None))

        if track.scale_ticks:   # Ticks are required on the scale
            # Draw large ticks 
            #I want the ticks to be consistently positioned relative to
            #the start of the sequence (position 0), not relative to the
            #current viewpoint (self.start and self.end)

            ticklen = track.scale_largeticks * trackheight
            tickiterval = int(track.scale_largetick_interval)
            #Note that we could just start the list of ticks using
            #range(0,self.end,tickinterval) and the filter out the
            #ones before self.start - but this seems wasteful.
            #Using tickiterval * (self.start/tickiterval) is a shortcut.
            largeticks = [pos for pos \
                          in range(tickiterval * (self.start/tickiterval),
                                   int(self.end),
                                   tickiterval) \
                          if pos >= self.start]
            for tickpos in largeticks:
                tick, label = self.draw_tick(tickpos, ctr, ticklen,
                                             track,
                                             track.scale_largetick_labels)
                scale_elements.append(tick)
                if label is not None:   # If there's a label, add it
                    scale_labels.append(label)
            # Draw small ticks
            ticklen = track.scale_smallticks * trackheight
            tickiterval = int(track.scale_smalltick_interval)
            smallticks = [pos for pos \
                          in range(tickiterval * (self.start/tickiterval),
                                   int(self.end),
                                   tickiterval) \
                          if pos >= self.start]
            for tickpos in smallticks:
                tick, label = self.draw_tick(tickpos, ctr, ticklen,
                                             track,
                                             track.scale_smalltick_labels)
                scale_elements.append(tick)
                if label is not None:   # If there's a label, add it
                    scale_labels.append(label)
        
        # Check to see if the track contains a graph - if it does, get the
        # minimum and maximum values, and put them on the scale Y-axis
        # at 60 degree intervals, ordering the labels by graph_id
        if track.axis_labels:
            for set in track.get_sets():
                if set.__class__ is GraphSet:
                    # Y-axis
                    for n in xrange(7):
                        angle = n * 1.0471975511965976
                        ticksin, tickcos = sin(angle), cos(angle)
                        x0, y0 = self.xcenter+btm*ticksin, self.ycenter+btm*tickcos
                        x1, y1 = self.xcenter+top*ticksin, self.ycenter+top*tickcos
                        scale_elements.append(Line(x0, y0, x1, y1,
                                                   strokeColor=track.scale_color))

                        graph_label_min = []
                        graph_label_max = []
                        graph_label_mid = []
                        for graph in set.get_graphs():                        
                            quartiles = graph.quartiles()
                            minval, maxval = quartiles[0], quartiles[4]
                            if graph.center is None:
                                midval = (maxval + minval)/2.
                                graph_label_min.append("%.3f" % minval)
                                graph_label_max.append("%.3f" % maxval)
                                graph_label_mid.append("%.3f" % midval)
                            else:
                                diff = max((graph.center-minval),
                                           (maxval-graph.center))
                                minval = graph.center-diff
                                maxval = graph.center+diff
                                midval = graph.center
                                graph_label_mid.append("%.3f" % midval)
                                graph_label_min.append("%.3f" % minval)
                                graph_label_max.append("%.3f" % maxval)
                        xmid, ymid = (x0+x1)/2., (y0+y1)/2.
                        for limit, x, y, in [(graph_label_min, x0, y0),
                                             (graph_label_max, x1, y1),
                                             (graph_label_mid, xmid, ymid)]:
                            label = String(0, 0, ";".join(limit),
                                           fontName=track.scale_font,
                                           fontSize=track.scale_fontsize,
                                           fillColor=track.scale_color)
                            label.textAnchor = 'middle'
                            labelgroup = Group(label)
                            labelgroup.transform = (tickcos, -ticksin,
                                                    ticksin, tickcos,
                                                    x, y)
                            scale_labels.append(labelgroup)

        return scale_elements, scale_labels
    def _draw_arc(self,
                  inner_radius,
                  outer_radius,
                  startangle,
                  endangle,
                  color,
                  border=None,
                  colour=None,
                  **kwargs):
        """ draw_arc(self, inner_radius, outer_radius, startangle, endangle, color)
                -> Group

            o inner_radius  Float distance of inside of arc from drawing center

            o outer_radius  Float distance of outside of arc from drawing center

            o startangle    Float angle subtended by start of arc at drawing center
                            (in radians)

            o endangle      Float angle subtended by end of arc at drawing center
                            (in radians)

            o color        colors.Color object for arc (overridden by backwards
                           compatible argument with UK spelling, colour).

            Returns a closed path object describing an arced box corresponding to
            the passed values.  For very small angles, a simple four sided
            polygon is used.
        """
        #Let the UK spelling (colour) override the USA spelling (color)
        if colour is not None:
            color = colour

        if border is None:
            border = color

        if color is None:
            color = colour
        if color == colors.white and border is None:  # Force black border on
            strokecolor = colors.black  # white boxes with
        elif border is None:  # undefined border, else
            strokecolor = color  # use fill colour
        elif border is not None:
            strokecolor = border

        angle = float(endangle - startangle)  # angle subtended by arc
        if angle > .01:  # Wide arc, represent with multiple boxes
            p = ArcPath(strokeColor=strokecolor,
                        fillColor=color,
                        strokewidth=0)
            #Note reportlab counts angles anti-clockwise from the horizontal
            #(as in mathematics, e.g. complex numbers and polar coordinates)
            #but we use clockwise from the vertical.  Also reportlab uses
            #degrees, but we use radians.
            p.addArc(self.xcenter,
                     self.ycenter,
                     inner_radius,
                     90 - (endangle * 180 / pi),
                     90 - (startangle * 180 / pi),
                     moveTo=True)
            p.addArc(self.xcenter,
                     self.ycenter,
                     outer_radius,
                     90 - (endangle * 180 / pi),
                     90 - (startangle * 180 / pi),
                     reverse=True)
            p.closePath()
            return p
        else:
            #Cheat and just use a four sided polygon.
            # Calculate trig values for angle and coordinates
            startcos, startsin = cos(startangle), sin(startangle)
            endcos, endsin = cos(endangle), sin(endangle)
            boxes = Group()  # Holds arc elements
            x0, y0 = self.xcenter, self.ycenter  # origin of the circle
            x1, y1 = (x0 + inner_radius * startsin,
                      y0 + inner_radius * startcos)
            x2, y2 = (x0 + inner_radius * endsin, y0 + inner_radius * endcos)
            x3, y3 = (x0 + outer_radius * endsin, y0 + outer_radius * endcos)
            x4, y4 = (x0 + outer_radius * startsin,
                      y0 + outer_radius * startcos)
            return draw_polygon([(x1, y1), (x2, y2), (x3, y3), (x4, y4)],
                                color, border)
Exemple #10
0
    def __init__(self, specification, drawing_callable, pages_to_draw=None,
            border=False, shade_missing=False, direction="across"):
        """
        Parameters
        ----------
        specification: labels.Specification instance
            The sizes etc of the label sheets.
        drawing_callable: callable
            A function (or other callable object) to call to draw an individual
            label. It will be given four parameters specifying the label. In
            order, these are a `reportlab.graphics.shapes.Drawing` instance to
            draw the label on, the width of the label, the height of the label,
            and the object to draw. The dimensions will be in points, the unit
            of choice for ReportLab.
        pages_to_draw: list of positive integers, default None
            The list pages to actually draw labels on. This is intended to be
            used with the preview methods to avoid drawing labels that will
            never be displayed. A value of None means draw all pages.
        border: Boolean, default False
            Whether or not to draw a border around each label.
        shade_missing: Boolean or ReportLab colour, default False
            Whether or not to shade missing labels (those specified through the
            partial_pages method). False means leave the labels unshaded. If a
            ReportLab colour is given, the labels will be shaded in that colour.
            A value of True will result in the missing labels being shaded in
            the hex colour 0xBBBBBB (a medium-light grey).
        direction: String, either "across" or "down" to indication the order
            labels will be assigned. Default is across.

        Notes
        -----
        If you specify a pages_to_draw list, pages not in that list will be
        blank since the drawing function will not be called on that page. This
        could have a side-affect if you rely on the drawing function modifying
        some global values. For example, in the nametags.py and preview.py demo
        scripts, the colours for each label are picked by a pseduo-random number
        generator. However, in the preview script, this generator is not
        advanced and so the colours on the last page differ between the preview
        and the actual output.

        """
        # Save our arguments.
        specification._calculate()
        self.specs = deepcopy(specification)
        self.drawing_callable = drawing_callable
        self.pages_to_draw = pages_to_draw
        self.border = border
        if shade_missing == True:
            self.shade_missing = colors.HexColor(0xBBBBBB)
        else:
            self.shade_missing = shade_missing

        # Set up some internal variables.
        self._lw = self.specs.label_width * mm
        self._lh = self.specs.label_height * mm
        self._cr = self.specs.corner_radius * mm
        self._dw = (self.specs.label_width - self.specs.left_padding - self.specs.right_padding) * mm
        self._dh = (self.specs.label_height - self.specs.top_padding - self.specs.bottom_padding) * mm
        self._lp = self.specs.left_padding * mm
        self._bp = self.specs.bottom_padding * mm
        self._pr = self.specs.padding_radius * mm
        self._used = {}
        self._pages = []
        self._current_page = None

        # Page information.
        self._pagesize = (float(self.specs.sheet_width*mm), float(self.specs.sheet_height*mm))
        self._numlabels = (self.specs.rows, self.specs.columns)
        self._position = None
        self.label_count = 0
        self.page_count = 0
        if direction == "vertical":
            self._positionIteratorFunc = specification.verticalPosIterator
        else:
            self._positionIteratorFunc = specification.horizontalPosIterator

        # Background image.
        if self.specs.background_image:
            self._bgimage = deepcopy(self.specs.background_image)

            # Different classes are scaled in different ways...
            if isinstance(self._bgimage, Image):
                self._bgimage.x = 0
                self._bgimage.y = 0
                self._bgimage.width = self._pagesize[0]
                self._bgimage.height = self._pagesize[1]
            elif isinstance(self._bgimage, Drawing):
                self._bgimage.shift(0, 0)
                self._bgimage.scale(self._pagesize[0]/self._bgimage.width, self._pagesize[1]/self._bgimage.height)
            else:
                raise ValueError("Unhandled background type.")

        # Background from a filename.
        elif self.specs.background_filename:
            self._bgimage = Image(0, 0, self._pagesize[0], self._pagesize[1], self.specs.background_filename)

        # No background.
        else:
            self._bgimage = None

        # Borders and clipping paths. We need two clipping paths; one for the
        # label as a whole (which is identical to the border), and one for the
        # available drawing area (i.e., after taking the padding into account).
        # This is necessary because sometimes the drawing area can extend
        # outside the border at the corners, e.g., if there is left padding
        # only and no padding radius, then the 'available' area corners will be
        # square and go outside the label corners if they are rounded.

        # Copy some properties to a local scope.
        h, w, r = float(self._lh), float(self._lw), float(self._cr)

        # Create the border from a path. If the corners are not rounded, skip
        # adding the arcs.
        border = ArcPath()
        if r:
            border.moveTo(w - r, 0)
            border.addArc(w - r, r, r, -90, 0)
            border.lineTo(w, h - r)
            border.addArc(w - r, h - r, r, 0, 90)
            border.lineTo(r, h)
            border.addArc(r, h - r, r, 90, 180)
            border.lineTo(0, r)
            border.addArc(r, r, r, 180, 270)
            border.closePath()
        else:
            border.moveTo(0, 0)
            border.lineTo(w, 0)
            border.lineTo(w, h)
            border.lineTo(0, h)
            border.closePath()

        # Set the properties and store.
        border.isClipPath = 0
        border.strokeWidth = 1
        border.strokeColor = colors.black
        border.fillColor = None
        self._border = border

        # Clip path for the label is the same as the border.
        self._clip_label = deepcopy(border)
        self._clip_label.isClipPath = 1
        self._clip_label.strokeColor = None
        self._clip_label.fillColor = None

        # If there is no padding (i.e., the drawable area is the same as the
        # label area) then we can just use the label clip path for the drawing
        # clip path.
        if (self._dw == self._lw) and (self._dh == self._lh):
            self._clip_drawing = self._clip_label

        # Otherwise we have to generate a separate path.
        else:
            h, w, r = float(self._dh), float(self._dw), float(self._pr)
            clip = ArcPath()
            if r:
                clip.moveTo(w - r, 0)
                clip.addArc(w - r, r, r, -90, 0)
                clip.lineTo(w, h - r)
                clip.addArc(w - r, h - r, r, 0, 90)
                clip.lineTo(r, h)
                clip.addArc(r, h - r, r, 90, 180)
                clip.lineTo(0, r)
                clip.addArc(r, r, r, 180, 270)
                clip.closePath()
            else:
                clip.moveTo(0, 0)
                clip.lineTo(w, 0)
                clip.lineTo(w, h)
                clip.lineTo(0, h)
                clip.closePath()

            # Set the clipping properties.
            clip.isClipPath = 1
            clip.strokeColor = None
            clip.fillColor = None
            self._clip_drawing = clip
    def draw_scale(self, track):
        """ draw_scale(self, track) -> ([element, element,...], [element, element,...])

            o track     Track object

            Returns a tuple of (list of elements in the scale, list of labels
            in the scale)
        """
        scale_elements = []  # holds axes and ticks
        scale_labels = []  # holds labels

        if not track.scale:  # no scale required, exit early
            return [], []

        # Get track locations
        btm, ctr, top = self.track_radii[self.current_track_level]
        trackheight = (top - ctr)

        # X-axis
        if self.sweep < 1:
            #Draw an arc, leaving out the wedge
            p = ArcPath(strokeColor=track.scale_color, fillColor=None)
            #Note reportlab counts angles anti-clockwise from the horizontal
            #(as in mathematics, e.g. complex numbers and polar coordinates)
            #in degrees.
            p.addArc(self.xcenter,
                     self.ycenter,
                     ctr,
                     startangledegrees=90 - 360 * self.sweep,
                     endangledegrees=90)
            scale_elements.append(p)
            del p
        else:
            #Draw a full circle
            scale_elements.append(
                Circle(self.xcenter,
                       self.ycenter,
                       ctr,
                       strokeColor=track.scale_color,
                       fillColor=None))

        if track.scale_ticks:  # Ticks are required on the scale
            # Draw large ticks
            #I want the ticks to be consistently positioned relative to
            #the start of the sequence (position 0), not relative to the
            #current viewpoint (self.start and self.end)

            ticklen = track.scale_largeticks * trackheight
            tickiterval = int(track.scale_largetick_interval)
            #Note that we could just start the list of ticks using
            #range(0,self.end,tickinterval) and the filter out the
            #ones before self.start - but this seems wasteful.
            #Using tickiterval * (self.start/tickiterval) is a shortcut.
            largeticks = [pos for pos \
                          in range(tickiterval * (self.start/tickiterval),
                                   int(self.end),
                                   tickiterval) \
                          if pos >= self.start]
            for tickpos in largeticks:
                tick, label = self.draw_tick(tickpos, ctr, ticklen, track,
                                             track.scale_largetick_labels)
                scale_elements.append(tick)
                if label is not None:  # If there's a label, add it
                    scale_labels.append(label)
            # Draw small ticks
            ticklen = track.scale_smallticks * trackheight
            tickiterval = int(track.scale_smalltick_interval)
            smallticks = [pos for pos \
                          in range(tickiterval * (self.start/tickiterval),
                                   int(self.end),
                                   tickiterval) \
                          if pos >= self.start]
            for tickpos in smallticks:
                tick, label = self.draw_tick(tickpos, ctr, ticklen, track,
                                             track.scale_smalltick_labels)
                scale_elements.append(tick)
                if label is not None:  # If there's a label, add it
                    scale_labels.append(label)

        # Check to see if the track contains a graph - if it does, get the
        # minimum and maximum values, and put them on the scale Y-axis
        # at 60 degree intervals, ordering the labels by graph_id
        if track.axis_labels:
            for set in track.get_sets():
                if set.__class__ is GraphSet:
                    # Y-axis
                    for n in xrange(7):
                        angle = n * 1.0471975511965976
                        ticksin, tickcos = sin(angle), cos(angle)
                        x0, y0 = self.xcenter + btm * ticksin, self.ycenter + btm * tickcos
                        x1, y1 = self.xcenter + top * ticksin, self.ycenter + top * tickcos
                        scale_elements.append(
                            Line(x0, y0, x1, y1,
                                 strokeColor=track.scale_color))

                        graph_label_min = []
                        graph_label_max = []
                        graph_label_mid = []
                        for graph in set.get_graphs():
                            quartiles = graph.quartiles()
                            minval, maxval = quartiles[0], quartiles[4]
                            if graph.center is None:
                                midval = (maxval + minval) / 2.
                                graph_label_min.append("%.3f" % minval)
                                graph_label_max.append("%.3f" % maxval)
                                graph_label_mid.append("%.3f" % midval)
                            else:
                                diff = max((graph.center - minval),
                                           (maxval - graph.center))
                                minval = graph.center - diff
                                maxval = graph.center + diff
                                midval = graph.center
                                graph_label_mid.append("%.3f" % midval)
                                graph_label_min.append("%.3f" % minval)
                                graph_label_max.append("%.3f" % maxval)
                        xmid, ymid = (x0 + x1) / 2., (y0 + y1) / 2.
                        for limit, x, y, in [(graph_label_min, x0, y0),
                                             (graph_label_max, x1, y1),
                                             (graph_label_mid, xmid, ymid)]:
                            label = String(0,
                                           0,
                                           join(limit, ';'),
                                           fontName=track.scale_font,
                                           fontSize=track.scale_fontsize,
                                           fillColor=track.scale_color)
                            label.textAnchor = 'middle'
                            labelgroup = Group(label)
                            labelgroup.transform = (tickcos, -ticksin, ticksin,
                                                    tickcos, x, y)
                            scale_labels.append(labelgroup)

        return scale_elements, scale_labels
    def _draw_arc_arrow(self,
                        inner_radius,
                        outer_radius,
                        startangle,
                        endangle,
                        color,
                        border=None,
                        shaft_height_ratio=0.4,
                        head_length_ratio=1.0,
                        orientation='right',
                        colour=None,
                        **kwargs):
        """Draw an arrow along an arc."""
        #Let the UK spelling (colour) override the USA spelling (color)
        if colour is not None:
            color = colour

        if border is None:
            border = color

        if color is None:
            color = colour
        if color == colors.white and border is None:  # Force black border on
            strokecolor = colors.black  # white boxes with
        elif border is None:  # undefined border, else
            strokecolor = color  # use fill colour
        elif border is not None:
            strokecolor = border

        #if orientation == 'right':
        #    startangle, endangle = min(startangle, endangle), max(startangle, endangle)
        #elif orientation == 'left':
        #    startangle, endangle = max(startangle, endangle), min(startangle, endangle)
        #else :
        startangle, endangle = min(startangle,
                                   endangle), max(startangle, endangle)
        if orientation <> "left" and orientation <> "right":
            raise ValueError("Invalid orientation %s, should be 'left' or 'right'" \
                             % repr(orientation))

        angle = float(endangle - startangle)  # angle subtended by arc
        middle_radius = 0.5 * (inner_radius + outer_radius)
        boxheight = outer_radius - inner_radius
        shaft_height = boxheight * shaft_height_ratio
        shaft_inner_radius = middle_radius - 0.5 * shaft_height
        shaft_outer_radius = middle_radius + 0.5 * shaft_height
        headangle_delta = min(
            abs(asin(boxheight / middle_radius) * head_length_ratio),
            abs(angle))
        if angle < 0:
            headangle_delta *= -1  #reverse it
        if orientation == "right":
            headangle = endangle - headangle_delta
        else:
            headangle = startangle + headangle_delta
        if startangle <= endangle:
            headangle = max(min(headangle, endangle), startangle)
        else:
            headangle = max(min(headangle, startangle), endangle)
        assert startangle <= headangle <= endangle \
            or endangle <= headangle <= startangle

        # Calculate trig values for angle and coordinates
        startcos, startsin = cos(startangle), sin(startangle)
        headcos, headsin = cos(headangle), sin(headangle)
        endcos, endsin = cos(endangle), sin(endangle)
        x0, y0 = self.xcenter, self.ycenter  # origin of the circle
        if abs(headangle_delta) >= abs(angle):
            #Cheat and just use a triangle.
            boxes = Group()  # Holds arc elements
            if orientation == "right":
                x1, y1 = (x0 + inner_radius * startsin,
                          y0 + inner_radius * startcos)
                x2, y2 = (x0 + outer_radius * startsin,
                          y0 + outer_radius * startcos)
                x3, y3 = (x0 + middle_radius * endsin,
                          y0 + middle_radius * endcos)
            else:
                x1, y1 = (x0 + inner_radius * endsin,
                          y0 + inner_radius * endcos)
                x2, y2 = (x0 + outer_radius * endsin,
                          y0 + outer_radius * endcos)
                x3, y3 = (x0 + middle_radius * startsin,
                          y0 + middle_radius * startcos)
            return draw_polygon([(x1, y1), (x2, y2), (x3, y3)], color, border)
        elif orientation == "right":
            p = ArcPath(strokeColor=strokecolor,
                        fillColor=color,
                        strokewidth=0)
            #Note reportlab counts angles anti-clockwise from the horizontal
            #(as in mathematics, e.g. complex numbers and polar coordinates)
            #but we use clockwise from the vertical.  Also reportlab uses
            #degrees, but we use radians.
            p.addArc(self.xcenter,
                     self.ycenter,
                     shaft_inner_radius,
                     90 - (headangle * 180 / pi),
                     90 - (startangle * 180 / pi),
                     moveTo=True)
            p.addArc(self.xcenter,
                     self.ycenter,
                     shaft_outer_radius,
                     90 - (headangle * 180 / pi),
                     90 - (startangle * 180 / pi),
                     reverse=True)
            p.lineTo(x0 + outer_radius * headsin, y0 + outer_radius * headcos)
            p.lineTo(x0 + middle_radius * endsin, y0 + middle_radius * endcos)
            p.lineTo(x0 + inner_radius * headsin, y0 + inner_radius * headcos)
            p.closePath()
            return p
        else:
            p = ArcPath(strokeColor=strokecolor,
                        fillColor=color,
                        strokewidth=0)
            #Note reportlab counts angles anti-clockwise from the horizontal
            #(as in mathematics, e.g. complex numbers and polar coordinates)
            #but we use clockwise from the vertical.  Also reportlab uses
            #degrees, but we use radians.
            p.addArc(self.xcenter,
                     self.ycenter,
                     shaft_inner_radius,
                     90 - (endangle * 180 / pi),
                     90 - (headangle * 180 / pi),
                     moveTo=True,
                     reverse=True)
            p.addArc(self.xcenter,
                     self.ycenter,
                     shaft_outer_radius,
                     90 - (endangle * 180 / pi),
                     90 - (headangle * 180 / pi),
                     reverse=False)
            p.lineTo(x0 + outer_radius * headsin, y0 + outer_radius * headcos)
            p.lineTo(x0 + middle_radius * startsin,
                     y0 + middle_radius * startcos)
            p.lineTo(x0 + inner_radius * headsin, y0 + inner_radius * headcos)
            p.closePath()
            return p
Exemple #13
0
    def _draw_arc_arrow(self, inner_radius, outer_radius, startangle, endangle,
                  color, border=None,
                  shaft_height_ratio=0.4, head_length_ratio=1.0, orientation='right',
                  colour=None, **kwargs):
        """Draw an arrow along an arc."""
        #Let the UK spelling (colour) override the USA spelling (color)
        if colour is not None:
            color = colour

        if border is None:
            border = color

        if color is None:
            color = colour
        if color == colors.white and border is None:   # Force black border on 
            strokecolor = colors.black                 # white boxes with
        elif border is None:                           # undefined border, else
            strokecolor = color                        # use fill colour
        elif border is not None:
            strokecolor = border

        #if orientation == 'right':
        #    startangle, endangle = min(startangle, endangle), max(startangle, endangle)
        #elif orientation == 'left':
        #    startangle, endangle = max(startangle, endangle), min(startangle, endangle)
        #else :
        startangle, endangle = min(startangle, endangle), max(startangle, endangle)
        if orientation <> "left" and orientation <> "right" :
            raise ValueError("Invalid orientation %s, should be 'left' or 'right'" \
                             % repr(orientation))

        angle = float(endangle - startangle)    # angle subtended by arc
        middle_radius = 0.5*(inner_radius+outer_radius)
        boxheight = outer_radius - inner_radius
        shaft_height = boxheight*shaft_height_ratio
        shaft_inner_radius = middle_radius - 0.5*shaft_height
        shaft_outer_radius = middle_radius + 0.5*shaft_height
        headangle_delta = min(abs(asin(boxheight/middle_radius)*head_length_ratio), abs(angle))
        if angle < 0 :
            headangle_delta *= -1 #reverse it
        if orientation=="right" :
            headangle = endangle-headangle_delta
        else :
            headangle = startangle+headangle_delta
        if startangle <= endangle :
            headangle = max(min(headangle, endangle), startangle)
        else :
            headangle = max(min(headangle, startangle), endangle)
        assert startangle <= headangle <= endangle \
            or endangle <= headangle <= startangle
        

        # Calculate trig values for angle and coordinates
        startcos, startsin = cos(startangle), sin(startangle)
        headcos, headsin = cos(headangle), sin(headangle)
        endcos, endsin = cos(endangle), sin(endangle)
        x0,y0 = self.xcenter, self.ycenter      # origin of the circle
        if abs(headangle_delta) >= abs(angle) :
            #Cheat and just use a triangle.
            if orientation=="right" :
                x1,y1 = (x0+inner_radius*startsin, y0+inner_radius*startcos)
                x2,y2 = (x0+outer_radius*startsin, y0+outer_radius*startcos)
                x3,y3 = (x0+middle_radius*endsin, y0+middle_radius*endcos)
            else :
                x1,y1 = (x0+inner_radius*endsin, y0+inner_radius*endcos)
                x2,y2 = (x0+outer_radius*endsin, y0+outer_radius*endcos)
                x3,y3 = (x0+middle_radius*startsin, y0+middle_radius*startcos)
            return draw_polygon([(x1,y1),(x2,y2),(x3,y3)], color, border)
        elif orientation=="right" :
            p = ArcPath(strokeColor=strokecolor,
                        fillColor=color,
                        strokewidth=0)
            #Note reportlab counts angles anti-clockwise from the horizontal
            #(as in mathematics, e.g. complex numbers and polar coordinates)
            #but we use clockwise from the vertical.  Also reportlab uses
            #degrees, but we use radians.
            p.addArc(self.xcenter, self.ycenter, shaft_inner_radius,
                     90 - (headangle * 180 / pi), 90 - (startangle * 180 / pi),
                     moveTo=True)
            p.addArc(self.xcenter, self.ycenter, shaft_outer_radius,
                     90 - (headangle * 180 / pi), 90 - (startangle * 180 / pi),
                     reverse=True)
            p.lineTo(x0+outer_radius*headsin, y0+outer_radius*headcos)
            p.lineTo(x0+middle_radius*endsin, y0+middle_radius*endcos)
            p.lineTo(x0+inner_radius*headsin, y0+inner_radius*headcos)
            p.closePath()
            return p
        else :
            p = ArcPath(strokeColor=strokecolor,
                        fillColor=color,
                        strokewidth=0)
            #Note reportlab counts angles anti-clockwise from the horizontal
            #(as in mathematics, e.g. complex numbers and polar coordinates)
            #but we use clockwise from the vertical.  Also reportlab uses
            #degrees, but we use radians.
            p.addArc(self.xcenter, self.ycenter, shaft_inner_radius,
                     90 - (endangle * 180 / pi), 90 - (headangle * 180 / pi),
                     moveTo=True, reverse=True)
            p.addArc(self.xcenter, self.ycenter, shaft_outer_radius,
                     90 - (endangle * 180 / pi), 90 - (headangle * 180 / pi),
                     reverse=False)
            p.lineTo(x0+outer_radius*headsin, y0+outer_radius*headcos)
            p.lineTo(x0+middle_radius*startsin, y0+middle_radius*startcos)
            p.lineTo(x0+inner_radius*headsin, y0+inner_radius*headcos)
            p.closePath()
            return p
Exemple #14
0
    def __init__(self, specification, drawing_callable, pages_to_draw=None, border=False, shade_missing=False):
        """
        Parameters
        ----------
        specification: labels.Specification instance
            The sizes etc of the label sheets.
        drawing_callable: callable
            A function (or other callable object) to call to draw an individual
            label. It will be given four parameters specifying the label. In
            order, these are a `reportlab.graphics.shapes.Drawing` instance to
            draw the label on, the width of the label, the height of the label,
            and the object to draw. The dimensions will be in points, the unit
            of choice for ReportLab.
        pages_to_draw: list of positive integers, default None
            The list pages to actually draw labels on. This is intended to be
            used with the preview methods to avoid drawing labels that will
            never be displayed. A value of None means draw all pages.
        border: Boolean, default False
            Whether or not to draw a border around each label.
        shade_missing: Boolean or ReportLab colour, default False
            Whether or not to shade missing labels (those specified through the
            partial_pages method). False means leave the labels unshaded. If a
            ReportLab colour is given, the labels will be shaded in that colour.
            A value of True will result in the missing labels being shaded in
            the hex colour 0xBBBBBB (a medium-light grey).

        Notes
        -----
        If you specify a pages_to_draw list, pages not in that list will be
        blank since the drawing function will not be called on that page. This
        could have a side-affect if you rely on the drawing function modifying
        some global values. For example, in the nametags.py and preview.py demo
        scripts, the colours for each label are picked by a pseduo-random number
        generator. However, in the preview script, this generator is not
        advanced and so the colours on the last page differ between the preview
        and the actual output.

        """
        # Save our arguments.
        specification._calculate()
        self.specs = deepcopy(specification)
        self.drawing_callable = drawing_callable
        self.pages_to_draw = pages_to_draw
        self.border = border
        if shade_missing == True:
            self.shade_missing = colors.HexColor(0xBBBBBB)
        else:
            self.shade_missing = shade_missing

        # Set up some internal variables.
        self._lw = self.specs.label_width * mm
        self._lh = self.specs.label_height * mm
        self._cr = self.specs.corner_radius * mm
        self._dw = (self.specs.label_width - self.specs.left_padding - self.specs.right_padding) * mm
        self._dh = (self.specs.label_height - self.specs.top_padding - self.specs.bottom_padding) * mm
        self._lp = self.specs.left_padding * mm
        self._bp = self.specs.bottom_padding * mm
        self._pr = self.specs.padding_radius * mm
        self._used = {}
        self._pages = []
        self._current_page = None

        # Page information.
        self._pagesize = (float(self.specs.sheet_width * mm), float(self.specs.sheet_height * mm))
        self._numlabels = [self.specs.rows, self.specs.columns]
        self._position = [1, 0]
        self.label_count = 0
        self.page_count = 0

        # Background image.
        if self.specs.background_image:
            self._bgimage = deepcopy(self.specs.background_image)

            # Different classes are scaled in different ways...
            if isinstance(self._bgimage, Image):
                self._bgimage.x = 0
                self._bgimage.y = 0
                self._bgimage.width = self._pagesize[0]
                self._bgimage.height = self._pagesize[1]
            elif isinstance(self._bgimage, Drawing):
                self._bgimage.shift(0, 0)
                self._bgimage.scale(self._pagesize[0] / self._bgimage.width, self._pagesize[1] / self._bgimage.height)
            else:
                raise ValueError("Unhandled background type.")

        # Background from a filename.
        elif self.specs.background_filename:
            self._bgimage = Image(0, 0, self._pagesize[0], self._pagesize[1], self.specs.background_filename)

        # No background.
        else:
            self._bgimage = None

        # Borders and clipping paths. We need two clipping paths; one for the
        # label as a whole (which is identical to the border), and one for the
        # available drawing area (i.e., after taking the padding into account).
        # This is necessary because sometimes the drawing area can extend
        # outside the border at the corners, e.g., if there is left padding
        # only and no padding radius, then the 'available' area corners will be
        # square and go outside the label corners if they are rounded.

        # Copy some properties to a local scope.
        h, w, r = float(self._lh), float(self._lw), float(self._cr)

        # Create the border from a path. If the corners are not rounded, skip
        # adding the arcs.
        border = ArcPath()
        if r:
            border.moveTo(w - r, 0)
            border.addArc(w - r, r, r, -90, 0)
            border.lineTo(w, h - r)
            border.addArc(w - r, h - r, r, 0, 90)
            border.lineTo(r, h)
            border.addArc(r, h - r, r, 90, 180)
            border.lineTo(0, r)
            border.addArc(r, r, r, 180, 270)
            border.closePath()
        else:
            border.moveTo(0, 0)
            border.lineTo(w, 0)
            border.lineTo(w, h)
            border.lineTo(0, h)
            border.closePath()

        # Set the properties and store.
        border.isClipPath = 0
        border.strokeWidth = 1
        border.strokeColor = colors.black
        border.fillColor = None
        self._border = border

        # Clip path for the label is the same as the border.
        self._clip_label = deepcopy(border)
        self._clip_label.isClipPath = 1
        self._clip_label.strokeColor = None
        self._clip_label.fillColor = None

        # If there is no padding (i.e., the drawable area is the same as the
        # label area) then we can just use the label clip path for the drawing
        # clip path.
        if (self._dw == self._lw) and (self._dh == self._lh):
            self._clip_drawing = self._clip_label

        # Otherwise we have to generate a separate path.
        else:
            h, w, r = float(self._dh), float(self._dw), float(self._pr)
            clip = ArcPath()
            if r:
                clip.moveTo(w - r, 0)
                clip.addArc(w - r, r, r, -90, 0)
                clip.lineTo(w, h - r)
                clip.addArc(w - r, h - r, r, 0, 90)
                clip.lineTo(r, h)
                clip.addArc(r, h - r, r, 90, 180)
                clip.lineTo(0, r)
                clip.addArc(r, r, r, 180, 270)
                clip.closePath()
            else:
                clip.moveTo(0, 0)
                clip.lineTo(w, 0)
                clip.lineTo(w, h)
                clip.lineTo(0, h)
                clip.closePath()

            # Set the clipping properties.
            clip.isClipPath = 1
            clip.strokeColor = None
            clip.fillColor = None
            self._clip_drawing = clip
Exemple #15
0
    def __init__(self, specification, drawing_callable, pages_to_draw=None, border=False, shade_missing=False):
        """
        Parameters
        ----------
        specification: labels.Specification instance
            The sizes etc of the label sheets.
        drawing_callable: callable
            A function (or other callable object) to call to draw an individual
            label. It will be given four parameters specifying the label. In
            order, these are a `reportlab.graphics.shapes.Drawing` instance to
            draw the label on, the width of the label, the height of the label,
            and the object to draw. The dimensions will be in points, the unit
            of choice for ReportLab.
        pages_to_draw: list of positive integers, default None
            The list pages to actually draw labels on. This is intended to be
            used with the preview methods to avoid drawing labels that will
            never be displayed. A value of None means draw all pages.
        border: Boolean, default False
            Whether or not to draw a border around each label.
        shade_missing: Boolean or ReportLab colour, default False
            Whether or not to shade missing labels (those specified through the
            partial_pages method). False means leave the labels unshaded. If a
            ReportLab colour is given, the labels will be shaded in that colour.
            A value of True will result in the missing labels being shaded in
            the hex colour 0xBBBBBB (a medium-light grey).

        Notes
        -----
        If you specify a pages_to_draw list, pages not in that list will be
        blank since the drawing function will not be called on that page. This
        could have a side-affect if you rely on the drawing function modifying
        some global values. For example, in the nametags.py and preview.py demo
        scripts, the colours for each label are picked by a pseduo-random number
        generator. However, in the preview script, this generator is not
        advanced and so the colours on the last page differ between the preview
        and the actual output.

        """
        # Save our arguments.
        specification._calculate()
        self.specs = deepcopy(specification)
        self.drawing_callable = drawing_callable
        self.pages_to_draw = pages_to_draw
        self.border = border
        if shade_missing == True:
            self.shade_missing = colors.HexColor(0xBBBBBB)
        else:
            self.shade_missing = shade_missing

        # Set up some internal variables.
        self._lw = self.specs.label_width * mm
        self._lh = self.specs.label_height * mm
        self._cr = self.specs.corner_radius * mm
        self._used = {}
        self._pages = []
        self._current_page = None

        # Page information.
        self._pagesize = (float(self.specs.sheet_width*mm), float(self.specs.sheet_height*mm))
        self._numlabels = [self.specs.rows, self.specs.columns]
        self._position = [1, 0]
        self.label_count = 0
        self.page_count = 0

        # Have to create the border from a path so we can use it as a clip path.
        border = ArcPath()

        # Copy some properties to a local scope.
        h, w, cr = float(self._lh), float(self._lw), float(self._cr)

        # If the border has rounded corners.
        if self._cr:
            border.moveTo(w - cr, 0)
            border.addArc(w - cr, cr, cr, -90, 0)
            border.lineTo(w, h - cr)
            border.addArc(w - cr, h - cr, cr, 0, 90)
            border.lineTo(cr, h)
            border.addArc(cr, h - cr, cr, 90, 180)
            border.lineTo(0, cr)
            border.addArc(cr, cr, cr, 180, 270)
            border.closePath()

        # No rounded corners.
        else:
            border.moveTo(0, 0)
            border.lineTo(w, 0)
            border.lineTo(w, h)
            border.lineTo(0, h)
            border.closePath()

        # Use it as a clip path.
        border.isClipPath = 1
        border.strokeColor = None
        border.fillColor = None

        # And done.
        self._border = border

        # The border doesn't show up if its part of a clipping path when
        # outputting to an image. If its needed, make a copy and turn the
        # clipping path off.
        if self.border:
            from copy import copy
            self._border_visible = copy(self._border)
            self._border_visible.isClipPath = 0
            self._border_visible.strokeWidth = 1
            self._border_visible.strokeColor = colors.black
        else:
            self._border_visible = None