You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

77 lines
2.5 KiB

  1. """a handful of utility functions used by GlitterPOS."""
  2. import math
  3. import time
  4. # https://gist.githubusercontent.com/jeromer/2005586/raw/5456a9386acce189ac6cc416c42e9c4b560a633b/compassbearing.py
  5. def compass_bearing(pointA, pointB):
  6. """
  7. Calculates the bearing between two points.
  8. The formulae used is the following:
  9. θ = atan2(sin(Δlong).cos(lat2),
  10. cos(lat1).sin(lat2) sin(lat1).cos(lat2).cos(Δlong))
  11. :Parameters:
  12. - `pointA: The tuple representing the latitude/longitude for the
  13. first point. Latitude and longitude must be in decimal degrees
  14. - `pointB: The tuple representing the latitude/longitude for the
  15. second point. Latitude and longitude must be in decimal degrees
  16. :Returns:
  17. The bearing in degrees
  18. :Returns Type:
  19. float
  20. """
  21. if (type(pointA) != tuple) or (type(pointB) != tuple):
  22. raise TypeError("Only tuples are supported as arguments")
  23. lat1 = math.radians(pointA[0])
  24. lat2 = math.radians(pointB[0])
  25. diffLong = math.radians(pointB[1] - pointA[1])
  26. x = math.sin(diffLong) * math.cos(lat2)
  27. y = math.cos(lat1) * math.sin(lat2) - (math.sin(lat1)
  28. * math.cos(lat2) * math.cos(diffLong))
  29. initial_bearing = math.atan2(x, y)
  30. # Now we have the initial bearing but math.atan2 return values
  31. # from -180° to + 180° which is not what we want for a compass bearing
  32. # The solution is to normalize the initial bearing as shown below
  33. initial_bearing = math.degrees(initial_bearing)
  34. compass_bearing = (initial_bearing + 360) % 360
  35. return compass_bearing
  36. def bearing_to_pixel(bearing, count=16):
  37. # Subtract from count since the neopixel ring runs counterclockwise:
  38. pixel = count - int(round((bearing / 360) * count))
  39. if pixel == count:
  40. return 0
  41. return pixel
  42. def map_range(x, in_min, in_max, out_min, out_max):
  43. """
  44. Maps a number from one range to another.
  45. :return: Returns value mapped to new range
  46. :rtype: float
  47. """
  48. mapped = (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
  49. if out_min <= out_max:
  50. return max(min(mapped, out_max), out_min)
  51. return min(max(mapped, out_max), out_min)
  52. def timestamp():
  53. """print a human-readable timestamp"""
  54. timestamp = time.localtime()
  55. return '{}/{}/{} {:02}:{:02}:{:02}'.format(
  56. timestamp.tm_year,
  57. timestamp.tm_mon,
  58. timestamp.tm_mday,
  59. timestamp.tm_hour,
  60. timestamp.tm_min,
  61. timestamp.tm_sec
  62. )