draw.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #!/usr/bin/env python
  2. from __future__ import division
  3. import pygame
  4. from threading import Thread
  5. from math import degrees
  6. from tests.parse_arguments import create_parser, parse_args
  7. from src import FullscreenArea, create_driver
  8. from src.screen import screen_size
  9. # Parse arguments
  10. parser = create_parser()
  11. parser.add_argument('-f', '--fullscreen', action='store_true', default=False,
  12. help='run in fullscreen')
  13. args = parse_args(parser)
  14. pygame.init()
  15. # Config
  16. FINGER_RADIUS = 20
  17. CENTROID_RADIUS = 15
  18. W, H = screen_size if args.fullscreen else (640, 480)
  19. BG_COLOR = 0, 0, 0
  20. LINE_COLOR = 128, 128, 128
  21. CIRCLE_COLOR = 255, 255, 255
  22. RECT_COLOR = 0, 200, 0
  23. RECT_POS = W / 2, H / 2
  24. RECT_SIZE = W / 6., H / 6.
  25. TAP_RADIUS = 65
  26. TAP_INCREMENT = .3
  27. BEAM_COLOR = 255, 50, 50
  28. BEAM_LENGTH = 50
  29. BEAM_WIDTH = 3
  30. BEAM_INCREMENT = .8
  31. MAX_SCALE = 10
  32. # Create canvas GUI
  33. flags = pygame.FULLSCREEN if args.fullscreen else 0
  34. screen = pygame.display.set_mode((W, H), flags)
  35. def coord(x, y):
  36. w, h = screen_size
  37. return int(round(W / w * x)), int(round(H / h * y))
  38. # Global state
  39. angle = 0
  40. scale = 1
  41. taps = []
  42. dtaps = []
  43. points = []
  44. def update():
  45. global taps, dtaps
  46. # Clear previous frame
  47. screen.fill(BG_COLOR)
  48. # Apply scale and rotation to a fixed-size rectangle canvas
  49. canvas = pygame.Surface(RECT_SIZE)
  50. canvas.fill(RECT_COLOR)
  51. transformed = pygame.transform.rotozoom(canvas, degrees(angle), scale)
  52. rect = transformed.get_rect()
  53. rect.center = W / 2, H / 2
  54. screen.blit(transformed, rect)
  55. # Draw touch points
  56. if transform and transform.centroid:
  57. c = coord(*transform.centroid)
  58. for p in points:
  59. xy = coord(p.x, p.y)
  60. # Draw line to centroid
  61. if transform and transform.centroid:
  62. pygame.draw.line(screen, LINE_COLOR, xy, c, 1)
  63. # Draw outlined circle around touch point
  64. pygame.draw.circle(screen, CIRCLE_COLOR, xy, FINGER_RADIUS, 1)
  65. # Fill filled circle with background color within the outline
  66. pygame.draw.circle(screen, BG_COLOR, xy, FINGER_RADIUS - 1, 0)
  67. # Draw filled circle around centroid
  68. if transform and transform.centroid:
  69. pygame.draw.circle(screen, CIRCLE_COLOR, c, CENTROID_RADIUS)
  70. # Draw an expanding circle around each tap event
  71. taps = filter(lambda (xy, r): r <= TAP_RADIUS, taps)
  72. for tap in taps:
  73. xy, radius = tap
  74. pygame.draw.circle(screen, CIRCLE_COLOR, xy, int(radius), 2)
  75. # Increment radius
  76. tap[1] += TAP_INCREMENT
  77. # Shoot a beam from each double tap event to the left
  78. dtaps = filter(lambda (x, y, s): 0 <= x <= W, dtaps)
  79. for dtap in dtaps:
  80. x, y, single = dtap
  81. if single:
  82. start_x = x
  83. end_x = x + BEAM_LENGTH
  84. dtap[0] += BEAM_INCREMENT
  85. else:
  86. start_x = x - BEAM_LENGTH
  87. end_x = x
  88. dtap[0] -= BEAM_INCREMENT
  89. pygame.draw.line(screen, BEAM_COLOR, (start_x, y), (end_x, y),
  90. BEAM_WIDTH)
  91. # Update canvas
  92. pygame.display.flip()
  93. transform = None
  94. def save_tracker(gesture):
  95. global transform
  96. if not transform:
  97. transform = gesture.get_tracker()
  98. def rotate(gesture):
  99. global angle
  100. angle += gesture.get_angle()
  101. save_tracker(gesture)
  102. def pinch(gesture):
  103. global scale
  104. scale = min(scale * gesture.get_scale(), MAX_SCALE)
  105. save_tracker(gesture)
  106. area = FullscreenArea()
  107. driver = create_driver(area)
  108. area.on_rotate(rotate)
  109. area.on_pinch(pinch)
  110. area.on_tap(lambda g: taps.append([coord(*g), FINGER_RADIUS]))
  111. area.on_single_tap(lambda g: dtaps.append(list(coord(*g)) + [1]))
  112. area.on_double_tap(lambda g: dtaps.append(list(coord(*g)) + [0]))
  113. area.on_point_down(lambda g: points.append(g.get_event().point))
  114. area.on_point_up(lambda g: points.remove(g.get_event().point))
  115. try:
  116. # Start touch gesture server in separate thread
  117. thread = Thread(target=driver.start)
  118. thread.daemon = True
  119. thread.start()
  120. # Start GUI event loop
  121. def is_quit_event(e):
  122. return e.type == pygame.QUIT \
  123. or (e.type == pygame.KEYDOWN and e.key == ord('q'))
  124. while not any(filter(is_quit_event, pygame.event.get())):
  125. update()
  126. except KeyboardInterrupt:
  127. pass
  128. finally:
  129. driver.stop()