Guest User

Hank Mclaughlin

a guest
Aug 18th, 2010
198
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.66 KB | None | 0 0
  1. ##
  2. #Hank Mclaughlin's Rect class
  3. #
  4. #This is a rectangle that has collision detection and some
  5. #basic collision response as well as properties for edges,
  6. #corners, midpoints of edges, the center point, and the size
  7. #that can be used as normal members.
  8. #It can also find the union or intersection between itself
  9. #and another given Rect.
  10. #In addition to that, it has a fairly flexible constructor
  11. #that can take a variety of types of sets of arguments.
  12. #
  13. #This is public domain, please use it however you want!
  14. #
  15. #For reference, there are some Doxygen-style docs above
  16. #each method.
  17. #(Aside from the private getters and setters for
  18. # properties, that is)
  19. #Methods are camelCased, as well, and the getters and
  20. #setters begin with underscores (IE: _ ) which mean
  21. #that they are mostly internal.
  22.  
  23.  
  24. ##
  25. #@brief Generic rectangle container
  26. #
  27. #Contains methods for collision detection and reponse,
  28. #as well as properties for all 4 edges, size, corners,
  29. #and midpoints of edges.
  30. class Rect(object):
  31.   def __init__(self,x,y=None,w=None,h=None):
  32.     if y != None:
  33.       if w != None:
  34.         if h != None:
  35.           self.left   = x
  36.           self.bottom = y
  37.           self.width  = w
  38.           self.height = h
  39.         else:
  40.           self.left   = x
  41.           self.bottom = y
  42.           self.width  = w
  43.           self.height = w
  44.       else:
  45.         self.bottomleft = x
  46.         self.size       = y
  47.     else:
  48.       if isinstance(x,Rect):
  49.         self.left   = x.left
  50.         self.bottom = x.bottom
  51.         self.width  = x.width
  52.         self.height = x.height
  53.       else:
  54.         self.left   = x[0]
  55.         self.bottom = x[1]
  56.         self.width  = x[2]
  57.         self.height = x[3]
  58.    
  59.  
  60.   def _getLeft(self):
  61.     return self._left
  62.   def _setLeft(self,new_left):
  63.     self._left = new_left
  64.   left = property(_getLeft,_setLeft)
  65.  
  66.   def _getRight(self):
  67.     return self._left + self._width
  68.   def _setRight(self,new_right):
  69.     self._left = new_right - self._width
  70.   right = property(_getRight,_setRight)
  71.  
  72.   def _getCenterx(self):
  73.     return self._left + (self._width / 2.0)
  74.   def _setCenterx(self,new_centerx):
  75.     self._left = new_centerx - (self._width / 2.0)
  76.   centerx = property(_getCenterx,_setCenterx)
  77.  
  78.   def _getBottom(self):
  79.     return self._bottom
  80.   def _setBottom(self,new_bottom):
  81.     self._bottom = new_bottom
  82.   bottom = property(_getBottom,_setBottom)
  83.  
  84.   def _getTop(self):
  85.     return self._bottom + self._width
  86.   def _setTop(self,new_top):
  87.     self._bottom = new_top - self._width
  88.   top = property(_getTop,_setTop)
  89.  
  90.   def _getCentery(self):
  91.     return self._bottom + (self._width / 2.0)
  92.   def _setCentery(self,new_centery):
  93.     self._bottom = new_centery - (self._width / 2.0)
  94.   centery = property(_getCentery,_setCentery)
  95.  
  96.   def _getWidth(self):
  97.     return self._width
  98.   def _setWidth(self,new_width):
  99.     self._width = new_width
  100.   width = property(_getWidth,_setWidth)
  101.  
  102.   def _getHeight(self):
  103.     return self._height
  104.   def _setHeight(self,new_height):
  105.     self._height = new_height
  106.   height = property(_getHeight,_setHeight)
  107.  
  108.   def _getTopLeft(self):
  109.     return self.left, self.top
  110.   def _setTopLeft(self,new_topleft):
  111.     self.left, self.top = new_topleft
  112.   topleft = property(_getTopLeft, _setTopLeft)
  113.  
  114.   def _getTopRight(self):
  115.     return self.right, self.top
  116.   def _setTopRight(self,new_topright):
  117.     self.right, self.top = new_topright
  118.   topright = property(_getTopRight, _setTopRight)
  119.  
  120.   def _getBottomLeft(self):
  121.     return self.left, self.bottom
  122.   def _setBottomLeft(self,new_bottomleft):
  123.     self.left, self.bottom = new_bottomleft
  124.   bottomleft = property(_getBottomLeft, _setBottomLeft)
  125.  
  126.   def _getBottomRight(self):
  127.     return self.right, self.bottom
  128.   def _setBottomRight(self,new_bottomright):
  129.     self.right, self.bottom = new_bottomright
  130.   bottomright = property(_getBottomRight, _setBottomRight)
  131.  
  132.   def _getMidLeft(self):
  133.     return self.left, self.centery
  134.   def _setMidLeft(self,new_midleft):
  135.     self.left, self.centery = new_midleft
  136.   midleft = property(_getMidLeft, _setMidLeft)
  137.  
  138.   def _getMidRight(self):
  139.     return self.right, self.centery
  140.   def _setMidRight(self,new_midright):
  141.     self.right, self.centery = new_midright
  142.   midright = property(_getMidRight, _setMidRight)
  143.  
  144.   def _getMidTop(self):
  145.     return self.centerx, self.top
  146.   def _setMidTop(self,new_midtop):
  147.     self.centerx, self.top = new_midtop
  148.   midtop = property(_getMidTop, _setMidTop)
  149.  
  150.   def _getMidBottom(self):
  151.     return self.centerx, self.bottom
  152.   def _setMidBottom(self,new_midbottom):
  153.     self.centerx, self.bottom = new_midbottom
  154.   midbottom = property(_getMidBottom, _setMidBottom)
  155.  
  156.   def _getCenter(self):
  157.     return self.centerx,self.centery
  158.   def _setCenter(self,new_center):
  159.     self.centerx,self.centery = new_center
  160.   center = property(_getCenter,_setCenter)
  161.  
  162.   def _getSize(self):
  163.     return self.width,self.height
  164.   def _setSize(self,new_size):
  165.     self.width,self.height = new_size
  166.   size = property(_getSize,_setSize)
  167.  
  168.  
  169.   ##
  170.   #@brief Does the caller contain the given point?
  171.   #
  172.   #@param pt (2-tuple of numbers)\n
  173.   #          The point to test
  174.   #
  175.   #@return Whether the caller contains the given point
  176.   def collidePoint(self,pt):
  177.     collide_x = pt[0] > self.left   and pt[0] < self.right
  178.     collide_y = pt[1] > self.bottom and pt[1] <   self.top
  179.    
  180.     return collide_x and collide_y
  181.    
  182.  
  183.   ##
  184.   #@brief Does the caller overlap with the given Rect?
  185.   #
  186.   #@param other (Rect)\n
  187.   #             The Rect to check
  188.   #
  189.   #@return Whether the caller and the given Rect overlap
  190.   def collideRect(self,other):
  191.     collide_x = self.left < other.right
  192.     collide_x = collide_x and other.left < self.right
  193.    
  194.     collide_y = self.bottom < other.top
  195.     collide_y = collide_y and other.bottom < self.top
  196.    
  197.     return collide_x and collide_y
  198.    
  199.  
  200.  
  201.   ##
  202.   #@brief Move the caller inside of the given Rect
  203.   #
  204.   #@param other (Rect)\n
  205.   #             The Rect to move the caller inside of
  206.   #
  207.   #@post If the caller is wider than the given
  208.   #      Rect, then it has been centered on the
  209.   #      given Rect horizontally. Otherwise, the
  210.   #      caller lies completely within the given
  211.   #      Rect along the X axis\n
  212.   #      If the caller is taller than the given
  213.   #      Rect, the it has been centered on the
  214.   #      given Rect vertically. Otherwise, the
  215.   #      caller lies completely within the given
  216.   #      Rect along the Y axis
  217.   def clampIn(self,other):
  218.     if not self.collideRect(other):
  219.       return None
  220.    
  221.     if   self.width > other.width:
  222.       self.centerx = other.centerx
  223.     elif self.left < other.left:
  224.       self.left = other.left
  225.     elif self.right > other.right:
  226.       self.right = other.right
  227.    
  228.     if   self.height > other.height:
  229.       self.centery = other.centery
  230.     elif self.bottom < other.bottom:
  231.       self.bottom = other.bottom
  232.     elif self.top > other.top:
  233.       self.top = other.top
  234.    
  235.  
  236.   ##
  237.   #@brief Move the caller completely out of the given Rect
  238.   #
  239.   #@param other (Rect)\n
  240.   #             The Rect to move the caller out of
  241.   #@param dx (number)\n
  242.   #          The direction/speed along the X
  243.   #          axis that the caller should be moving
  244.   #@param dy (number)\n
  245.   #          The direction/speed along the Y
  246.   #          axis that the caller should be moving
  247.   #
  248.   #@post If dx > 0 and the caller's right edge
  249.   #      overlapped the given Rect's left edge,
  250.   #      the caller's right edge is now at the
  251.   #      given Rect's left edge\n
  252.   #      If dx < 0 and the caller's left edge
  253.   #      overlapped the given Rect's right edge,
  254.   #      the caller's left edge is now at the
  255.   #      given Rect's right edge\n
  256.   #      If dy > 0 and the caller's top edge
  257.   #      overlapped the given Rect's bottom
  258.   #      edge, the caller's top edge is now
  259.   #      at the given Rect's bottom edge\n
  260.   #      If dy < 0 and the caller's bottom
  261.   #      edge overlapped the given Rect's
  262.   #      top edge, the caller's bottom edge
  263.   #      is now at the given Rect's top edge
  264.   #
  265.   #\note If abs(dx) > abs(dy), then dy is treated
  266.   #      as if it were given as 0. Otherwise, dx
  267.   #      is treated as if it were given as 0
  268.   #      
  269.   def clampOff(self,other,dx,dy):
  270.     if not self.collideRect(other):
  271.       return None
  272.    
  273.     if abs(dx) > abs(dy):
  274.       dy = 0
  275.     else:
  276.       dx = 0
  277.    
  278.     if dx > 0 and self.right > other.left:
  279.       self.right = other.left
  280.      
  281.     if dx < 0 and self.left < other.right:
  282.       self.left = other.right
  283.      
  284.     if dy > 0 and self.top > other.bottom:
  285.       self.top = other.bottom
  286.      
  287.     if dy < 0 and self.bottom < other.top:
  288.       self.bottom = other.top
  289.      
  290.    
  291.  
  292.  
  293.   ##
  294.   #@brief Get the union of the caller and a given Rect
  295.   #
  296.   #@param other (Rect)\n
  297.   #             The Rect to get the union of
  298.   #
  299.   #@return A new Rect that covers the combined area of
  300.   #        other and the caller. This is still a Rect,
  301.   #        so additional area is covered
  302.   def union(self,other):
  303.     far_left   = self.left
  304.     far_right  = self.right
  305.     far_top    = self.top
  306.     far_bottom = self.bottom
  307.    
  308.     if self.left > other.left:
  309.       far_left = other.left
  310.    
  311.     if self.right < other.right:
  312.       far_right = other.right
  313.    
  314.     if self.bottom > other.bottom:
  315.       far_bottom = other.bottom
  316.    
  317.     if self.top < other.top:
  318.       far_top = other.top
  319.    
  320.     rect_area = [0,0,0,0]
  321.    
  322.     rect_area[0] = far_left
  323.     rect_area[1] = far_bottom
  324.     rect_area[2] = far_right - far_left
  325.     rect_area[3] = far_top   - far_bottom
  326.    
  327.     return Rect(rect_area)
  328.    
  329.  
  330.  
  331.   ##
  332.   #@brief Get the area shared by the caller and a given Rect
  333.   #
  334.   #@param other (Rect)\n
  335.   #             The Rect to intersect the caller with
  336.   #
  337.   #@return If other and the caller intersect, this method
  338.   #        returns a Rect covering the shared area\n
  339.   #        If they do not, then this method returns None
  340.   def intersection(self,other):
  341.     if not self.collideRect(other):
  342.       return None
  343.      
  344.    
  345.     near_left   = self.left
  346.     near_top    = self.top
  347.     near_right  = self.right
  348.     near_bottom = self.bottom
  349.    
  350.     if self.left < other.left:
  351.       near_left = other.left
  352.    
  353.     if self.right > other.right:
  354.       near_right = other.right
  355.    
  356.     if self.bottom < other.bottom:
  357.       near_bottom = other.bottom
  358.    
  359.     if self.top > other.top:
  360.       near_top = other.top
  361.    
  362.     rect_area = [0,0,0,0]
  363.    
  364.     rect_area[0] = near_left
  365.     rect_area[1] = near_bottom
  366.     rect_area[2] = near_right - near_left
  367.     rect_area[3] = near_top   - near_bottom
  368.    
  369.     return Rect(rect_area)
Advertisement
Add Comment
Please, Sign In to add comment