utils.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. from __future__ import division
  2. from time import sleep
  3. from threading import Thread
  4. from numpy import array, diag, dot, cos, sin, asarray, column_stack, c_
  5. from src import RectangularArea
  6. class BoundingBoxArea(RectangularArea):
  7. def __init__(self, x, y, points):
  8. super(BoundingBoxArea, self).__init__(x, y, 0, 0)
  9. self.points = array(points).T
  10. self.update_bounds()
  11. def translate_points(self, tx, ty):
  12. self.points += [[tx], [ty]]
  13. def scale_points(self, scale, cx, cy):
  14. self.translate_points(-cx, -cy)
  15. self.points = dot(diag([scale, scale]), self.points)
  16. self.translate_points(cx, cy)
  17. def rotate_points(self, angle, cx, cy):
  18. cosa = cos(angle)
  19. sina = sin(angle)
  20. mat = array([[cosa, -sina], [sina, cosa]])
  21. self.translate_points(-cx, -cy)
  22. self.points = dot(mat, self.points)
  23. self.translate_points(cx, cy)
  24. def contains(self, x, y):
  25. ox, oy = self.get_position()
  26. return inside_shape((x - ox, y - oy), self.points)
  27. def update_bounds(self):
  28. min_x, min_y = self.points.min(1)
  29. max_x, max_y = self.points.max(1)
  30. self.set_size(max_x - min_x, max_y - min_y)
  31. if min_x or min_y:
  32. self.translate(min_x, min_y)
  33. self.translate_points(-min_x, -min_y)
  34. FLICK_UPDATE_RATE = 30
  35. class Flick(object):
  36. def __init__(self, callback, seconds, start_amount=1.0):
  37. self.callback = callback
  38. self.amount = start_amount
  39. self.iterations = int(seconds * FLICK_UPDATE_RATE)
  40. self.reduce_rate = start_amount / self.iterations
  41. def iteration(self):
  42. self.callback(self.amount)
  43. self.amount -= self.reduce_rate
  44. self.iterations -= 1
  45. return self.is_not_done()
  46. def is_not_done(self):
  47. return self.iterations > 0
  48. def is_done(self):
  49. return self.iterations <= 0
  50. class FlickThread(Thread):
  51. def __init__(self):
  52. super(FlickThread, self).__init__()
  53. self.flicks = []
  54. def run(self):
  55. while True:
  56. self.flicks = filter(Flick.iteration, self.flicks)
  57. sleep(1 / FLICK_UPDATE_RATE)
  58. def add(self, flick):
  59. self.flicks.append(flick)
  60. def inside_shape(p, verts):
  61. """Test whether the point p is inside the specified shape.
  62. The shape is specified by 'verts' and 'edges'
  63. Arguments:
  64. p - the 2d point
  65. verts - (N,2) array of points
  66. Returns:
  67. - True/False based on result of in/out test.
  68. Uses the 'ray to infinity' even-odd test.
  69. Let the ray be the horizontal ray starting at p and going to +inf in x.
  70. """
  71. x, y = p
  72. inside = False
  73. for i in range(-1, verts.shape[1] - 1):
  74. x0, y0 = verts[:,i]
  75. x1, y1 = verts[:,i + 1]
  76. # Check for horizontal line - another horz line can't intersect it
  77. # Check if both verts to the left, bottom or top of ray
  78. if (y0 == y1) or (x0 < x and x1 < x) or (y0 < y and y1 < y) \
  79. or (y0 > y and y1 > y):
  80. continue
  81. # Compute x intersection value
  82. xisect = x0 + (x1 - x0) * (y - y0) / (y1 - y0)
  83. print xisect, x
  84. if xisect >= x:
  85. inside = not inside
  86. return inside