Consider performing a full-text search with your search terms.

Clear message

# 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: 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.

"""Point and Rectangle classes.

This code is in the public domain.

Point  -- point with (x,y) coordinates
Rect  -- two points, forming a rectangle
"""

import math

class Point:

"""A point identified by (x,y) coordinates.

supports: +, -, *, /, str, repr

length  -- calculate length of vector to point from origin
distance_to  -- calculate distance between two points
as_tuple  -- construct tuple (x,y)
clone  -- construct a duplicate
integerize  -- convert x & y to integers
floatize  -- convert x & y to floats
move_to  -- reset x & y
slide  -- move (in place) +dx, +dy, as spec'd by point
slide_xy  -- move (in place) +dx, +dy
rotate  -- rotate around the origin
rotate_about  -- rotate around another point
"""

def __init__(self, x=0.0, y=0.0):
self.x = x
self.y = y

"""Point(x1+x2, y1+y2)"""
return Point(self.x+p.x, self.y+p.y)

def __sub__(self, p):
"""Point(x1-x2, y1-y2)"""
return Point(self.x-p.x, self.y-p.y)

def __mul__( self, scalar ):
"""Point(x1*x2, y1*y2)"""
return Point(self.x*scalar, self.y*scalar)

def __div__(self, scalar):
"""Point(x1/x2, y1/y2)"""
return Point(self.x/scalar, self.y/scalar)

def __str__(self):
return "(%s, %s)" % (self.x, self.y)

def __repr__(self):
return "%s(%r, %r)" % (self.__class__.__name__, self.x, self.y)

def length(self):
return math.sqrt(self.x**2 + self.y**2)

def distance_to(self, p):
"""Calculate the distance between two points."""
return (self - p).length()

def as_tuple(self):
"""(x, y)"""
return (self.x, self.y)

def clone(self):
"""Return a full copy of this point."""
return Point(self.x, self.y)

def integerize(self):
"""Convert co-ordinate values to integers."""
self.x = int(self.x)
self.y = int(self.y)

def floatize(self):
"""Convert co-ordinate values to floats."""
self.x = float(self.x)
self.y = float(self.y)

def move_to(self, x, y):
"""Reset x & y coordinates."""
self.x = x
self.y = y

def slide(self, p):
'''Move to new (x+dx,y+dy).

Can anyone think up a better name for this function?
slide? shift? delta? move_by?
'''
self.x = self.x + p.x
self.y = self.y + p.y

def slide_xy(self, dx, dy):
'''Move to new (x+dx,y+dy).

Can anyone think up a better name for this function?
slide? shift? delta? move_by?
'''
self.x = self.x + dx
self.y = self.y + dy

Positive y goes *up,* as in traditional mathematics.

Interestingly, you can use this in y-down computer graphics, if
you just remember that it turns clockwise, rather than
counter-clockwise.

The new position is returned as a new Point.
"""
s, c = [f(rad) for f in (math.sin, math.cos)]
x, y = (c*self.x - s*self.y, s*self.x + c*self.y)
return Point(x,y)

"""Rotate counter-clockwise around a point, by theta degrees.

Positive y goes *up,* as in traditional mathematics.

The new position is returned as a new Point.
"""
result = self.clone()
result.slide(-p.x, -p.y)
result.rotate(theta)
result.slide(p.x, p.y)
return result

class Rect:

"""A rectangle identified by two points.

The rectangle stores left, top, right, and bottom values.

Coordinates are based on screen coordinates.

origin                               top
+-----> x increases                |
|                           left  -+-  right
v                                  |
y increases                         bottom

set_points  -- reset rectangle coordinates
contains  -- is a point inside?
overlaps  -- does a rectangle overlap?
top_left  -- get top-left corner
bottom_right  -- get bottom-right corner
expanded_by  -- grow (or shrink)
"""

def __init__(self, pt1, pt2):
"""Initialize a rectangle from two points."""
self.set_points(pt1, pt2)

def set_points(self, pt1, pt2):
"""Reset the rectangle coordinates."""
(x1, y1) = pt1.as_tuple()
(x2, y2) = pt2.as_tuple()
self.left = min(x1, x2)
self.top = min(y1, y2)
self.right = max(x1, x2)
self.bottom = max(y1, y2)

def contains(self, pt):
"""Return true if a point is inside the rectangle."""
x,y = pt.as_tuple()
return (self.left <= x <= self.right and
self.top <= y <= self.bottom)

def overlaps(self, other):
"""Return true if a rectangle overlaps this rectangle."""
return (self.right > other.left and self.left < other.right and
self.top < other.bottom and self.bottom > other.top)

def top_left(self):
"""Return the top-left corner as a Point."""
return Point(self.left, self.top)

def bottom_right(self):
"""Return the bottom-right corner as a Point."""
return Point(self.right, self.bottom)

def expanded_by(self, n):
"""Return a rectangle with extended borders.

Create a new rectangle that is wider and taller than the
immediate one. All sides are extended by "n" points.
"""
p1 = Point(self.left-n, self.top-n)
p2 = Point(self.right+n, self.bottom+n)
return Rect(p1, p2)

def __str__( self ):
return "<Rect (%s,%s)-(%s,%s)>" % (self.left,self.top,
self.right,self.bottom)

def __repr__(self):
return "%s(%r, %r)" % (self.__class__.__name__,
Point(self.left, self.top),
Point(self.right, self.bottom))

## Historical Note

It seems that Python version 1.0.2 had standard module rect!