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