xyz.py 2.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. from math import sqrt
  2. from math import degrees
  3. from math import acos
  4. from synergine2.simulation import Mechanism
  5. from synergine2.simulation import Simulation as BaseSimulation
  6. """
  7. Positions are exprimed as tuple: (x, y, z) Considering start point at top left:
  8. Z
  9. #
  10. #
  11. #
  12. #-------------> X
  13. |.
  14. | .
  15. | .
  16. |
  17. Y
  18. """
  19. COLLECTION_XYZ = 'COLLECTION_XYZ'
  20. def get_distance_between_points(a: tuple, b: tuple) -> float:
  21. return abs(sqrt((b[0] - a[0]) ** 2 + (b[1] - a[1]) ** 2))
  22. def get_degree_from_north(a, b):
  23. if a == b:
  24. return 0
  25. ax, ay = a[0], a[1]
  26. bx, by = b[0], b[1]
  27. Dx, Dy = ax, ay - 1
  28. ab = sqrt((bx - ax) ** 2 + (by - ay) ** 2)
  29. aD = sqrt((Dx - ax) ** 2 + (Dy - ay) ** 2)
  30. Db = sqrt((bx - Dx) ** 2 + (by - Dy) ** 2)
  31. degs = degrees(acos((ab ** 2 + aD ** 2 - Db ** 2) / (2 * ab * aD)))
  32. if bx < ax:
  33. return 360 - degs
  34. return degs
  35. class XYZSubjectMixinMetaClass(type):
  36. def __init__(cls, name, parents, attribs):
  37. super().__init__(name, parents, attribs)
  38. collections = getattr(cls, "collections", [])
  39. if COLLECTION_XYZ not in collections:
  40. collections.append(COLLECTION_XYZ)
  41. class XYZSubjectMixin(object, metaclass=XYZSubjectMixinMetaClass):
  42. def __init__(self, *args, **kwargs):
  43. """
  44. :param position: tuple with (x, y, z)
  45. """
  46. self.position = kwargs.pop('position')
  47. super().__init__(*args, **kwargs)
  48. class ProximityMechanism(Mechanism):
  49. distance = 1
  50. feel_collections = [COLLECTION_XYZ]
  51. direction_round_decimals = 0
  52. distance_round_decimals = 2
  53. def run(self):
  54. subjects = []
  55. for feel_collection in self.feel_collections:
  56. for subject in self.simulation.collections.get(feel_collection, []):
  57. if subject == self.subject:
  58. continue
  59. distance = round(
  60. self.get_distance_of(subject),
  61. self.distance_round_decimals,
  62. )
  63. if subject != self.subject and distance <= self.distance:
  64. direction = round(
  65. get_degree_from_north(
  66. self.subject.position,
  67. subject.position,
  68. ),
  69. self.direction_round_decimals,
  70. )
  71. subjects.append({
  72. 'subject': subject,
  73. 'direction': direction,
  74. 'distance': distance,
  75. })
  76. return subjects
  77. def get_distance_of(self, subject: XYZSubjectMixin):
  78. return get_distance_between_points(
  79. self.subject.position,
  80. subject.position,
  81. )
  82. class Simulation(BaseSimulation):
  83. """
  84. TODO: xyz properties
  85. """
  86. pass