git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_8_BRANCH@45725 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			171 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			171 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """
 | |
| A Bounding Box object and assorted utilities , subclassed from a numpy array
 | |
| 
 | |
| """
 | |
| 
 | |
| import numpy as N
 | |
| 
 | |
| class BBox(N.ndarray):
 | |
|     """
 | |
|     A Bounding Box object:
 | |
|     
 | |
|     Takes Data as an array. Data is any python sequence that can be turned into a 
 | |
|     2x2 numpy array of floats:
 | |
| 
 | |
|     [[MinX, MinY ],
 | |
|      [MaxX, MaxY ]]
 | |
| 
 | |
|     It is a subclass of numpy.ndarray, so for the most part it can be used as 
 | |
|     an array, and arrays that fit the above description can be used in its place.
 | |
|     
 | |
|     Usually created by the factory functions:
 | |
|     
 | |
|         asBBox
 | |
|         
 | |
|         and 
 | |
|         
 | |
|         fromPoints
 | |
|     
 | |
|     """
 | |
|     def __new__(subtype, data):
 | |
|         """
 | |
|         Takes Data as an array. Data is any python sequence that can be turned into a 
 | |
|         2x2 numpy array of floats:
 | |
| 
 | |
|         [[MinX, MinY ],
 | |
|         [MaxX, MaxY ]]
 | |
| 
 | |
|         You don't usually call this directly. BBox objects are created with the factory functions:
 | |
|         
 | |
|         asBBox
 | |
|         
 | |
|         and 
 | |
|         
 | |
|         fromPoints
 | |
| 
 | |
|         """
 | |
|         arr = N.array(data, N.float)
 | |
|         arr.shape = (2,2)
 | |
|         if arr[0,0] > arr[1,0] or arr[0,1] > arr[1,1]:
 | |
|             # note: zero sized BB OK.
 | |
|             raise ValueError("BBox values not aligned: \n minimum values must be less that maximum values")
 | |
|         return N.ndarray.__new__(BBox, shape=arr.shape, dtype=arr.dtype, buffer=arr)
 | |
| 
 | |
|     def Overlaps(self, BB):
 | |
|         """
 | |
|         Overlap(BB):
 | |
| 
 | |
|         Tests if the given Bounding Box overlaps with this one.
 | |
|         Returns True is the Bounding boxes overlap, False otherwise
 | |
|         If they are just touching, returns True
 | |
|         """
 | |
| 
 | |
|         if ( (self[1,0] >= BB[0,0]) and (self[0,0] <= BB[1,0]) and
 | |
|              (self[1,1] >= BB[0,1]) and (self[0,1] <= BB[1,1]) ):
 | |
|             return True
 | |
|         else:
 | |
|             return False
 | |
| 
 | |
|     def Inside(self, BB):
 | |
|         """
 | |
|         Inside(BB):
 | |
| 
 | |
|         Tests if the given Bounding Box is entirely inside this one.
 | |
| 
 | |
|         Returns True if it is entirely inside, or touching the
 | |
|         border.
 | |
| 
 | |
|         Returns False otherwise
 | |
|         """
 | |
|         if ( (BB[0,0] >= self[0,0]) and (BB[1,0] <= self[1,0]) and
 | |
|              (BB[0,1] >= self[0,1]) and (BB[1,1] <= self[1,1]) ):
 | |
|             return True
 | |
|         else:
 | |
|             return False
 | |
|     
 | |
|     def Merge(self, BB):
 | |
|         """
 | |
|         Joins this bounding box with the one passed in, maybe making this one bigger
 | |
| 
 | |
|         """ 
 | |
| 
 | |
|         if BB[0,0] < self[0,0]: self[0,0] = BB[0,0]
 | |
|         if BB[0,1] < self[0,1]: self[0,1] = BB[0,1]
 | |
|         if BB[1,0] > self[1,0]: self[1,0] = BB[1,0]
 | |
|         if BB[1,1] > self[1,1]: self[1,1] = BB[1,1]
 | |
|     
 | |
|     ### This could be used for a make BB from a bunch of BBs
 | |
| 
 | |
|     #~ def _getboundingbox(bboxarray): # lrk: added this
 | |
|         #~ # returns the bounding box of a bunch of bounding boxes
 | |
|         #~ upperleft = N.minimum.reduce(bboxarray[:,0])
 | |
|         #~ lowerright = N.maximum.reduce(bboxarray[:,1])
 | |
|         #~ return N.array((upperleft, lowerright), N.float)
 | |
|     #~ _getboundingbox = staticmethod(_getboundingbox)
 | |
| 
 | |
| 
 | |
|     ## Save the ndarray __eq__ for internal use.
 | |
|     Array__eq__ = N.ndarray.__eq__
 | |
|     def __eq__(self, BB):
 | |
|         """
 | |
|         __eq__(BB) The equality operator
 | |
| 
 | |
|         A == B if and only if all the entries are the same
 | |
| 
 | |
|         """
 | |
|         return N.all(self.Array__eq__(BB))
 | |
|         
 | |
| 
 | |
| def asBBox(data):
 | |
|     """
 | |
|     returns a BBox object.
 | |
| 
 | |
|     If object is a BBox, it is returned unaltered
 | |
| 
 | |
|     If object is a numpy array, a BBox object is returned that shares a
 | |
|     view of the data with that array
 | |
| 
 | |
|     """
 | |
| 
 | |
|     if isinstance(data, BBox):
 | |
|         return data
 | |
|     arr = N.asarray(data, N.float)
 | |
|     return N.ndarray.__new__(BBox, shape=arr.shape, dtype=arr.dtype, buffer=arr)
 | |
| 
 | |
| def fromPoints(Points):
 | |
|     """
 | |
|     fromPoints (Points).
 | |
| 
 | |
|     reruns the bounding box of the set of points in Points. Points can
 | |
|     be any python object that can be turned into a numpy NX2 array of Floats.
 | |
| 
 | |
|     If a single point is passed in, a zero-size Bounding Box is returned.
 | |
|     
 | |
|     """
 | |
|     Points = N.asarray(Points, N.float).reshape(-1,2)
 | |
| 
 | |
|     arr = N.vstack( (Points.min(0), Points.max(0)) )
 | |
|     return N.ndarray.__new__(BBox, shape=arr.shape, dtype=arr.dtype, buffer=arr)
 | |
| 
 | |
| def fromBBArray(BBarray):
 | |
|    """
 | |
|    Builds a BBox object from an array of Bounding Boxes. 
 | |
|    The resulting Bounding Box encompases all the included BBs.
 | |
|    
 | |
|    The BBarray is in the shape: (Nx2x2) where BBarray[n] is a 2x2 array that represents a BBox
 | |
|    """
 | |
|    
 | |
|    #upperleft = N.minimum.reduce(BBarray[:,0])
 | |
|    #lowerright = N.maximum.reduce(BBarray[:,1])
 | |
| 
 | |
| #   BBarray = N.asarray(BBarray, N.float).reshape(-1,2)
 | |
| #   arr = N.vstack( (BBarray.min(0), BBarray.max(0)) )
 | |
|    BBarray = N.asarray(BBarray, N.float).reshape(-1,2,2)
 | |
|    arr = N.vstack( (BBarray[:,0,:].min(0), BBarray[:,1,:].max(0)) )
 | |
|    return asBBox(arr)
 | |
|    #return asBBox( (upperleft, lowerright) ) * 2
 | |
|    
 | |
|    
 | |
|    
 | |
|    
 |