~openerp-groupes/openobject-server/6.0-fix-setup-windows

« back to all changes in this revision

Viewing changes to bin/reportlab/graphics/charts/utils3d.py

  • Committer: pinky
  • Date: 2006-12-07 13:41:40 UTC
  • Revision ID: pinky-3f10ee12cea3c4c75cef44ab04ad33ef47432907
New trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
from reportlab.lib import colors
 
2
from reportlab.lib.attrmap import *
 
3
from reportlab.pdfgen.canvas import Canvas
 
4
from reportlab.graphics.shapes import Group, Drawing, Ellipse, Wedge, String, STATE_DEFAULTS, Polygon, Line
 
5
 
 
6
def _getShaded(col,shd=None,shading=0.1):
 
7
    if shd is None:
 
8
        from reportlab.lib.colors import Blacker
 
9
        if col: shd = Blacker(col,1-shading)
 
10
    return shd
 
11
 
 
12
def _getLit(col,shd=None,lighting=0.1):
 
13
    if shd is None:
 
14
        from reportlab.lib.colors import Whiter
 
15
        if col: shd = Whiter(col,1-lighting)
 
16
    return shd
 
17
 
 
18
 
 
19
def _draw_3d_bar(G, x1, x2, y0, yhigh, xdepth, ydepth,
 
20
                fillColor=None, fillColorShaded=None,
 
21
                strokeColor=None, strokeWidth=1, shading=0.1):
 
22
    fillColorShaded = _getShaded(fillColor,None,shading)
 
23
    fillColorShadedTop = _getShaded(fillColor,None,shading/2.0)
 
24
 
 
25
    def _add_3d_bar(x1, x2, y1, y2, xoff, yoff,
 
26
                    G=G,strokeColor=strokeColor, strokeWidth=strokeWidth, fillColor=fillColor):
 
27
        G.add(Polygon((x1,y1, x1+xoff,y1+yoff, x2+xoff,y2+yoff, x2,y2),
 
28
            strokeWidth=strokeWidth, strokeColor=strokeColor, fillColor=fillColor,strokeLineJoin=1))
 
29
 
 
30
    usd = max(y0, yhigh)
 
31
    if xdepth or ydepth:
 
32
        if y0!=yhigh:   #non-zero height
 
33
            _add_3d_bar( x2, x2, y0, yhigh, xdepth, ydepth, fillColor=fillColorShaded) #side
 
34
 
 
35
        _add_3d_bar(x1, x2, usd, usd, xdepth, ydepth, fillColor=fillColorShadedTop)    #top
 
36
 
 
37
    G.add(Polygon((x1,y0,x2,y0,x2,yhigh,x1,yhigh),
 
38
        strokeColor=strokeColor, strokeWidth=strokeWidth, fillColor=fillColor,strokeLineJoin=1)) #front
 
39
 
 
40
    if xdepth or ydepth:
 
41
        G.add(Line( x1, usd, x2, usd, strokeWidth=strokeWidth, strokeColor=strokeColor or fillColorShaded))
 
42
 
 
43
class _YStrip:
 
44
    def __init__(self,y0,y1, slope, fillColor, fillColorShaded, shading=0.1):
 
45
        self.y0 = y0
 
46
        self.y1 = y1
 
47
        self.slope = slope
 
48
        self.fillColor = fillColor
 
49
        self.fillColorShaded = _getShaded(fillColor,fillColorShaded,shading)
 
50
 
 
51
def _ystrip_poly( x0, x1, y0, y1, xoff, yoff):
 
52
    return [x0,y0,x0+xoff,y0+yoff,x1+xoff,y1+yoff,x1,y1]
 
53
 
 
54
 
 
55
def _make_3d_line_info( G, x0, x1, y0, y1, z0, z1,
 
56
                    theta_x, theta_y,
 
57
                    fillColor, fillColorShaded=None, tileWidth=1,
 
58
                    strokeColor=None, strokeWidth=None, strokeDashArray=None,
 
59
                    shading=0.1):
 
60
    zwidth = abs(z1-z0)
 
61
    xdepth = zwidth*theta_x
 
62
    ydepth = zwidth*theta_y
 
63
    depth_slope  = xdepth==0 and 1e150 or -ydepth/float(xdepth)
 
64
 
 
65
    x = float(x1-x0)
 
66
    slope = x==0 and 1e150 or (y1-y0)/x
 
67
 
 
68
    c = slope>depth_slope and _getShaded(fillColor,fillColorShaded,shading) or fillColor
 
69
    zy0 = z0*theta_y
 
70
    zx0 = z0*theta_x
 
71
 
 
72
    tileStrokeWidth = 0.6
 
73
    if tileWidth is None:
 
74
        D = [(x1,y1)]
 
75
    else:
 
76
        T = ((y1-y0)**2+(x1-x0)**2)**0.5
 
77
        tileStrokeWidth *= tileWidth
 
78
        if T<tileWidth:
 
79
            D = [(x1,y1)]
 
80
        else:
 
81
            n = int(T/float(tileWidth))+1
 
82
            dx = float(x1-x0)/n
 
83
            dy = float(y1-y0)/n
 
84
            D = []
 
85
            a = D.append
 
86
            for i in xrange(1,n):
 
87
                a((x0+dx*i,y0+dy*i))
 
88
 
 
89
    a = G.add
 
90
    x_0 = x0+zx0
 
91
    y_0 = y0+zy0
 
92
    for x,y in D:
 
93
        x_1 = x+zx0
 
94
        y_1 = y+zy0
 
95
        P = Polygon(_ystrip_poly(x_0, x_1, y_0, y_1, xdepth, ydepth),
 
96
                    fillColor = c, strokeColor=c, strokeWidth=tileStrokeWidth)
 
97
        a((0,z0,z1,x_0,y_0,P))
 
98
        x_0 = x_1
 
99
        y_0 = y_1
 
100
 
 
101
from math import pi, sin, cos
 
102
_pi_2 = pi*0.5
 
103
_2pi = 2*pi
 
104
_180_pi=180./pi
 
105
 
 
106
def _2rad(angle):
 
107
    return (angle*pi)/180
 
108
 
 
109
def mod_2pi(radians):
 
110
    radians = radians % _2pi
 
111
    if radians<-1e-6: radians += _2pi
 
112
    return radians
 
113
 
 
114
def _2deg(o):
 
115
    return o*_180_pi
 
116
 
 
117
def _360(a):
 
118
    a %= 360
 
119
    if a<-1e-6: a += 360
 
120
    return a
 
121
 
 
122
_ZERO = 1e-8
 
123
_ONE = 1-_ZERO
 
124
class _Segment:
 
125
    def __init__(self,s,i,data):
 
126
        S = data[s]
 
127
        x0 = S[i-1][0]
 
128
        y0 = S[i-1][1]
 
129
        x1 = S[i][0]
 
130
        y1 = S[i][1]
 
131
        if x1<x0:
 
132
            x0,y0,x1,y1 = x1,y1,x0,y0
 
133
        # (y-y0)*(x1-x0) = (y1-y0)*(x-x0)
 
134
        # (x1-x0)*y + (y0-y1)*x = y0*(x1-x0)+x0*(y0-y1)
 
135
        # a*y+b*x = c
 
136
        self.a = float(x1-x0)
 
137
        self.b = float(y1-y0)
 
138
        self.x0 = x0
 
139
        self.x1 = x1
 
140
        self.y0 = y0
 
141
        self.y1 = y1
 
142
        self.series = s
 
143
        self.i = i
 
144
        self.s = s
 
145
 
 
146
    def __str__(self):
 
147
        return '[(%s,%s),(%s,%s)]' % (self.x0,self.y0,self.x1,self.y1)
 
148
 
 
149
    __repr__ = __str__
 
150
 
 
151
    def intersect(self,o,I):
 
152
        '''try to find an intersection with _Segment o
 
153
        '''
 
154
        x0 = self.x0
 
155
        ox0 = o.x0
 
156
        assert x0<=ox0
 
157
        if ox0>self.x1: return 1
 
158
        if o.s==self.s and o.i in (self.i-1,self.i+1): return
 
159
        a = self.a
 
160
        b = self.b
 
161
        oa = o.a
 
162
        ob = o.b
 
163
        det = ob*a - oa*b
 
164
        if -1e-8<det<1e-8: return
 
165
        dx = x0 - ox0
 
166
        dy = self.y0 - o.y0
 
167
        u = (oa*dy - ob*dx)/det
 
168
        ou = (a*dy - b*dx)/det
 
169
        if u<0 or u>1 or ou<0 or ou>1: return
 
170
        x = x0 + u*a
 
171
        y = self.y0 + u*b
 
172
        if _ZERO<u<_ONE:
 
173
            t = self.s,self.i,x,y
 
174
            if t not in I: I.append(t)
 
175
        if _ZERO<ou<_ONE:
 
176
            t = o.s,o.i,x,y
 
177
            if t not in I:  I.append(t)
 
178
 
 
179
def _segCmp(a,b):
 
180
    return cmp((a.x0,a.x1,a.y0,a.y1,a.s,a.i),(b.x0,b.x1,b.y0,b.y1,b.s,b.i))
 
181
 
 
182
def find_intersections(data,small=0):
 
183
    '''
 
184
    data is a sequence of series
 
185
    each series is a list of (x,y) coordinates
 
186
    where x & y are ints or floats
 
187
 
 
188
    find_intersections returns a sequence of 4-tuples
 
189
        i, j, x, y
 
190
 
 
191
    where i is a data index j is an insertion position for data[i]
 
192
    and x, y are coordinates of an intersection of series data[i]
 
193
    with some other series. If correctly implemented we get all such
 
194
    intersections. We don't count endpoint intersections and consider
 
195
    parallel lines as non intersecting (even when coincident).
 
196
    We ignore segments that have an estimated size less than small.
 
197
    '''
 
198
 
 
199
    #find all line segments
 
200
    S = []
 
201
    a = S.append
 
202
    for s in xrange(len(data)):
 
203
        ds = data[s]
 
204
        if not ds: continue
 
205
        n = len(ds)
 
206
        if n==1: continue
 
207
        for i in xrange(1,n):
 
208
            seg = _Segment(s,i,data)
 
209
            if seg.a+abs(seg.b)>=small: a(seg)
 
210
    S.sort(_segCmp)
 
211
    I = []
 
212
    n = len(S)
 
213
    for i in xrange(0,n-1):
 
214
        s = S[i]
 
215
        for j in xrange(i+1,n):
 
216
            if s.intersect(S[j],I)==1: break
 
217
    I.sort()
 
218
    return I
 
219
 
 
220
if __name__=='__main__':
 
221
    from reportlab.graphics.shapes import Drawing
 
222
    from reportlab.lib.colors import lightgrey, pink
 
223
    D = Drawing(300,200)
 
224
    _draw_3d_bar(D, 10, 20, 10, 50, 5, 5, fillColor=lightgrey, strokeColor=pink)
 
225
    _draw_3d_bar(D, 30, 40, 10, 45, 5, 5, fillColor=lightgrey, strokeColor=pink)
 
226
 
 
227
    D.save(formats=['pdf'],outDir='.',fnRoot='_draw_3d_bar')
 
228
 
 
229
    print find_intersections([[(0,0.5),(1,0.5),(0.5,0),(0.5,1)],[(.2666666667,0.4),(0.1,0.4),(0.1,0.2),(0,0),(1,1)],[(0,1),(0.4,0.1),(1,0.1)]])
 
230
    print find_intersections([[(0.1, 0.2), (0.1, 0.4)], [(0, 1), (0.4, 0.1)]])
 
231
    print find_intersections([[(0.2, 0.4), (0.1, 0.4)], [(0.1, 0.8), (0.4, 0.1)]])
 
232
    print find_intersections([[(0,0),(1,1)],[(0.4,0.1),(1,0.1)]])
 
233
    print find_intersections([[(0,0.5),(1,0.5),(0.5,0),(0.5,1)],[(0,0),(1,1)],[(0.1,0.8),(0.4,0.1),(1,0.1)]])