Revision 14 as of 2005-04-17 02:10:41

Clear message

TableOfContents()

Points & Rectangles

A pair of classes to provide points and rectangles.

Surprisingly, I haven't been able to find a single Python module providing such primitive support.

WxPython supports wxPoint and wxRect, but it lacks many basic functions (such as, say, adding two points together to produce a third point..!) (See: [http://wiki.wxpython.org/index.cgi/wx_2eRect wxPyWiki:wx.Rect])

This code is lacking a zillion essential features (but interpoint distance can now be calculated). I only put in the ones I needed immediately. Please add, refactor, optimize, rename stuff to be more standard, etc., as you see fit..!

If there's an actual, accessible, easy-to-include Python module, not tied to a graphics library, that does this stuff already, please write about it here! No sense in reinventing the wheel. I've looked, but haven't found one. Hence this.

   1 """Point and Rectangle classes.
   2 
   3 This code is in the public domain.
   4 
   5 Point  -- point with (x,y) coordinates
   6 Rect  -- two points, forming a rectangle
   7 """
   8 
   9 import math
  10 
  11 
  12 class Point:
  13 
  14     """A point identified by (x,y) coordinates.
  15 
  16     supports: +, -, *, /, str, repr
  17 
  18     as_tuple  -- construct tuple (x,y)
  19     clone  -- construct a duplicate
  20     integerize  -- convert x & y to integers
  21     floatize  -- convert x & y to floats
  22     distance_to  -- calculate distance between points
  23     move_to  -- reset x & y
  24     slide  -- move to +dx, +dy
  25     rotate  -- rotate around the origin
  26     rotate_about  -- rotate around another point
  27     """
  28 
  29     def __init__(self, x, y):
  30         self.x = x
  31         self.y = y
  32 
  33     def __add__(self, other):
  34         """Point(x1+x2, y1+y2)"""
  35         return Point(self.x+other.x, self.y+other.y)
  36 
  37     def __sub__(self, other):
  38         """Point(x1-x2, y1-y2)"""
  39         return Point(self.x-other.x, self.y-other.y)
  40 
  41     def __mul__( self, scalar ):
  42         """Point(x1*x2, y1*y2)"""
  43         return Point(self.x*scalar, self.y*scalar)
  44 
  45     def __div__(self, scalar):
  46         """Point(x1/x2, y1/y2)"""
  47         return Point(self.x/scalar, self.y/scalar)
  48 
  49     def __str__(self):
  50         return "(%s, %s)" % (self.x, self.y)
  51 
  52     def __repr__(self):
  53         return "%s(%r, %r)" % (self.__class__.__name__, self.x, self.y)
  54 
  55     def as_tuple(self):
  56         """(x, y)"""
  57         return (self.x, self.y)
  58 
  59     def clone(self):
  60         """Return a full copy of this point."""
  61         return Point(self.x, self.y)
  62 
  63     def integerize(self):
  64         """Convert co-ordinate values to integers."""
  65         self.x = int(self.x)
  66         self.y = int(self.y)
  67 
  68     def floatize(self):
  69         """Convert co-ordinate values to floats."""
  70         self.x = float(self.x)
  71         self.y = float(self.y)
  72 
  73     def distance_to(self, pt):
  74         """Calculate the distance between two points."""
  75         dy = float(self.y - pt.y)
  76         dx = float(self.x - pt.x)
  77         return sqrt(dy*dy + dx*dx)
  78 
  79     def move_to(self, x, y):
  80         """Reset x & y coordinates."""
  81         self.x = x
  82         self.y = y
  83 
  84     def slide(self, dx, dy):
  85         '''Move to new (x+dx,y+dy).
  86 
  87         Can anyone think up a better name for this function?
  88         slide? shift? delta? move_by?
  89         '''
  90         self.x = self.x + dx
  91         self.y = self.y + dy
  92 
  93     def rotate(self, theta):
  94         """Rotate clockwise by theta degrees.
  95 
  96         Rotate the point clockwise, around the origin.
  97         The new position is returned as a new Point.
  98 
  99         WARNING: UNTESTED CODE.
 100         """
 101         r2 = math.sqrt(self.x)+math.sqrt(self.y)
 102         tmp = math.tan(theta*math.pi/90 + math.atan(self.x/self.y))
 103         return Point(math.sqrt(r2/(1+tmp*tmp)),
 104                      ret.x * tmp)
 105 
 106     def rotate_about(self, pt, theta):
 107         """Rotate clockwise around a point, by theta degrees.
 108 
 109         Rotate the point clockwise, around another point.
 110         The new position is returned as a new Point.
 111 
 112         WARNING: UNTESTED CODE.
 113         """
 114         result = self.clone()
 115         result.slide(-pt.x, -pt.y)
 116         result.rotate(theta)
 117         result.slide(pt.x, pt.y)
 118         return result
 119 
 120 
 121 class Rect:
 122 
 123     """A rectangle identified by two points.
 124 
 125     The rectangle stores left, top, right, and bottom values.
 126 
 127     Coordinates are based on screen coordinates.
 128 
 129     origin                               top
 130        +-----> x increases                |
 131        |                           left  -+-  right
 132        v                                  |
 133     y increases                         bottom
 134 
 135     set_points  -- reset rectangle coordinates
 136     contains  -- is a point inside?
 137     overlaps  -- does a rectangle overlap?
 138     top_left  -- get top-left corner
 139     bottom_right  -- get bottom-right corner
 140     expanded_by  -- grow (or shrink)
 141     """
 142 
 143     def __init__(self, pt1, pt2):
 144         """Initialize a rectangle from two points."""
 145         self.set_points(pt1, pt2)
 146 
 147     def set_points(self, pt1, pt2):
 148         """Reset the rectangle coordinates."""
 149         (x1, y1) = pt1.as_tuple()
 150         (x2, y2) = pt2.as_tuple()
 151         self.left = min(x1, x2)
 152         self.top = min(y1, y2)
 153         self.right = max(x1, x2)
 154         self.bottom = max(y1, y2)
 155 
 156     def contains(self, pt):
 157         """Return true if a point is inside the rectangle."""
 158         x,y = pt.as_tuple()
 159         return (self.left <= x <= self.right and
 160                 self.top <= y <= self.bottom)
 161 
 162     def overlaps(self, other):
 163         """Return true if a rectangle overlaps this rectangle."""
 164         return (self.right > other.left and self.left < other.right and
 165                 self.top < other.bottom and self.bottom > other.top)
 166     
 167     def top_left(self):
 168         """Return the top-left corner as a Point."""
 169         return Point(self.left, self.top)
 170     
 171     def bottom_right(self):
 172         """Return the bottom-right corner as a Point."""
 173         return Point(self.right, self.bottom)
 174     
 175     def expanded_by(self, n):
 176         """Return a rectangle with extended borders.
 177 
 178         Create a new rectangle that is wider and taller than the
 179         immediate one. All sides are extended by "n" points.
 180         """
 181         p1 = Point(self.left-n, self.top-n)
 182         p2 = Point(self.right+n, self.bottom+n)
 183         return Rect(p1, p2)
 184     
 185     def __str__( self ):
 186         return "<Rect (%s,%s)-(%s,%s)>" % (self.left,self.top,
 187                                            self.right,self.bottom)
 188     
 189     def __repr__(self):
 190         return "%s(%r, %r)" % (self.__class__.__name__,
 191                                Point(self.left, self.top),
 192                                Point(self.right, self.bottom))

Historical Note

It seems that [http://www.informatik.hu-berlin.de/Themen/manuals/python/python-texinfo/top.html Python version 1.0.2] had [http://www.informatik.hu-berlin.de/Themen/manuals/python/python-texinfo/module_index.html standard module] [http://www.informatik.hu-berlin.de/Themen/manuals/python/python-texinfo/rect.html rect!]

See Also

Unable to edit the page? See the FrontPage for instructions.