00001
00002
00003
00004 import sys
00005 import numpy as np
00006 import matplotlib.pyplot as plt
00007 import matplotlib.patches as patches
00008 import math
00009
00010 from Drag import *
00011
00012 class DragRectangle( Drag, patches.Rectangle ) :
00013
00014 def __init__(self, xy=None, width=1, height=1, linewidth=2, linestyle='solid', color='b', picker=8, fill=False, str_of_pars=None) :
00015
00016 Drag.__init__(self, linewidth, color, linestyle, my_type='Rectangle')
00017
00018 if str_of_pars is not None :
00019 x,y,w,h,lw,col,s,t,r = self.parse_str_of_pars(str_of_pars)
00020 patches.Rectangle.__init__(self, (x,y), w, h, linewidth=lw, color=col, fill=fill, picker=picker)
00021 self.isSelected = s
00022 self.myType = t
00023 self.isRemoved = r
00024 self.isInitialized = True
00025
00026 elif xy is None :
00027 xy0=(0,0)
00028 patches.Rectangle.__init__(self, xy0, width, height, linewidth=linewidth, color=color, fill=fill, picker=picker)
00029 self.isInitialized = False
00030
00031
00032 else :
00033 patches.Rectangle.__init__(self, xy, width, height, linewidth=linewidth, color=color, fill=fill, picker=picker)
00034 self.isInitialized = True
00035
00036 self.set_picker(picker)
00037 self.myPicker = picker
00038 self.press = None
00039
00040
00041 def get_list_of_pars(self) :
00042 x0 = int( self.get_x() )
00043 y0 = int( self.get_y() )
00044 w0 = int( self.get_width () )
00045 h0 = int( self.get_height() )
00046 lw = int( self.get_linewidth() )
00047 col= self.myCurrentColor
00048 x = min(x0,x0+w0)
00049 y = min(y0,y0+h0)
00050 h = abs(h0)
00051 w = abs(w0)
00052 s = self.isSelected
00053 t = self.myType
00054 r = self.isRemoved
00055 return (x,y,w,h,lw,col,s,t,r)
00056
00057
00058 def parse_str_of_pars(self, str_of_pars) :
00059 pars = str_of_pars.split()
00060
00061 t = pars[0]
00062 x = float(pars[1])
00063 y = float(pars[2])
00064 w = float(pars[3])
00065 h = float(pars[4])
00066 lw = int(pars[5])
00067 col = str(pars[6])
00068 s = self.dicBool[pars[7].lower()]
00069 r = self.dicBool[pars[8].lower()]
00070
00071 return (x,y,w,h,lw,col,s,t,r)
00072
00073
00074 def get_str_of_pars(self) :
00075 x,y,w,h,lw,col,s,t,r = self.get_list_of_pars()
00076 return '%s %7.2f %7.2f %7.2f %7.2f %d %s %s %s' % (t,x,y,w,h,lw,col,s,r)
00077
00078
00079 def print_pars(self) :
00080 print 't,x,y,w,h,lw,col,s,r =', self.get_str_of_pars()
00081
00082
00083 def obj_contains_cursor(self, event):
00084 if not self.isInitialized : return False
00085 if event.inaxes != self.axes: return False
00086 return self.my_contains(event)
00087
00088
00089 def my_contains(self, event):
00090 x,y = event.xdata, event.ydata
00091 x0 = self.get_x()
00092 y0 = self.get_y()
00093 w0 = self.get_width()
00094 h0 = self.get_height()
00095 r = self.myPicker
00096
00097 xmin = min(x0, x0+w0)
00098 xmax = max(x0, x0+w0)
00099 ymin = min(y0, y0+h0)
00100 ymax = max(y0, y0+h0)
00101
00102 if x > xmin-r and x < xmax+r and y > ymin-r and y < ymax+r :
00103 self.inLargeBox = True
00104 else :
00105 self.inLargeBox = False
00106
00107 if x > xmin+r and x < xmax-r and y > ymin+r and y < ymax-r :
00108 self.inSmallBox = True
00109 else :
00110 self.inSmallBox = False
00111
00112
00113
00114 if self.inLargeBox and not self.inSmallBox:
00115 return True
00116 else :
00117 return False
00118
00119
00120 def on_press(self, event):
00121 'on button press we will see if the mouse is over us and store some data'
00122 if event.inaxes != self.axes: return
00123
00124 clickxy = event.xdata, event.ydata
00125
00126
00127 if self.isInitialized :
00128
00129 contains = self.my_contains(event)
00130 if not contains: return
00131
00132
00133 xy0 = self.get_xy()
00134 x0 = self.get_x()
00135 y0 = self.get_y()
00136 w0 = self.get_width()
00137 h0 = self.get_height()
00138 w2 = w0/2
00139 h2 = h0/2
00140
00141 self.list_of_verts = [(x0,y0), (x0+w0,y0), (x0,y0+h0), (x0+w0,y0+h0),
00142 (x0,y0+h2), (x0+w0,y0+h2), (x0+w2,y0), (x0+w2,y0+h0)]
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157 vertindex = 10
00158
00159 self.dist_min = 1000
00160 for i, vert in enumerate(self.list_of_verts) :
00161 dist = self.max_deviation(clickxy,vert)
00162 if dist < self.dist_min :
00163 vertindex = i+1
00164 self.dist_min = dist
00165
00166
00167
00168 self.press = xy0, w0, h0, clickxy, vertindex
00169
00170
00171 if event.button is 2 :
00172 self.remove_object_from_img()
00173 return
00174
00175 else :
00176 vertindex = 0
00177 xy0 = clickxy
00178 w0 = 1
00179 h0 = 1
00180 self.press = xy0, w0, h0, clickxy, vertindex
00181
00182 self.on_press_graphic_manipulations()
00183
00184
00185 def on_motion(self, event):
00186 'on motion we will move the rect if the mouse is over us'
00187 if self.press is None: return
00188 if event.inaxes != self.axes: return
00189
00190
00191 currentxy = event.xdata, event.ydata
00192
00193 xy0, w0, h0, clickxy, vertindex = self.press
00194 xy = [xy0[0], xy0[1]]
00195
00196 dx = currentxy[0]-clickxy[0]
00197 dy = currentxy[1]-clickxy[1]
00198
00199 if event.button is 3 and self.isInitialized :
00200
00201
00202 self.set_xy( (xy0[0] + dx, xy0[1] + dy) )
00203
00204
00205 elif event.button is 1 and self.isInitialized :
00206
00207 if vertindex == 1 :
00208 self.set_xy( (xy0[0] + dx, xy0[1] + dy) )
00209 self.set_width (w0 - dx)
00210 self.set_height(h0 - dy)
00211 elif vertindex == 2 :
00212 self.set_y( xy0[1] + dy)
00213 self.set_width (w0 + dx)
00214 self.set_height(h0 - dy)
00215 elif vertindex == 3 :
00216 self.set_x( xy0[0] + dx)
00217 self.set_width (w0 - dx)
00218 self.set_height(h0 + dy)
00219 elif vertindex == 4 :
00220 self.set_width (w0 + dx)
00221 self.set_height(h0 + dy)
00222 elif vertindex == 5 :
00223 self.set_x( xy0[0] + dx)
00224 self.set_width (w0 - dx)
00225 elif vertindex == 6 :
00226 self.set_width (w0 + dx)
00227 elif vertindex == 7 :
00228 self.set_y( xy0[1] + dy)
00229 self.set_height(h0 - dy)
00230 elif vertindex == 8 :
00231 self.set_height(h0 + dy)
00232
00233 elif event.button is 1 and not self.isInitialized :
00234
00235 self.set_width (dx)
00236 self.set_height(dy)
00237 self.set_xy(xy0)
00238
00239 self.on_motion_graphic_manipulations()
00240
00241
00242 def on_release(self, event):
00243 'on release we reset the press data'
00244 self.on_release_graphic_manipulations()
00245
00246 if self.press is not None : self.maskIsAvailable = False
00247 self.press = None
00248
00249
00250 def get_poly_verts(self):
00251 """Creates a set of (closed) poly vertices for mask"""
00252 x,y,w,h,lw,col,s,t,r = self.get_list_of_pars()
00253 return [(x,y), (x+w,y), (x+w,y+h), (x,y+h), (x,y)]
00254
00255
00256
00257 def get_obj_mask(self, shape):
00258 """Re-implementation of this method from Drag: standard method for points in polygon is very slow"""
00259 if not self.maskIsAvailable :
00260 self.mask = self.get_mask_for_rectangle(shape)
00261 self.maskIsAvailable = True
00262 if self.isSelected : return ~self.mask
00263 else : return self.mask
00264
00265
00266 def get_mask_for_rectangle(self, shape):
00267 x0,y0,w,h,lw,col,s,t,r = self.get_list_of_pars()
00268 x, y = np.meshgrid(np.arange(shape[1]), np.arange(shape[0]))
00269 return np.select([x<x0, x>x0+w, y<y0, y>y0+h], [False, False, False, False], default=True)
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279 from DragObjectSet import *
00280
00281
00282
00283
00284 def generate_list_of_objects(img_extent) :
00285 """Produce the list of initial random objects for test purpose.
00286 1. Generates initial list of random objects
00287 2. Add them to the figure axes
00288 3. Connect with signals.
00289 4. Returns the list of created objects.
00290 """
00291
00292 xmin,xmax,ymin,ymax = img_extent
00293 print 'xmin,xmax,ymin,ymax = ', xmin,xmax,ymin,ymax
00294
00295 nobj = 10
00296 x = xmin+(xmax-xmin)*np.random.rand(nobj)
00297 y = ymax+(ymin-ymax)*np.random.rand(nobj)
00298 w = (xmax-xmin)/3*np.random.rand(nobj)
00299 h = (ymin-ymax)/3*np.random.rand(nobj)
00300
00301
00302 obj_list = []
00303
00304
00305 for indobj in range(nobj) :
00306 obj = DragRectangle((x[indobj],y[indobj]), w[indobj], h[indobj], color='g')
00307 obj_list.append(obj)
00308
00309 return obj_list
00310
00311
00312
00313 def main_full_test():
00314 """Full test of the class DragRectangle, using the class DragObjectSet
00315 1. make a 2D plot
00316 2. make a list of random objects and add them to the plot
00317 3. use the class DragObjectSet to switch between modes for full test of the class DragRectangle
00318 """
00319 fig, axes, imsh = generate_test_image()
00320 list_of_objs = generate_list_of_objects(imsh.get_extent())
00321
00322 t = DragObjectSet(fig, axes, DragRectangle, useKeyboard=True)
00323 t .set_list_of_objs(list_of_objs)
00324
00325 plt.get_current_fig_manager().window.geometry('+50+10')
00326 plt.show()
00327
00328
00329
00330 def main_simple_test():
00331 """Simple test of the class DragRectangle.
00332 1. make a 2-d plot
00333 2. make a list of random objects and add them to the plot
00334 3. add one more object with initialization at 1st click-and-drag of mouse-left button
00335 """
00336 fig, axes, imsh = generate_test_image()
00337 list_of_objs = generate_list_of_objects(imsh.get_extent())
00338
00339
00340 obj = DragRectangle()
00341 add_obj_to_axes(obj, axes, list_of_objs)
00342
00343 plt.get_current_fig_manager().window.geometry('+50+10')
00344 plt.show()
00345
00346
00347
00348 if __name__ == "__main__" :
00349
00350
00351 main_full_test()
00352 sys.exit ('End of test')
00353
00354