CorAna/src/DragRectangle.py

Go to the documentation of this file.
00001 #!/usr/bin/env python
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 # cos(x), sin(x), radians(x), degrees()
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 : # Default line initialization
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             #print "DragRectangle initialization w/o parameters."
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 # Is used to transmit local information between press and release button
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         #print 'pars:', pars
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         #print 'Parsed pars: %s %7.2f %7.2f %7.2f %7.2f %d %s %s %s' % (t,x,y,w,h,lw,col,s,r)
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): # Overrides method in Drag
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         #print 'self.inLargeBox =',self.inLargeBox ,'  self.inSmallBox =', self.inSmallBox
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         #print 'clickxy =',clickxy 
00126 
00127         if self.isInitialized :
00128             #contains, attrd = self.contains(event)
00129             contains = self.my_contains(event)
00130             if not contains: return
00131             #print 'event contains object',
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 # Numeration in vertindex the vertices and sides of the wedge
00145 #
00146 #        x0                x0+w0
00147 #        
00148 # y0+h0  3--------8--------4
00149 #        |                 |
00150 #        |                 |
00151 #        5                 6
00152 #        |                 |
00153 #        |                 |
00154 # y0     1--------7--------2
00155 
00156 
00157             vertindex = 10 # click xy is already contained around rect area within self.myPicker 
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             #print 'vertindex=',vertindex
00167 
00168             self.press = xy0, w0, h0, clickxy, vertindex
00169 
00170             #----Remove object at click on middle mouse botton
00171             if event.button is 2 : # for middle mouse button
00172                 self.remove_object_from_img() # Remove object from image
00173                 return
00174 
00175         else : # if the object position is not defined yet:
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         #print 'event on_moution', self.get_xydata()
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 : # move on right mouse button
00200 
00201             #if   vertindex == 10 : #side
00202             self.set_xy( (xy0[0] + dx,  xy0[1] + dy) )
00203 
00204 
00205         elif event.button is 1 and self.isInitialized : # change size for left mouse button
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 : # add new rect
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         #if self.press is not None : self.print_pars()
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 # inversed mask
00263         else               : return  self.mask # 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 # Test
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     #print ' x=',x, ' y=',y, ' w=',w, ' h=',h
00301 
00302     obj_list = []
00303 
00304     # Add objects with initialization through the parameters
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') # move(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     #Add one more object
00340     obj = DragRectangle() # call W/O parameters => object will be initialized at first mouse click
00341     add_obj_to_axes(obj, axes, list_of_objs)
00342 
00343     plt.get_current_fig_manager().window.geometry('+50+10') # move(50, 10)
00344     plt.show()
00345 
00346 #-----------------------------
00347 
00348 if __name__ == "__main__" :
00349 
00350     #main_simple_test()
00351     main_full_test()
00352     sys.exit ('End of test')
00353 
00354 #-----------------------------

Generated on 19 Dec 2016 for PSDMSoftware by  doxygen 1.4.7