draw.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #!/usr/bin/env python
  2. from __future__ import division
  3. import pygame
  4. import sys
  5. import time
  6. from threading import Thread
  7. from math import degrees, cos, sin
  8. from src.server import GestureServer
  9. from src.window import FullscreenWindow
  10. from src.trackers.transform import TransformationTracker
  11. from src.trackers.tap import TapTracker
  12. from src.screen import screen_size
  13. import tests.parse_arguments
  14. pygame.init()
  15. FULLSCREEN = '-f' in sys.argv[1:]
  16. # Config
  17. FINGER_RADIUS = 20
  18. CENTROID_RADIUS = 15
  19. W, H = screen_size if FULLSCREEN else (640, 480)
  20. BG_COLOR = 0, 0, 0
  21. LINE_COLOR = 128, 128, 128
  22. CIRCLE_COLOR = 255, 255, 255
  23. RECT_COLOR = 0, 200, 0
  24. RECT_POS = W / 2, H / 2
  25. RECT_SIZE = W / 6., H / 6.
  26. TAP_RADIUS = 65
  27. TAP_INCREMENT = .3
  28. BEAM_COLOR = 255, 50, 50
  29. BEAM_LENGTH = 50
  30. BEAM_WIDTH = 3
  31. BEAM_INCREMENT = .8
  32. MAX_SCALE = 10
  33. # Create canvas GUI
  34. flags = pygame.FULLSCREEN if FULLSCREEN else 0
  35. screen = pygame.display.set_mode((W, H), flags)
  36. def coord(x, y):
  37. w, h = screen_size
  38. return int(round(W / w * x)), int(round(H / h * y))
  39. # Global state
  40. angle = 0
  41. scale = 1
  42. taps = []
  43. dtaps = []
  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.centroid:
  57. c = coord(*transform.centroid.xy)
  58. for p in server.points.itervalues():
  59. xy = coord(p.x, p.y)
  60. # Draw line to centroid
  61. if 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.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), BEAM_WIDTH)
  90. # Update canvas
  91. pygame.display.flip()
  92. # Create server and fullscreen window
  93. server = GestureServer()
  94. win = FullscreenWindow(server=server)
  95. # Bind trackers
  96. def rotate(gesture):
  97. global angle
  98. angle += gesture.get_angle()
  99. def pinch(gesture):
  100. global scale
  101. scale = min(scale * gesture.get_scale(), MAX_SCALE)
  102. transform = TransformationTracker(win)
  103. transform.bind('rotate', rotate)
  104. transform.bind('pinch', pinch)
  105. tap = TapTracker(win)
  106. tap.bind('tap', lambda g: taps.append([coord(*g.xy), FINGER_RADIUS]))
  107. tap.bind('single_tap', lambda g: dtaps.append(list(coord(*g.xy)) + [1]))
  108. tap.bind('double_tap', lambda g: dtaps.append(list(coord(*g.xy)) + [0]))
  109. try:
  110. # Start touch gesture server in separate thread
  111. thread = Thread(target=server.start)
  112. thread.daemon = True
  113. thread.start()
  114. # Start GUI event loop
  115. def is_quit_event(e):
  116. return e.type == pygame.QUIT \
  117. or (e.type == pygame.KEYDOWN and e.key == ord('q'))
  118. while not any(filter(is_quit_event, pygame.event.get())):
  119. update()
  120. except KeyboardInterrupt:
  121. pass
  122. finally:
  123. server.stop()