Package lib :: Module geom
[hide private]
[frames] | no frames]

Source Code for Module lib.geom

  1  # -*- coding: utf-8 -*- 
  2   
  3  #    callirhoe - high quality calendar rendering 
  4  #    Copyright (C) 2012 George M. Tzoumas 
  5   
  6  #    This program is free software: you can redistribute it and/or modify 
  7  #    it under the terms of the GNU General Public License as published by 
  8  #    the Free Software Foundation, either version 3 of the License, or 
  9  #    (at your option) any later version. 
 10  # 
 11  #    This program is distributed in the hope that it will be useful, 
 12  #    but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 14  #    GNU General Public License for more details. 
 15  # 
 16  #    You should have received a copy of the GNU General Public License 
 17  #    along with this program.  If not, see http://www.gnu.org/licenses/ 
 18   
 19  # ***************************************** 
 20  #                                         # 
 21  """  general-purpose geometry routines  """ 
 22  #                                         # 
 23  # ***************************************** 
 24   
25 -def rect_ratio(r):
26 """returns the ratio of rect I{r} which is defined as M{width/height} 27 28 @rtype: float 29 """ 30 return r[2]*1.0/r[3]
31
32 -def rect_rel_scale(r, fw, fh, align_x = 0, align_y = 0):
33 """relatively scale a rect 34 35 @type fw: float in [0,1] 36 @param fw: width fraction (to be multiplied) 37 @type fh: float in [0,1] 38 @param fh: height fraction (to be multiplied) 39 @type align_x: float in [-1,1] 40 @param align_x: determines the relative position of the new rect with respect to 41 the old one. A value of 0 aligns in the center, a value of -1 aligns on the 42 left, a value of 1 aligns on the right hand side. Intermediate values do 43 linear interpolation. 44 @type align_y: float in [-1,1] 45 @param align_y: Performs vertical (top-bottom) alignment similarly to L{align_x}. 46 @rtype: (float,float,float,float) 47 """ 48 x, y, w, h = r 49 return (x + (align_x + 1.0)*w*(1 - fw)/2.0, 50 y + (align_y + 1.0)*h*(1 - fh)/2.0, w*fw, h*fh)
51
52 -def rect_pad(r, pad):
53 """returns a padded rect by reducing border by the I{pad} tuple (top,left,bottom,right) 54 55 @rtype: (float,float,float,float) 56 """ 57 x, y, w, h = r 58 t_, l_, b_, r_ = pad 59 return (x + l_, y + t_, w - r_ - l_, h - t_ - b_)
60
61 -def rect_to_abs(r):
62 """get absolute coordinates (x0,y0,x1,y1) from rect definition (x,y,w,h) 63 64 @rtype: (float,float,float,float) 65 """ 66 x, y, w, h = r 67 return (x, y, x + w, y + h)
68
69 -def abs_to_rect(a):
70 """get rect definition (x,y,w,h) from absolute coordinates (x0,y0,x1,y1) 71 72 @rtype: (float,float,float,float) 73 """ 74 x1, y1, x2, y2 = a 75 return (x1, y1, x2 - x1, y2 - y1)
76
77 -def rect_from_origin(r):
78 """returns a similar rect with top-left corner at (0,0) 79 80 @rtype: (float,float,float,float) 81 """ 82 return (0, 0, r[2], r[3])
83
84 -def rect_hull(r1,r2):
85 """returns the smallest rect containing r1 and r2 86 87 @rtype: (float,float,float,float) 88 """ 89 x1, y1, x2, y2 = rect_to_abs(r1) 90 x3, y3, x4, y4 = rect_to_abs(r2) 91 return abs_to_rect((min(x1,x3), min(y1,y3), max(x2,x4), max(y2,y4)))
92
93 -def rect_hsplit(r, f = 0.5, fdist = 0.0):
94 """split a rect horizontally 95 96 @type f: float in [0,1] 97 @param f: split fraction 98 @param fdist: fraction of space to discard before splitting (free space) 99 @rtype: ((float,float,float,float),(float,float,float,float)) 100 @return: tuple (r1,r2) with splits and free space evenly distributed 101 before r1, between r1 and r2 and after r2 102 """ 103 x, y, w, h = r 104 rw = w*(1.0 - fdist) 105 r1 = (x + w*fdist/3.0, y, rw*f, h) 106 r2 =(x + rw*f + w*fdist*2.0/3, y, rw*(1 - f), h) 107 return (r1, r2)
108
109 -def rect_vsplit(r, f = 0.5, fdist = 0.0):
110 """split a rect vertically, similarly to L{rect_hsplit} 111 112 @rtype: ((float,float,float,float),(float,float,float,float)) 113 """ 114 x, y, w, h = r 115 rh = h*(1.0 - fdist) 116 r1 = (x, y + h*fdist/3.0, w, rh*f) 117 r2 = (x, y + rh*f + h*fdist*2.0/3, w, rh*(1 - f)) 118 return (r1, r2)
119
120 -def color_mix(a, b, frac):
121 """mix two colors 122 123 @type frac: float in [0,1] 124 @param frac: amount of first color 125 @rtype: tuple 126 """ 127 return map(lambda (x,y): x*frac + y*(1 - frac), zip(a,b))
128
129 -def color_scale(a, frac):
130 """scale color values 131 132 @type frac: float 133 @param frac: scale amount (to be multiplied) 134 @rtype: tuple 135 """ 136 return map(lambda x: min(1.0,x*frac), a)
137
138 -def color_auto_fg(bg, light = (1,1,1), dark = (0,0,0)):
139 """return I{light} or I{dark} foreground color based on an ad-hoc evaluation of I{bg} 140 141 @rtype: tuple 142 """ 143 return light if (bg[0] + 1.5*bg[1] + bg[2]) < 1.0 else dark
144 145 # ********* layout managers *********** 146
147 -class VLayout(object):
148 """vertical layout manager 149 150 @ivar rect: bounding rect for layout -- this rect will be split and the slices assigned to every item 151 @ivar nitems: maximum number of items in the layout 152 @ivar pad: tuple(top,left,bottom,right) with item padding 153 """
154 - def __init__(self, rect, nitems = 1, pad = (0.0,0.0,0.0,0.0)): # TLBR
155 self.rect = rect 156 self.nitems = nitems 157 self.pad = pad
158
159 - def count(self):
160 """return maximum number of items in the layout 161 162 @rtype: int 163 """ 164 return self.nitems
165
166 - def resize(self, k):
167 """set maximum number of items""" 168 self.nitems = k
169
170 - def grow(self, delta = 1):
171 """increase number of items by I{delta}""" 172 self.nitems += delta
173
174 - def item(self, i = 0):
175 """get rect for item I{i} 176 177 @rtype: (float,float,float,float) 178 """ 179 x, y, w, h = self.rect 180 h *= 1.0/self.nitems 181 y += i*h 182 return rect_pad((x,y,w,h), self.pad)
183
184 - def item_span(self, n, k = -1):
185 """get union of I{k} consecutive items, starting at position I{n} 186 187 @param n: first item 188 @param k: number of items, -1 for all remaining items 189 @rtype: (float,float,float,float) 190 """ 191 if k < 0: k = (self.count() - n) // 2 192 return rect_hull(self.item(k), self.item(k + n - 1))
193
194 - def items(self):
195 """returns a sequence of all items 196 197 @rtype: (float,float,float,float),... 198 """ 199 return map(self.item, range(self.count()))
200
201 -class HLayout(VLayout):
202 """horizontal layout manager defined as a transpose of L{VLayout}"""
203 - def __init__(self, rect, nitems = 1, pad = (0.0,0.0,0.0,0.0)): # TLBR
204 super(HLayout,self).__init__((rect[1],rect[0],rect[3],rect[2]), 205 nitems, (pad[1], pad[0], pad[3], pad[2]))
206
207 - def item(self, i = 0):
208 """get rect for item I{i} 209 210 @rtype: (float,float,float,float) 211 """ 212 t = super(HLayout,self).item(i) 213 return (t[1], t[0], t[3], t[2])
214
215 -class GLayout(object):
216 """grid layout manager 217 218 @ivar vrep: internal L{VLayout} for row computations 219 @ivar hrep: internal L{HLayout} for column computations 220 """
221 - def __init__(self, rect, nrows = 1, ncols = 1, pad = (0.0,0.0,0.0,0.0)): # TLBR
222 """initialize layout 223 224 @param rect: layout rect (tuple) 225 @param nrows: number of rows 226 @param ncols: number of columns 227 @param pad: cell padding 228 """ 229 self.vrep = VLayout(rect, nrows, (pad[0], 0.0, pad[2], 0.0)) 230 t = self.vrep.item(0) 231 self.hrep = HLayout((rect[0], rect[1], t[2], t[3]), ncols, (0.0, pad[1], 0.0, pad[3]))
232
233 - def row_count(self):
234 """get (max) number of rows in the grid 235 236 @rtype: int 237 """ 238 return self.vrep.count()
239
240 - def col_count(self):
241 """get (max) number of columns in the grid 242 243 @rtype: int 244 """ 245 return self.hrep.count()
246
247 - def count(self):
248 """get total number of cells in the grid (which is M{rows*cols}) 249 250 @rtype: int 251 """ 252 return self.row_count()*self.col_count()
253
254 - def resize(self, rows, cols):
255 """resize grid by specifying new number of rows and columns""" 256 self.vrep.resize(rows) 257 t = self.vrep.item(0) 258 self.hrep = HLayout(t[0:2], t[2:4], cols, (0.0, pad[1], 0.0, pad[3]))
259
260 - def item(self, row, col):
261 """get rect of cell at position I{row,col} 262 263 @rtype: (float,float,float,float) 264 """ 265 ty = self.vrep.item(row) 266 tx = self.hrep.item(col) 267 return (tx[0], ty[1], tx[2], tx[3])
268
269 - def item_seq(self, k, column_wise = False):
270 """get rect of cell at position I{k} column-wise or row-wise 271 272 @rtype: (float,float,float,float) 273 """ 274 if not column_wise: 275 row, col = k // self.col_count(), k % self.col_count() 276 else: 277 col, row = k // self.row_count(), k % self.row_count() 278 return self.item(row, col)
279
280 - def items(self, column_wise = False):
281 """get sequence of rects of cells column-wise or row-wise 282 283 @rtype: (float,float,float,float),... 284 """ 285 return map(self.item_seq, range(self.count()))
286
287 - def row_items(self, row):
288 """get sequence of cell rects of a row 289 290 @rtype: (float,float,float,float),... 291 """ 292 return map(lambda x: self.item(row, x), range(self.col_count()))
293
294 - def col_items(self, col):
295 """get sequence of cell rects of a column 296 297 @rtype: (float,float,float,float),... 298 """ 299 return map(lambda x: self.item(x, col), range(self.row_count()))
300 301
302 - def item_span(self, nr, nc, row = -1, col = -1):
303 """get union of cell rects spanning a subgrid 304 305 @param nr: number of spanning rows 306 @param nc: number of spanning columns 307 @param row: starting row, -1 for vertically centered 308 @param col: starting column, -1 for horizontally centered 309 @rtype: (float,float,float,float) 310 """ 311 if row < 0: row = (self.row_count() - nr) // 2 312 if col < 0: col = (self.col_count() - nc) // 2 313 return rect_hull(self.item(row, col), self.item(row + nr - 1, col + nc - 1))
314