blob: 74ccd5627699e4c5c757df57f1b75e479ec6a2f5 [file] [log] [blame]
Just470b5052000-01-16 20:37:11 +00001#
jvrfc3879e2003-08-29 19:29:46 +00002# Various array and rectangle tools, but mostly rectangles, hence the
3# name of this module (not).
Just470b5052000-01-16 20:37:11 +00004#
5
Just470b5052000-01-16 20:37:11 +00006
7def calcBounds(array):
jvrfc3879e2003-08-29 19:29:46 +00008 """Return the bounding rectangle of a 2D points array as a tuple:
9 (xMin, yMin, xMax, yMax)
Just470b5052000-01-16 20:37:11 +000010 """
jvrfc3879e2003-08-29 19:29:46 +000011 import Numeric
Just470b5052000-01-16 20:37:11 +000012 if len(array) == 0:
13 return 0, 0, 0, 0
jvrfc3879e2003-08-29 19:29:46 +000014 xMin, yMin = Numeric.minimum.reduce(array)
15 xMax, yMax = Numeric.maximum.reduce(array)
16 return xMin, yMin, xMax, yMax
Just470b5052000-01-16 20:37:11 +000017
jvr182a7ba2003-06-29 18:18:54 +000018def updateBounds(bounds, (x, y), min=min, max=max):
19 """Return the bounding recangle of rectangle bounds and point (x, y)."""
20 xMin, yMin, xMax, yMax = bounds
21 return min(xMin, x), min(yMin, y), max(xMax, x), max(yMax, y)
22
23def pointInRect((x, y), rect):
24 """Return True when point (x, y) is inside rect."""
25 xMin, yMin, xMax, yMax = rect
26 return (xMin <= x <= xMax) and (yMin <= y <= yMax)
27
Just470b5052000-01-16 20:37:11 +000028def pointsInRect(array, rect):
29 """Find out which points or array are inside rect.
30 Returns an array with a boolean for each point.
31 """
jvrfc3879e2003-08-29 19:29:46 +000032 import Numeric
Just470b5052000-01-16 20:37:11 +000033 if len(array) < 1:
34 return []
35 lefttop = rect[:2]
36 rightbottom = rect[2:]
37 condition = Numeric.logical_and(
jvrfc3879e2003-08-29 19:29:46 +000038 Numeric.greater_equal(array, lefttop),
39 Numeric.less_equal(array, rightbottom))
Just470b5052000-01-16 20:37:11 +000040 return Numeric.logical_and.reduce(condition, -1)
41
Justdeb3b632000-01-26 19:32:45 +000042def vectorLength(vector):
jvrfc3879e2003-08-29 19:29:46 +000043 """Return the length of the given vector."""
44 import Numeric
Justdeb3b632000-01-26 19:32:45 +000045 return Numeric.sqrt(vector[0]**2 + vector[1]**2)
46
47def asInt16(array):
jvrfc3879e2003-08-29 19:29:46 +000048 """Round and cast to 16 bit integer."""
49 import Numeric
Justdeb3b632000-01-26 19:32:45 +000050 return Numeric.floor(array + 0.5).astype(Numeric.Int16)
51
Just470b5052000-01-16 20:37:11 +000052
jvrfc3879e2003-08-29 19:29:46 +000053def normRect((xMin, yMin, xMax, yMax)):
54 """Normalize the rectangle so that the following holds:
55 xMin <= xMax and yMin <= yMax
56 """
57 return min(xMin, xMax), min(yMin, yMax), max(xMin, xMax), max(yMin, yMax)
Just470b5052000-01-16 20:37:11 +000058
jvrfc3879e2003-08-29 19:29:46 +000059def scaleRect((xMin, yMin, xMax, yMax), x, y):
60 """Scale the rectangle by x, y."""
61 return xMin * x, yMin * y, xMax * x, yMax * y
Just470b5052000-01-16 20:37:11 +000062
jvrfc3879e2003-08-29 19:29:46 +000063def offsetRect((xMin, yMin, xMax, yMax), dx, dy):
64 """Offset the rectangle by dx, dy."""
65 return xMin+dx, yMin+dy, xMax+dx, yMax+dy
Justbe7163c2000-01-18 22:29:39 +000066
jvrfc3879e2003-08-29 19:29:46 +000067def insetRect((xMin, yMin, xMax, yMax), dx, dy):
68 """Inset the rectangle by dx, dy on all sides."""
69 return xMin+dx, yMin+dy, xMax-dx, yMax-dy
Justbe7163c2000-01-18 22:29:39 +000070
jvrfc3879e2003-08-29 19:29:46 +000071def sectRect((xMin1, yMin1, xMax1, yMax1), (xMin2, yMin2, xMax2, yMax2)):
72 """Return a boolean and a rectangle. If the input rectangles intersect, return
73 True and the intersecting rectangle. Return False and (0, 0, 0, 0) if the input
74 rectangles don't intersect.
75 """
76 xMin, yMin, xMax, yMax = (max(xMin1, xMin2), max(yMin1, yMin2),
77 min(xMax1, xMax2), min(yMax1, yMax2))
78 if xMin >= xMax or yMin >= yMax:
Justbe7163c2000-01-18 22:29:39 +000079 return 0, (0, 0, 0, 0)
jvrfc3879e2003-08-29 19:29:46 +000080 return 1, (xMin, yMin, xMax, yMax)
Justbe7163c2000-01-18 22:29:39 +000081
jvrfc3879e2003-08-29 19:29:46 +000082def unionRect((xMin1, yMin1, xMax1, yMax1), (xMin2, yMin2, xMax2, yMax2)):
83 """Return the smallest rectangle in which both input rectangles are fully
84 enclosed. In other words, return the total bounding rectangle of both input
85 rectangles.
86 """
87 xMin, yMin, xMax, yMax = (min(xMin1, xMin2), min(yMin1, yMin2),
88 max(xMax1, xMax2), max(yMax1, yMax2))
89 return (xMin, yMin, xMax, yMax)
Just02a739a2000-01-23 19:10:27 +000090
jvrfc3879e2003-08-29 19:29:46 +000091def rectCenter((xMin, yMin, xMax, yMax)):
92 """Return the center of the rectangle as an (x, y) coordinate."""
93 return (xMin+xMax)/2, (yMin+yMax)/2
Just02a739a2000-01-23 19:10:27 +000094
jvrfc3879e2003-08-29 19:29:46 +000095def intRect((xMin, yMin, xMax, yMax)):
96 """Return the rectangle, rounded off to integer values, but guaranteeing that
97 the resulting rectangle is NOT smaller than the original.
98 """
99 import math
100 xMin = int(math.floor(xMin))
101 yMin = int(math.floor(yMin))
102 xMax = int(math.ceil(xMax))
103 yMax = int(math.ceil(yMax))
104 return (xMin, yMin, xMax, yMax)
Justbe7163c2000-01-18 22:29:39 +0000105
jvrfc3879e2003-08-29 19:29:46 +0000106
107if __name__ == "__main__":
108 import Numeric, math
109 assert calcBounds([(0, 40), (0, 100), (50, 50), (80, 10)]) == (0, 10, 80, 100)
110 assert updateBounds((0, 0, 0, 0), (100, 100)) == (0, 0, 100, 100)
111 assert pointInRect((50, 50), (0, 0, 100, 100))
112 assert pointInRect((0, 0), (0, 0, 100, 100))
113 assert pointInRect((100, 100), (0, 0, 100, 100))
114 assert not pointInRect((101, 100), (0, 0, 100, 100))
115 assert list(pointsInRect([(50, 50), (0, 0), (100, 100), (101, 100)],
116 (0, 0, 100, 100))) == [1, 1, 1, 0]
117 assert vectorLength((3, 4)) == 5
118 assert vectorLength((1, 1)) == math.sqrt(2)
119 assert list(asInt16(Numeric.array([0, 0.1, 0.5, 0.9]))) == [0, 0, 1, 1]
120 assert normRect((0, 10, 100, 200)) == (0, 10, 100, 200)
121 assert normRect((100, 200, 0, 10)) == (0, 10, 100, 200)
122 assert scaleRect((10, 20, 50, 150), 1.5, 2) == (15, 40, 75, 300)
123 assert offsetRect((10, 20, 30, 40), 5, 6) == ((15, 26, 35, 46))
124 assert insetRect((10, 20, 50, 60), 5, 10) == (15, 30, 45, 50)
125 assert insetRect((10, 20, 50, 60), -5, -10) == (5, 10, 55, 70)
126 intersects, rect = sectRect((0, 10, 20, 30), (0, 40, 20, 50))
127 assert not intersects
128 intersects, rect = sectRect((0, 10, 20, 30), (5, 20, 35, 50))
129 assert intersects
130 assert rect == (5, 20, 20, 30)
131 assert unionRect((0, 10, 20, 30), (0, 40, 20, 50)) == (0, 10, 20, 50)
132 assert rectCenter((0, 0, 100, 200)) == (50, 100)
133 assert rectCenter((0, 0, 100, 199.0)) == (50, 99.5)
134 assert intRect((0.9, 2.9, 3.1, 4.1)) == (0, 2, 4, 5)