xref: /aosp_15_r20/external/fonttools/Lib/fontTools/misc/arrayTools.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
1*e1fe3e4aSElliott Hughes"""Routines for calculating bounding boxes, point in rectangle calculations and
2*e1fe3e4aSElliott Hughesso on.
3*e1fe3e4aSElliott Hughes"""
4*e1fe3e4aSElliott Hughes
5*e1fe3e4aSElliott Hughesfrom fontTools.misc.roundTools import otRound
6*e1fe3e4aSElliott Hughesfrom fontTools.misc.vector import Vector as _Vector
7*e1fe3e4aSElliott Hughesimport math
8*e1fe3e4aSElliott Hughesimport warnings
9*e1fe3e4aSElliott Hughes
10*e1fe3e4aSElliott Hughes
11*e1fe3e4aSElliott Hughesdef calcBounds(array):
12*e1fe3e4aSElliott Hughes    """Calculate the bounding rectangle of a 2D points array.
13*e1fe3e4aSElliott Hughes
14*e1fe3e4aSElliott Hughes    Args:
15*e1fe3e4aSElliott Hughes        array: A sequence of 2D tuples.
16*e1fe3e4aSElliott Hughes
17*e1fe3e4aSElliott Hughes    Returns:
18*e1fe3e4aSElliott Hughes        A four-item tuple representing the bounding rectangle ``(xMin, yMin, xMax, yMax)``.
19*e1fe3e4aSElliott Hughes    """
20*e1fe3e4aSElliott Hughes    if not array:
21*e1fe3e4aSElliott Hughes        return 0, 0, 0, 0
22*e1fe3e4aSElliott Hughes    xs = [x for x, y in array]
23*e1fe3e4aSElliott Hughes    ys = [y for x, y in array]
24*e1fe3e4aSElliott Hughes    return min(xs), min(ys), max(xs), max(ys)
25*e1fe3e4aSElliott Hughes
26*e1fe3e4aSElliott Hughes
27*e1fe3e4aSElliott Hughesdef calcIntBounds(array, round=otRound):
28*e1fe3e4aSElliott Hughes    """Calculate the integer bounding rectangle of a 2D points array.
29*e1fe3e4aSElliott Hughes
30*e1fe3e4aSElliott Hughes    Values are rounded to closest integer towards ``+Infinity`` using the
31*e1fe3e4aSElliott Hughes    :func:`fontTools.misc.fixedTools.otRound` function by default, unless
32*e1fe3e4aSElliott Hughes    an optional ``round`` function is passed.
33*e1fe3e4aSElliott Hughes
34*e1fe3e4aSElliott Hughes    Args:
35*e1fe3e4aSElliott Hughes        array: A sequence of 2D tuples.
36*e1fe3e4aSElliott Hughes        round: A rounding function of type ``f(x: float) -> int``.
37*e1fe3e4aSElliott Hughes
38*e1fe3e4aSElliott Hughes    Returns:
39*e1fe3e4aSElliott Hughes        A four-item tuple of integers representing the bounding rectangle:
40*e1fe3e4aSElliott Hughes        ``(xMin, yMin, xMax, yMax)``.
41*e1fe3e4aSElliott Hughes    """
42*e1fe3e4aSElliott Hughes    return tuple(round(v) for v in calcBounds(array))
43*e1fe3e4aSElliott Hughes
44*e1fe3e4aSElliott Hughes
45*e1fe3e4aSElliott Hughesdef updateBounds(bounds, p, min=min, max=max):
46*e1fe3e4aSElliott Hughes    """Add a point to a bounding rectangle.
47*e1fe3e4aSElliott Hughes
48*e1fe3e4aSElliott Hughes    Args:
49*e1fe3e4aSElliott Hughes        bounds: A bounding rectangle expressed as a tuple
50*e1fe3e4aSElliott Hughes            ``(xMin, yMin, xMax, yMax), or None``.
51*e1fe3e4aSElliott Hughes        p: A 2D tuple representing a point.
52*e1fe3e4aSElliott Hughes        min,max: functions to compute the minimum and maximum.
53*e1fe3e4aSElliott Hughes
54*e1fe3e4aSElliott Hughes    Returns:
55*e1fe3e4aSElliott Hughes        The updated bounding rectangle ``(xMin, yMin, xMax, yMax)``.
56*e1fe3e4aSElliott Hughes    """
57*e1fe3e4aSElliott Hughes    (x, y) = p
58*e1fe3e4aSElliott Hughes    if bounds is None:
59*e1fe3e4aSElliott Hughes        return x, y, x, y
60*e1fe3e4aSElliott Hughes    xMin, yMin, xMax, yMax = bounds
61*e1fe3e4aSElliott Hughes    return min(xMin, x), min(yMin, y), max(xMax, x), max(yMax, y)
62*e1fe3e4aSElliott Hughes
63*e1fe3e4aSElliott Hughes
64*e1fe3e4aSElliott Hughesdef pointInRect(p, rect):
65*e1fe3e4aSElliott Hughes    """Test if a point is inside a bounding rectangle.
66*e1fe3e4aSElliott Hughes
67*e1fe3e4aSElliott Hughes    Args:
68*e1fe3e4aSElliott Hughes        p: A 2D tuple representing a point.
69*e1fe3e4aSElliott Hughes        rect: A bounding rectangle expressed as a tuple
70*e1fe3e4aSElliott Hughes            ``(xMin, yMin, xMax, yMax)``.
71*e1fe3e4aSElliott Hughes
72*e1fe3e4aSElliott Hughes    Returns:
73*e1fe3e4aSElliott Hughes        ``True`` if the point is inside the rectangle, ``False`` otherwise.
74*e1fe3e4aSElliott Hughes    """
75*e1fe3e4aSElliott Hughes    (x, y) = p
76*e1fe3e4aSElliott Hughes    xMin, yMin, xMax, yMax = rect
77*e1fe3e4aSElliott Hughes    return (xMin <= x <= xMax) and (yMin <= y <= yMax)
78*e1fe3e4aSElliott Hughes
79*e1fe3e4aSElliott Hughes
80*e1fe3e4aSElliott Hughesdef pointsInRect(array, rect):
81*e1fe3e4aSElliott Hughes    """Determine which points are inside a bounding rectangle.
82*e1fe3e4aSElliott Hughes
83*e1fe3e4aSElliott Hughes    Args:
84*e1fe3e4aSElliott Hughes        array: A sequence of 2D tuples.
85*e1fe3e4aSElliott Hughes        rect: A bounding rectangle expressed as a tuple
86*e1fe3e4aSElliott Hughes            ``(xMin, yMin, xMax, yMax)``.
87*e1fe3e4aSElliott Hughes
88*e1fe3e4aSElliott Hughes    Returns:
89*e1fe3e4aSElliott Hughes        A list containing the points inside the rectangle.
90*e1fe3e4aSElliott Hughes    """
91*e1fe3e4aSElliott Hughes    if len(array) < 1:
92*e1fe3e4aSElliott Hughes        return []
93*e1fe3e4aSElliott Hughes    xMin, yMin, xMax, yMax = rect
94*e1fe3e4aSElliott Hughes    return [(xMin <= x <= xMax) and (yMin <= y <= yMax) for x, y in array]
95*e1fe3e4aSElliott Hughes
96*e1fe3e4aSElliott Hughes
97*e1fe3e4aSElliott Hughesdef vectorLength(vector):
98*e1fe3e4aSElliott Hughes    """Calculate the length of the given vector.
99*e1fe3e4aSElliott Hughes
100*e1fe3e4aSElliott Hughes    Args:
101*e1fe3e4aSElliott Hughes        vector: A 2D tuple.
102*e1fe3e4aSElliott Hughes
103*e1fe3e4aSElliott Hughes    Returns:
104*e1fe3e4aSElliott Hughes        The Euclidean length of the vector.
105*e1fe3e4aSElliott Hughes    """
106*e1fe3e4aSElliott Hughes    x, y = vector
107*e1fe3e4aSElliott Hughes    return math.sqrt(x**2 + y**2)
108*e1fe3e4aSElliott Hughes
109*e1fe3e4aSElliott Hughes
110*e1fe3e4aSElliott Hughesdef asInt16(array):
111*e1fe3e4aSElliott Hughes    """Round a list of floats to 16-bit signed integers.
112*e1fe3e4aSElliott Hughes
113*e1fe3e4aSElliott Hughes    Args:
114*e1fe3e4aSElliott Hughes        array: List of float values.
115*e1fe3e4aSElliott Hughes
116*e1fe3e4aSElliott Hughes    Returns:
117*e1fe3e4aSElliott Hughes        A list of rounded integers.
118*e1fe3e4aSElliott Hughes    """
119*e1fe3e4aSElliott Hughes    return [int(math.floor(i + 0.5)) for i in array]
120*e1fe3e4aSElliott Hughes
121*e1fe3e4aSElliott Hughes
122*e1fe3e4aSElliott Hughesdef normRect(rect):
123*e1fe3e4aSElliott Hughes    """Normalize a bounding box rectangle.
124*e1fe3e4aSElliott Hughes
125*e1fe3e4aSElliott Hughes    This function "turns the rectangle the right way up", so that the following
126*e1fe3e4aSElliott Hughes    holds::
127*e1fe3e4aSElliott Hughes
128*e1fe3e4aSElliott Hughes        xMin <= xMax and yMin <= yMax
129*e1fe3e4aSElliott Hughes
130*e1fe3e4aSElliott Hughes    Args:
131*e1fe3e4aSElliott Hughes        rect: A bounding rectangle expressed as a tuple
132*e1fe3e4aSElliott Hughes            ``(xMin, yMin, xMax, yMax)``.
133*e1fe3e4aSElliott Hughes
134*e1fe3e4aSElliott Hughes    Returns:
135*e1fe3e4aSElliott Hughes        A normalized bounding rectangle.
136*e1fe3e4aSElliott Hughes    """
137*e1fe3e4aSElliott Hughes    (xMin, yMin, xMax, yMax) = rect
138*e1fe3e4aSElliott Hughes    return min(xMin, xMax), min(yMin, yMax), max(xMin, xMax), max(yMin, yMax)
139*e1fe3e4aSElliott Hughes
140*e1fe3e4aSElliott Hughes
141*e1fe3e4aSElliott Hughesdef scaleRect(rect, x, y):
142*e1fe3e4aSElliott Hughes    """Scale a bounding box rectangle.
143*e1fe3e4aSElliott Hughes
144*e1fe3e4aSElliott Hughes    Args:
145*e1fe3e4aSElliott Hughes        rect: A bounding rectangle expressed as a tuple
146*e1fe3e4aSElliott Hughes            ``(xMin, yMin, xMax, yMax)``.
147*e1fe3e4aSElliott Hughes        x: Factor to scale the rectangle along the X axis.
148*e1fe3e4aSElliott Hughes        Y: Factor to scale the rectangle along the Y axis.
149*e1fe3e4aSElliott Hughes
150*e1fe3e4aSElliott Hughes    Returns:
151*e1fe3e4aSElliott Hughes        A scaled bounding rectangle.
152*e1fe3e4aSElliott Hughes    """
153*e1fe3e4aSElliott Hughes    (xMin, yMin, xMax, yMax) = rect
154*e1fe3e4aSElliott Hughes    return xMin * x, yMin * y, xMax * x, yMax * y
155*e1fe3e4aSElliott Hughes
156*e1fe3e4aSElliott Hughes
157*e1fe3e4aSElliott Hughesdef offsetRect(rect, dx, dy):
158*e1fe3e4aSElliott Hughes    """Offset a bounding box rectangle.
159*e1fe3e4aSElliott Hughes
160*e1fe3e4aSElliott Hughes    Args:
161*e1fe3e4aSElliott Hughes        rect: A bounding rectangle expressed as a tuple
162*e1fe3e4aSElliott Hughes            ``(xMin, yMin, xMax, yMax)``.
163*e1fe3e4aSElliott Hughes        dx: Amount to offset the rectangle along the X axis.
164*e1fe3e4aSElliott Hughes        dY: Amount to offset the rectangle along the Y axis.
165*e1fe3e4aSElliott Hughes
166*e1fe3e4aSElliott Hughes    Returns:
167*e1fe3e4aSElliott Hughes        An offset bounding rectangle.
168*e1fe3e4aSElliott Hughes    """
169*e1fe3e4aSElliott Hughes    (xMin, yMin, xMax, yMax) = rect
170*e1fe3e4aSElliott Hughes    return xMin + dx, yMin + dy, xMax + dx, yMax + dy
171*e1fe3e4aSElliott Hughes
172*e1fe3e4aSElliott Hughes
173*e1fe3e4aSElliott Hughesdef insetRect(rect, dx, dy):
174*e1fe3e4aSElliott Hughes    """Inset a bounding box rectangle on all sides.
175*e1fe3e4aSElliott Hughes
176*e1fe3e4aSElliott Hughes    Args:
177*e1fe3e4aSElliott Hughes        rect: A bounding rectangle expressed as a tuple
178*e1fe3e4aSElliott Hughes            ``(xMin, yMin, xMax, yMax)``.
179*e1fe3e4aSElliott Hughes        dx: Amount to inset the rectangle along the X axis.
180*e1fe3e4aSElliott Hughes        dY: Amount to inset the rectangle along the Y axis.
181*e1fe3e4aSElliott Hughes
182*e1fe3e4aSElliott Hughes    Returns:
183*e1fe3e4aSElliott Hughes        An inset bounding rectangle.
184*e1fe3e4aSElliott Hughes    """
185*e1fe3e4aSElliott Hughes    (xMin, yMin, xMax, yMax) = rect
186*e1fe3e4aSElliott Hughes    return xMin + dx, yMin + dy, xMax - dx, yMax - dy
187*e1fe3e4aSElliott Hughes
188*e1fe3e4aSElliott Hughes
189*e1fe3e4aSElliott Hughesdef sectRect(rect1, rect2):
190*e1fe3e4aSElliott Hughes    """Test for rectangle-rectangle intersection.
191*e1fe3e4aSElliott Hughes
192*e1fe3e4aSElliott Hughes    Args:
193*e1fe3e4aSElliott Hughes        rect1: First bounding rectangle, expressed as tuples
194*e1fe3e4aSElliott Hughes            ``(xMin, yMin, xMax, yMax)``.
195*e1fe3e4aSElliott Hughes        rect2: Second bounding rectangle.
196*e1fe3e4aSElliott Hughes
197*e1fe3e4aSElliott Hughes    Returns:
198*e1fe3e4aSElliott Hughes        A boolean and a rectangle.
199*e1fe3e4aSElliott Hughes        If the input rectangles intersect, returns ``True`` and the intersecting
200*e1fe3e4aSElliott Hughes        rectangle. Returns ``False`` and ``(0, 0, 0, 0)`` if the input
201*e1fe3e4aSElliott Hughes        rectangles don't intersect.
202*e1fe3e4aSElliott Hughes    """
203*e1fe3e4aSElliott Hughes    (xMin1, yMin1, xMax1, yMax1) = rect1
204*e1fe3e4aSElliott Hughes    (xMin2, yMin2, xMax2, yMax2) = rect2
205*e1fe3e4aSElliott Hughes    xMin, yMin, xMax, yMax = (
206*e1fe3e4aSElliott Hughes        max(xMin1, xMin2),
207*e1fe3e4aSElliott Hughes        max(yMin1, yMin2),
208*e1fe3e4aSElliott Hughes        min(xMax1, xMax2),
209*e1fe3e4aSElliott Hughes        min(yMax1, yMax2),
210*e1fe3e4aSElliott Hughes    )
211*e1fe3e4aSElliott Hughes    if xMin >= xMax or yMin >= yMax:
212*e1fe3e4aSElliott Hughes        return False, (0, 0, 0, 0)
213*e1fe3e4aSElliott Hughes    return True, (xMin, yMin, xMax, yMax)
214*e1fe3e4aSElliott Hughes
215*e1fe3e4aSElliott Hughes
216*e1fe3e4aSElliott Hughesdef unionRect(rect1, rect2):
217*e1fe3e4aSElliott Hughes    """Determine union of bounding rectangles.
218*e1fe3e4aSElliott Hughes
219*e1fe3e4aSElliott Hughes    Args:
220*e1fe3e4aSElliott Hughes        rect1: First bounding rectangle, expressed as tuples
221*e1fe3e4aSElliott Hughes            ``(xMin, yMin, xMax, yMax)``.
222*e1fe3e4aSElliott Hughes        rect2: Second bounding rectangle.
223*e1fe3e4aSElliott Hughes
224*e1fe3e4aSElliott Hughes    Returns:
225*e1fe3e4aSElliott Hughes        The smallest rectangle in which both input rectangles are fully
226*e1fe3e4aSElliott Hughes        enclosed.
227*e1fe3e4aSElliott Hughes    """
228*e1fe3e4aSElliott Hughes    (xMin1, yMin1, xMax1, yMax1) = rect1
229*e1fe3e4aSElliott Hughes    (xMin2, yMin2, xMax2, yMax2) = rect2
230*e1fe3e4aSElliott Hughes    xMin, yMin, xMax, yMax = (
231*e1fe3e4aSElliott Hughes        min(xMin1, xMin2),
232*e1fe3e4aSElliott Hughes        min(yMin1, yMin2),
233*e1fe3e4aSElliott Hughes        max(xMax1, xMax2),
234*e1fe3e4aSElliott Hughes        max(yMax1, yMax2),
235*e1fe3e4aSElliott Hughes    )
236*e1fe3e4aSElliott Hughes    return (xMin, yMin, xMax, yMax)
237*e1fe3e4aSElliott Hughes
238*e1fe3e4aSElliott Hughes
239*e1fe3e4aSElliott Hughesdef rectCenter(rect):
240*e1fe3e4aSElliott Hughes    """Determine rectangle center.
241*e1fe3e4aSElliott Hughes
242*e1fe3e4aSElliott Hughes    Args:
243*e1fe3e4aSElliott Hughes        rect: Bounding rectangle, expressed as tuples
244*e1fe3e4aSElliott Hughes            ``(xMin, yMin, xMax, yMax)``.
245*e1fe3e4aSElliott Hughes
246*e1fe3e4aSElliott Hughes    Returns:
247*e1fe3e4aSElliott Hughes        A 2D tuple representing the point at the center of the rectangle.
248*e1fe3e4aSElliott Hughes    """
249*e1fe3e4aSElliott Hughes    (xMin, yMin, xMax, yMax) = rect
250*e1fe3e4aSElliott Hughes    return (xMin + xMax) / 2, (yMin + yMax) / 2
251*e1fe3e4aSElliott Hughes
252*e1fe3e4aSElliott Hughes
253*e1fe3e4aSElliott Hughesdef rectArea(rect):
254*e1fe3e4aSElliott Hughes    """Determine rectangle area.
255*e1fe3e4aSElliott Hughes
256*e1fe3e4aSElliott Hughes    Args:
257*e1fe3e4aSElliott Hughes        rect: Bounding rectangle, expressed as tuples
258*e1fe3e4aSElliott Hughes            ``(xMin, yMin, xMax, yMax)``.
259*e1fe3e4aSElliott Hughes
260*e1fe3e4aSElliott Hughes    Returns:
261*e1fe3e4aSElliott Hughes        The area of the rectangle.
262*e1fe3e4aSElliott Hughes    """
263*e1fe3e4aSElliott Hughes    (xMin, yMin, xMax, yMax) = rect
264*e1fe3e4aSElliott Hughes    return (yMax - yMin) * (xMax - xMin)
265*e1fe3e4aSElliott Hughes
266*e1fe3e4aSElliott Hughes
267*e1fe3e4aSElliott Hughesdef intRect(rect):
268*e1fe3e4aSElliott Hughes    """Round a rectangle to integer values.
269*e1fe3e4aSElliott Hughes
270*e1fe3e4aSElliott Hughes    Guarantees that the resulting rectangle is NOT smaller than the original.
271*e1fe3e4aSElliott Hughes
272*e1fe3e4aSElliott Hughes    Args:
273*e1fe3e4aSElliott Hughes        rect: Bounding rectangle, expressed as tuples
274*e1fe3e4aSElliott Hughes            ``(xMin, yMin, xMax, yMax)``.
275*e1fe3e4aSElliott Hughes
276*e1fe3e4aSElliott Hughes    Returns:
277*e1fe3e4aSElliott Hughes        A rounded bounding rectangle.
278*e1fe3e4aSElliott Hughes    """
279*e1fe3e4aSElliott Hughes    (xMin, yMin, xMax, yMax) = rect
280*e1fe3e4aSElliott Hughes    xMin = int(math.floor(xMin))
281*e1fe3e4aSElliott Hughes    yMin = int(math.floor(yMin))
282*e1fe3e4aSElliott Hughes    xMax = int(math.ceil(xMax))
283*e1fe3e4aSElliott Hughes    yMax = int(math.ceil(yMax))
284*e1fe3e4aSElliott Hughes    return (xMin, yMin, xMax, yMax)
285*e1fe3e4aSElliott Hughes
286*e1fe3e4aSElliott Hughes
287*e1fe3e4aSElliott Hughesdef quantizeRect(rect, factor=1):
288*e1fe3e4aSElliott Hughes    """
289*e1fe3e4aSElliott Hughes    >>> bounds = (72.3, -218.4, 1201.3, 919.1)
290*e1fe3e4aSElliott Hughes    >>> quantizeRect(bounds)
291*e1fe3e4aSElliott Hughes    (72, -219, 1202, 920)
292*e1fe3e4aSElliott Hughes    >>> quantizeRect(bounds, factor=10)
293*e1fe3e4aSElliott Hughes    (70, -220, 1210, 920)
294*e1fe3e4aSElliott Hughes    >>> quantizeRect(bounds, factor=100)
295*e1fe3e4aSElliott Hughes    (0, -300, 1300, 1000)
296*e1fe3e4aSElliott Hughes    """
297*e1fe3e4aSElliott Hughes    if factor < 1:
298*e1fe3e4aSElliott Hughes        raise ValueError(f"Expected quantization factor >= 1, found: {factor!r}")
299*e1fe3e4aSElliott Hughes    xMin, yMin, xMax, yMax = normRect(rect)
300*e1fe3e4aSElliott Hughes    return (
301*e1fe3e4aSElliott Hughes        int(math.floor(xMin / factor) * factor),
302*e1fe3e4aSElliott Hughes        int(math.floor(yMin / factor) * factor),
303*e1fe3e4aSElliott Hughes        int(math.ceil(xMax / factor) * factor),
304*e1fe3e4aSElliott Hughes        int(math.ceil(yMax / factor) * factor),
305*e1fe3e4aSElliott Hughes    )
306*e1fe3e4aSElliott Hughes
307*e1fe3e4aSElliott Hughes
308*e1fe3e4aSElliott Hughesclass Vector(_Vector):
309*e1fe3e4aSElliott Hughes    def __init__(self, *args, **kwargs):
310*e1fe3e4aSElliott Hughes        warnings.warn(
311*e1fe3e4aSElliott Hughes            "fontTools.misc.arrayTools.Vector has been deprecated, please use "
312*e1fe3e4aSElliott Hughes            "fontTools.misc.vector.Vector instead.",
313*e1fe3e4aSElliott Hughes            DeprecationWarning,
314*e1fe3e4aSElliott Hughes        )
315*e1fe3e4aSElliott Hughes
316*e1fe3e4aSElliott Hughes
317*e1fe3e4aSElliott Hughesdef pairwise(iterable, reverse=False):
318*e1fe3e4aSElliott Hughes    """Iterate over current and next items in iterable.
319*e1fe3e4aSElliott Hughes
320*e1fe3e4aSElliott Hughes    Args:
321*e1fe3e4aSElliott Hughes        iterable: An iterable
322*e1fe3e4aSElliott Hughes        reverse: If true, iterate in reverse order.
323*e1fe3e4aSElliott Hughes
324*e1fe3e4aSElliott Hughes    Returns:
325*e1fe3e4aSElliott Hughes        A iterable yielding two elements per iteration.
326*e1fe3e4aSElliott Hughes
327*e1fe3e4aSElliott Hughes    Example:
328*e1fe3e4aSElliott Hughes
329*e1fe3e4aSElliott Hughes        >>> tuple(pairwise([]))
330*e1fe3e4aSElliott Hughes        ()
331*e1fe3e4aSElliott Hughes        >>> tuple(pairwise([], reverse=True))
332*e1fe3e4aSElliott Hughes        ()
333*e1fe3e4aSElliott Hughes        >>> tuple(pairwise([0]))
334*e1fe3e4aSElliott Hughes        ((0, 0),)
335*e1fe3e4aSElliott Hughes        >>> tuple(pairwise([0], reverse=True))
336*e1fe3e4aSElliott Hughes        ((0, 0),)
337*e1fe3e4aSElliott Hughes        >>> tuple(pairwise([0, 1]))
338*e1fe3e4aSElliott Hughes        ((0, 1), (1, 0))
339*e1fe3e4aSElliott Hughes        >>> tuple(pairwise([0, 1], reverse=True))
340*e1fe3e4aSElliott Hughes        ((1, 0), (0, 1))
341*e1fe3e4aSElliott Hughes        >>> tuple(pairwise([0, 1, 2]))
342*e1fe3e4aSElliott Hughes        ((0, 1), (1, 2), (2, 0))
343*e1fe3e4aSElliott Hughes        >>> tuple(pairwise([0, 1, 2], reverse=True))
344*e1fe3e4aSElliott Hughes        ((2, 1), (1, 0), (0, 2))
345*e1fe3e4aSElliott Hughes        >>> tuple(pairwise(['a', 'b', 'c', 'd']))
346*e1fe3e4aSElliott Hughes        (('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'a'))
347*e1fe3e4aSElliott Hughes        >>> tuple(pairwise(['a', 'b', 'c', 'd'], reverse=True))
348*e1fe3e4aSElliott Hughes        (('d', 'c'), ('c', 'b'), ('b', 'a'), ('a', 'd'))
349*e1fe3e4aSElliott Hughes    """
350*e1fe3e4aSElliott Hughes    if not iterable:
351*e1fe3e4aSElliott Hughes        return
352*e1fe3e4aSElliott Hughes    if reverse:
353*e1fe3e4aSElliott Hughes        it = reversed(iterable)
354*e1fe3e4aSElliott Hughes    else:
355*e1fe3e4aSElliott Hughes        it = iter(iterable)
356*e1fe3e4aSElliott Hughes    first = next(it, None)
357*e1fe3e4aSElliott Hughes    a = first
358*e1fe3e4aSElliott Hughes    for b in it:
359*e1fe3e4aSElliott Hughes        yield (a, b)
360*e1fe3e4aSElliott Hughes        a = b
361*e1fe3e4aSElliott Hughes    yield (a, first)
362*e1fe3e4aSElliott Hughes
363*e1fe3e4aSElliott Hughes
364*e1fe3e4aSElliott Hughesdef _test():
365*e1fe3e4aSElliott Hughes    """
366*e1fe3e4aSElliott Hughes    >>> import math
367*e1fe3e4aSElliott Hughes    >>> calcBounds([])
368*e1fe3e4aSElliott Hughes    (0, 0, 0, 0)
369*e1fe3e4aSElliott Hughes    >>> calcBounds([(0, 40), (0, 100), (50, 50), (80, 10)])
370*e1fe3e4aSElliott Hughes    (0, 10, 80, 100)
371*e1fe3e4aSElliott Hughes    >>> updateBounds((0, 0, 0, 0), (100, 100))
372*e1fe3e4aSElliott Hughes    (0, 0, 100, 100)
373*e1fe3e4aSElliott Hughes    >>> pointInRect((50, 50), (0, 0, 100, 100))
374*e1fe3e4aSElliott Hughes    True
375*e1fe3e4aSElliott Hughes    >>> pointInRect((0, 0), (0, 0, 100, 100))
376*e1fe3e4aSElliott Hughes    True
377*e1fe3e4aSElliott Hughes    >>> pointInRect((100, 100), (0, 0, 100, 100))
378*e1fe3e4aSElliott Hughes    True
379*e1fe3e4aSElliott Hughes    >>> not pointInRect((101, 100), (0, 0, 100, 100))
380*e1fe3e4aSElliott Hughes    True
381*e1fe3e4aSElliott Hughes    >>> list(pointsInRect([(50, 50), (0, 0), (100, 100), (101, 100)], (0, 0, 100, 100)))
382*e1fe3e4aSElliott Hughes    [True, True, True, False]
383*e1fe3e4aSElliott Hughes    >>> vectorLength((3, 4))
384*e1fe3e4aSElliott Hughes    5.0
385*e1fe3e4aSElliott Hughes    >>> vectorLength((1, 1)) == math.sqrt(2)
386*e1fe3e4aSElliott Hughes    True
387*e1fe3e4aSElliott Hughes    >>> list(asInt16([0, 0.1, 0.5, 0.9]))
388*e1fe3e4aSElliott Hughes    [0, 0, 1, 1]
389*e1fe3e4aSElliott Hughes    >>> normRect((0, 10, 100, 200))
390*e1fe3e4aSElliott Hughes    (0, 10, 100, 200)
391*e1fe3e4aSElliott Hughes    >>> normRect((100, 200, 0, 10))
392*e1fe3e4aSElliott Hughes    (0, 10, 100, 200)
393*e1fe3e4aSElliott Hughes    >>> scaleRect((10, 20, 50, 150), 1.5, 2)
394*e1fe3e4aSElliott Hughes    (15.0, 40, 75.0, 300)
395*e1fe3e4aSElliott Hughes    >>> offsetRect((10, 20, 30, 40), 5, 6)
396*e1fe3e4aSElliott Hughes    (15, 26, 35, 46)
397*e1fe3e4aSElliott Hughes    >>> insetRect((10, 20, 50, 60), 5, 10)
398*e1fe3e4aSElliott Hughes    (15, 30, 45, 50)
399*e1fe3e4aSElliott Hughes    >>> insetRect((10, 20, 50, 60), -5, -10)
400*e1fe3e4aSElliott Hughes    (5, 10, 55, 70)
401*e1fe3e4aSElliott Hughes    >>> intersects, rect = sectRect((0, 10, 20, 30), (0, 40, 20, 50))
402*e1fe3e4aSElliott Hughes    >>> not intersects
403*e1fe3e4aSElliott Hughes    True
404*e1fe3e4aSElliott Hughes    >>> intersects, rect = sectRect((0, 10, 20, 30), (5, 20, 35, 50))
405*e1fe3e4aSElliott Hughes    >>> intersects
406*e1fe3e4aSElliott Hughes    1
407*e1fe3e4aSElliott Hughes    >>> rect
408*e1fe3e4aSElliott Hughes    (5, 20, 20, 30)
409*e1fe3e4aSElliott Hughes    >>> unionRect((0, 10, 20, 30), (0, 40, 20, 50))
410*e1fe3e4aSElliott Hughes    (0, 10, 20, 50)
411*e1fe3e4aSElliott Hughes    >>> rectCenter((0, 0, 100, 200))
412*e1fe3e4aSElliott Hughes    (50.0, 100.0)
413*e1fe3e4aSElliott Hughes    >>> rectCenter((0, 0, 100, 199.0))
414*e1fe3e4aSElliott Hughes    (50.0, 99.5)
415*e1fe3e4aSElliott Hughes    >>> intRect((0.9, 2.9, 3.1, 4.1))
416*e1fe3e4aSElliott Hughes    (0, 2, 4, 5)
417*e1fe3e4aSElliott Hughes    """
418*e1fe3e4aSElliott Hughes
419*e1fe3e4aSElliott Hughes
420*e1fe3e4aSElliott Hughesif __name__ == "__main__":
421*e1fe3e4aSElliott Hughes    import sys
422*e1fe3e4aSElliott Hughes    import doctest
423*e1fe3e4aSElliott Hughes
424*e1fe3e4aSElliott Hughes    sys.exit(doctest.testmod().failed)
425