utils.py 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. # coding: utf-8
  2. import collections
  3. from math import sqrt
  4. from synergine2_xyz.xyz import DIRECTION_MODIFIERS
  5. def get_positions_from_str_representation(str_representation):
  6. # TODO: Manage z axis (like ------------ as separator)
  7. lines = str_representation.split("\n") # One item per lines
  8. lines = map(lambda l: l.strip().replace(' ', ''), lines) # Remove spaces
  9. lines = filter(lambda l: bool(l), lines) # Only line with content
  10. lines = list(lines)
  11. width = len(lines[0])
  12. height = len(lines)
  13. if not width % 2 or not height % 2:
  14. raise Exception(
  15. 'Width and height of your representation must be odd. '
  16. 'Actually it\'s {0}x{1}'.format(
  17. width,
  18. height,
  19. ))
  20. items_positions = collections.defaultdict(list)
  21. start_x = - int(width / 2 - 0.5)
  22. start_y = - int(height / 2 - 0.5)
  23. start_z = 0
  24. current_y = start_y
  25. current_z = start_z
  26. for line in lines:
  27. current_x = start_x
  28. for char in line:
  29. items_positions[char].append((
  30. current_x,
  31. current_y,
  32. current_z,
  33. ))
  34. current_x += 1
  35. current_y += 1
  36. return items_positions
  37. def get_min_and_max(positions) -> (int, int, int, int, int):
  38. max_x_position = max(positions, key=lambda p: p[0])
  39. min_x_position = min(positions, key=lambda p: p[0])
  40. max_y_position = max(positions, key=lambda p: p[1])
  41. min_y_position = min(positions, key=lambda p: p[1])
  42. max_z_position = max(positions, key=lambda p: p[2])
  43. min_z_position = min(positions, key=lambda p: p[2])
  44. max_x = max_x_position[0]
  45. min_x = min_x_position[0]
  46. max_y = max_y_position[1]
  47. min_y = min_y_position[1]
  48. max_z = max_z_position[2]
  49. min_z = min_z_position[2]
  50. return min_x, max_x, min_y, max_y, min_z, max_z
  51. def get_str_representation_from_positions(
  52. items_positions: dict,
  53. separator='',
  54. tabulation='',
  55. start_with='',
  56. end_with='',
  57. force_items_as=None,
  58. force_positions_as=None,
  59. complete_lines_with=' ',
  60. ) -> str:
  61. positions = []
  62. for item_positions in items_positions.values():
  63. positions.extend(item_positions)
  64. positions = sorted(positions, key=lambda p: (p[2], p[1], p[0]))
  65. if complete_lines_with is not None:
  66. min_x, max_x, min_y, max_y, min_z, max_z = get_min_and_max(positions)
  67. all_ = []
  68. for x in range(min_x, max_x+1):
  69. for y in range(min_y, max_y+1):
  70. for z in range(min_z, max_z+1):
  71. all_.append((x, y, z))
  72. pass
  73. for one_of_all in all_:
  74. if one_of_all not in positions:
  75. if complete_lines_with not in items_positions:
  76. items_positions[complete_lines_with] = []
  77. items_positions[complete_lines_with].append(one_of_all)
  78. positions = []
  79. for item_positions in items_positions.values():
  80. positions.extend(item_positions)
  81. positions = sorted(positions, key=lambda p: (p[2], p[1], p[0]))
  82. str_representation = start_with + tabulation
  83. start_x = positions[0][0]
  84. start_y = positions[0][1]
  85. start_z = positions[0][2]
  86. current_y = start_y
  87. current_z = start_z
  88. for position in positions:
  89. item = None
  90. for parsed_item in items_positions:
  91. if position in items_positions[parsed_item]:
  92. item = parsed_item
  93. break
  94. if position[1] != current_y:
  95. str_representation += "\n" + tabulation
  96. if position[2] != current_z:
  97. str_representation += '----' + "\n" + tabulation
  98. str_item = item
  99. if force_items_as:
  100. for force_item_as in force_items_as:
  101. if force_item_as[0] == item:
  102. str_item = force_item_as[1]
  103. break
  104. if force_positions_as:
  105. for force_position_as in force_positions_as:
  106. if position == force_position_as[0]:
  107. str_item = force_position_as[1]
  108. break
  109. added_value = str_item
  110. if position[0] != start_x:
  111. added_value = separator + added_value
  112. str_representation += added_value
  113. current_y = position[1]
  114. current_z = position[2]
  115. return str_representation + end_with
  116. def get_around_positions_of_positions(position, exclude_start_position=True) -> list:
  117. """
  118. TODO: compute with z (allow or disable with parameter)
  119. Return positions around a point with distance of 1.
  120. :param position: (x, y, z) tuple
  121. :param exclude_start_position: if True, given position will not be
  122. added to result list
  123. :return: list of (x, y, z) positions
  124. :rtype: list
  125. """
  126. pz = position[2]
  127. px = position[0]
  128. py = position[1]
  129. points = [
  130. (px-1, py-1, pz),
  131. (px, py-1, pz),
  132. (px+1, py+1, pz),
  133. (px-1, py , pz),
  134. (px+1, py , pz),
  135. (px-1, py+1, pz),
  136. (px, py+1, pz),
  137. (px+1, py-1, pz)
  138. ]
  139. if not exclude_start_position:
  140. points.append(position)
  141. return points
  142. def get_around_positions_of(
  143. position,
  144. distance=1,
  145. exclude_start_point=True,
  146. ) -> list:
  147. """
  148. Return positions around a point.
  149. :param position: (x, y, z) tuple
  150. :param distance: Distance to compute
  151. :return: list of (x, y, z) positions
  152. """
  153. start_x = position[0] - distance
  154. start_y = position[1] - distance
  155. # start_z = position[0] - distance
  156. positions = []
  157. range_distance = (distance * 2) + 1
  158. for dx in range(range_distance):
  159. for dy in range(range_distance):
  160. # for dz in range(range_distance):
  161. # points.append((start_z+dz, start_x+dx, start_y+dy))
  162. positions.append((start_x + dx, start_y + dy, position[2]))
  163. if exclude_start_point:
  164. positions.remove(position)
  165. return positions
  166. def get_distance_between_points(a: tuple, b: tuple) -> float:
  167. return abs(sqrt((b[0] - a[0]) ** 2 + (b[1] - a[1]) ** 2))
  168. def get_position_for_direction(from_position: tuple, direction: int) -> tuple:
  169. modifier = DIRECTION_MODIFIERS[direction]
  170. return (
  171. from_position[0] + modifier[0],
  172. from_position[1] + modifier[1],
  173. from_position[2] + modifier[2],
  174. )