2
# Various array and rectangle tools, but mostly rectangles, hence the
3
# name of this module (not).
8
"""Return the bounding rectangle of a 2D points array as a tuple:
9
(xMin, yMin, xMax, yMax)
14
xMin, yMin = Numeric.minimum.reduce(array)
15
xMax, yMax = Numeric.maximum.reduce(array)
16
return xMin, yMin, xMax, yMax
18
def 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)
23
def 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)
28
def pointsInRect(array, rect):
29
"""Find out which points or array are inside rect.
30
Returns an array with a boolean for each point.
36
rightbottom = rect[2:]
37
condition = Numeric.logical_and(
38
Numeric.greater_equal(array, lefttop),
39
Numeric.less_equal(array, rightbottom))
40
return Numeric.logical_and.reduce(condition, -1)
42
def vectorLength(vector):
43
"""Return the length of the given vector."""
45
return Numeric.sqrt(vector[0]**2 + vector[1]**2)
48
"""Round and cast to 16 bit integer."""
50
return Numeric.floor(array + 0.5).astype(Numeric.Int16)
53
def normRect((xMin, yMin, xMax, yMax)):
54
"""Normalize the rectangle so that the following holds:
55
xMin <= xMax and yMin <= yMax
57
return min(xMin, xMax), min(yMin, yMax), max(xMin, xMax), max(yMin, yMax)
59
def scaleRect((xMin, yMin, xMax, yMax), x, y):
60
"""Scale the rectangle by x, y."""
61
return xMin * x, yMin * y, xMax * x, yMax * y
63
def offsetRect((xMin, yMin, xMax, yMax), dx, dy):
64
"""Offset the rectangle by dx, dy."""
65
return xMin+dx, yMin+dy, xMax+dx, yMax+dy
67
def 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
71
def 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.
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:
79
return 0, (0, 0, 0, 0)
80
return 1, (xMin, yMin, xMax, yMax)
82
def 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
87
xMin, yMin, xMax, yMax = (min(xMin1, xMin2), min(yMin1, yMin2),
88
max(xMax1, xMax2), max(yMax1, yMax2))
89
return (xMin, yMin, xMax, yMax)
91
def 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
95
def 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.
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)
107
if __name__ == "__main__":
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))
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)