Differences between revisions 11 and 12
Revision 11 as of 2004-11-26 19:17:58
Size: 4856
Editor: rba-cache1-vif1
Comment: Removes tabs to make indenting correct within Point().Rotate()
Revision 12 as of 2005-04-02 18:31:35
Size: 6924
Editor: aaron
Comment: PEP 8 strikes again
Deletions are marked like this. Additions are marked like this.
Line 17: Line 17:
# Code is Public Domain.

import math # required because of 'sqrt' in 'distanceTo' function
            # also tan and atan for rotations.

def normalize(x1, y1, x2, y2):
    '''I am not sure what this is for, care to comment?'''
    return min(x1,x2), min(y1,y2), max(x1,x2), max(y1,y2)
"""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
Line 27: Line 29:

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

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

    as_tuple -- construct tuple (x,y)
    clone -- construct a duplicate
    integerize -- convert x & y to integers
    floatize -- convert x & y to floats
    distance_to -- calculate distance between points
    move_to -- reset x & y
    slide -- move to +dx, +dy
    rotate -- rotate around the origin
    rotate_about -- rotate around another point
    """
Line 30: Line 48:
Line 31: Line 50:
        """Point(x1+x2, y1+y2)"""
Line 32: Line 52:
Line 33: Line 54:
        """Point(x1-x2, y1-y2)"""
Line 34: Line 56:
Line 35: Line 58:
        """Point(x1*x2, y1*y2)"""
Line 36: Line 60:
Line 37: Line 62:
        """Point(x1/x2, y1/y2)"""
Line 38: Line 64:
Line 40: Line 67:
Line 42: Line 70:
    def XY(self):
        '''Returns a tuple (x,y).'''
        return self.x,self.y
    def Clone(self):
        '''Returns a full copy of this point.'''

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

    def clone(self):
        """Return a full copy of this point."""
Line 48: Line 78:
    def Integerize(self):
        '''Rounds co-ordinate values to integers.'''

def integerize(self):
        """Convert co-ordinate values to integers."""
Line 52: Line 83:
    def Floatize(self):
        '''Converts co-ordinate values to floating point (is this necessary?)'''

def floatize(self):
        """Convert co-ordinate values to floats."""
Line 56: Line 88:
    def DistanceTo(self,pt):
        '''Distance between 2 points.'''
        dy = self.y - pt.y
        dx = self.x - pt.x

def distance_to(self, pt):
        """Calculate the distance between two points."""
        dy = float(self.y - pt.y)
        dx = float(self.x - pt.x)
Line 61: Line 94:
    def Move(newx,newy):
        '''Changes coordinates to those given.'''
        self.x = newx
        self.y = newy
    def MoveDelta(dx,dy):
        '''Move to new (x+dx,y+dy)'''

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

    def slide(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?
        '''
Line 69: Line 108:
    def Rotate(self,theta):
        '''Clockwise rotation about origin, theta in Degrees. Returns the new position as Point()'''
        # Err..this math is not exactly readable.
        # It is elementary though, involving only Pythogoras and basic trig.
        r2 = sqr(self.x)+sqr(self.y)

    def rotate(self, theta):
        """Rotate clockwise by theta degrees.

        Rotate the point clockwise, around the origin.
        The new position is returned as a new Point.

        WARNING: UNTESTED CODE.
        """
        r2 = math.sqrt(self.x)+math.sqrt(self.y)
Line 75: Line 119:
        ret = Point()
        ret.x = math.sqrt(r2/(1+tmp*tmp))
        ret.y = ret.x * tmp
        return ret
    def RotateAbout(self,OtherPoint,theta):
        '''Clockwise rotation about another point. Returns a Point() at new position'''
        tmpx = OtherPoint.x
        tmpy = OtherPoint.y
        self.MoveDelta(-tmpx,-tmpy)
        tmpPoint = self.Rotate(theta)
        tmpPoint.MoveDelta(tmpx,tmpy)
        return tmpPoint
        return Point(math.sqrt(r2/(1+tmp*tmp)),
                     ret.x * tmp)

    def rotate_about(self, pt, theta):
        """Rotate clockwise around a point, by theta degrees.

        Rotate the point clockwise, around another point.
        The new position is returned as a new Point.

        WARNING: UNTESTED CODE.
        """
        result = self.clone()
        result.slide(-pt.x, -pt.y)
        result.rotate(theta)
        result.slide(pt.x, pt.y)
        return result
Line 90: Line 138:

    """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)
    """
Line 91: Line 160:
        self.Set(pt1, pt2)
    def Contains(self, pt):
        x,y = pt.XY()
        return self.left <= x <= self.right and self.top <= y <= self.bottom
    def Set( self, pt1, pt2 ):
        extrema = normalize(pt1.x, pt1.y, pt2.x, pt2.y)
        self.left, self.top, self.right, self.bottom = extrema
    def Overlaps(self, other):
        return (self.right > other.left and self.left < other.right
                and self.top < other.bottom and self.bottom > other.top)
    def GetTL(self):
        """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."""
Line 103: Line 186:
    def GetBR(self):          def bottom_right(self):
        """Return the bottom-right corner as a Point."""
Line 105: Line 190:
    def ExpandedBy(self, n):
        p1 = Point(self.left-n, self.top+n)
         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)
Line 109: Line 200:
    def TransformedByFunction(self, foo):
        p1 = Point(self.left, self.top)
        p2 = Point(self.right, self.bottom)
        return Rect(foo(p1), foo(p2))
    
Line 116: Line 204:
    
Line 122: Line 211:

== See Also ==

 * [http://en.wikipedia.org/wiki/Cartesian_coordinate_system Wikipedia:Cartesian coordinate system]
 * [http://en.wikipedia.org/wiki/Vector_%28spatial%29 Wikipedia:Vector]

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..!)

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))

See Also

PointsAndRectangles (last edited 2008-11-15 13:59:40 by localhost)

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