Grid.py 6.35 KB
Newer Older
Karol Actun's avatar
Karol Actun committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from abc import ABC, abstractmethod


class Grid(ABC):

    @property
    @abstractmethod
    def size(self):
        pass

    @property
    @abstractmethod
    def directions(self):
        pass

    @abstractmethod
17
    def are_valid_coordinates(self, coordinates):
Karol Actun's avatar
Karol Actun committed
18
        """
19
20
21
        checks if given coordinates are valid for this grid
        :param coordinates: (float, float, float)
        :return: true = coordinates are valid, false = coordinates invalid
Karol Actun's avatar
Karol Actun committed
22
23
24
25
        """
        pass

    @abstractmethod
26
    def get_nearest_valid_coordinates(self, coordinates):
Karol Actun's avatar
Karol Actun committed
27
        """
28
        calculates the nearest valid coordinates to given coordinates
Karol Actun's avatar
Karol Actun committed
29
        :param coordinates: (float, float, float)
30
        :return: valid coordinates
Karol Actun's avatar
Karol Actun committed
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
        """
        pass

    def get_directions_dictionary(self):
        """
        returns a dictionary of the directions, with direction names (string) as keys
        and the direction vectors (3d tuple) as values
        :return: dictionary with  - 'string: (float, float,float)'
        """
        return self.directions

    def get_directions_list(self):
        """
        returns a list of the direction vectors
        :return: list of 3d tuples - '(float, float, float)'
        """
        return list(self.directions.values())

    def get_directions_names(self):
        """
        returns a list of direction names
        :return: list of strings
        """
        return list(self.directions.keys())

    def get_lines(self):
        """
        FOR VISUALIZATION!
        calculates line data in this grids directions for the visualization.
        output is a list of start and end points. the start point is always the center of this grid and the end points
        are the directions but only half in length
        :return: list of vectors, [(sx,sy,sz), (ex,ey,ez), (sx,sy,sz), (ea,eb,ec), ...]
        """
        lines = []
        for d in self.get_directions_list():
            lines.append(self.get_center())
            hd = (d[0] * 0.5, d[1] * 0.5, d[2] * 0.5)
            lines.append(hd)
        return lines

    @abstractmethod
    def get_box(self, width):
        """
74
        calculates all valid coordinates in a box
Karol Actun's avatar
Karol Actun committed
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
        :return: list of 3d coordinates: [(x_start_l0, y_start_l0), (x_end_l0, y_end_l0), (x_start_l1, y_start_l1), ...)
        """
        pass

    @abstractmethod
    def get_dimension_count(self):
        """
        returns the amount of dimensions
        :return: integer, amount of dimensions (3 or 2 presumably)
        """
        pass

    @abstractmethod
    def get_distance(self, start, end):
        """
        the metric or distance function for this grid
91
92
        :param start: coordinates, (float, float, float) tuple, start of path
        :param end: coordinates, (float, float, float) tuple, end of path
Karol Actun's avatar
Karol Actun committed
93
94
95
96
97
        :return: integer, minimal amount of steps between start and end
        """
        pass

    @staticmethod
98
    def get_coordinates_in_direction(position, direction):
Karol Actun's avatar
Karol Actun committed
99
100
        """
        calculates a new position from current position and direction
101
102
103
        :param position: coordinates, (float, float, float) tuple, current position
        :param direction: coordinates, (float, float, float) tuple, direction
        :return: coordinates, (float, float, float) tuple, new position
Karol Actun's avatar
Karol Actun committed
104
105
106
107
108
109
110
111
112
        """
        new_pos = []
        for i in range(len(position)):
            new_pos.append(position[i]+direction[i])
        return tuple(new_pos)

    def get_center(self):
        """
        returns the center of the grid. usually (0,0,0)
113
        :return: coordinates, (float, float, float) tuple
Karol Actun's avatar
Karol Actun committed
114
115
116
117
118
119
120
121
122
123
        """
        return 0.0, 0.0, 0.0

    def get_scaling(self):
        """
        returns the x,y,z scaling for the visualization. usually (1,1,1) = no scaling
        :return: x,y,z scaling values: float, float, float
        """
        return 1.0, 1.0, 1.0

124
    def get_adjacent_coordinates(self, coordinates):
Karol Actun's avatar
Karol Actun committed
125
        """
126
127
128
        calculates a set of adjacent coordinates of the given coordinates
        :param coordinates: the coordinates of which the neighboring coordinates should be calculated
        :return: a set of coordinates
Karol Actun's avatar
Karol Actun committed
129
130
131
        """
        n = set()
        for d in self.get_directions_list():
132
            n.add(self.get_coordinates_in_direction(coordinates, d))
Karol Actun's avatar
Karol Actun committed
133
134
        return n

135
    def _get_adjacent_coordinates_not_in_set(self, coordinates, not_in_set):
Karol Actun's avatar
Karol Actun committed
136
        """
137
138
139
140
        the same as 'get_neighboring_coordinates', but doesn't return coordinates which are in the given 'not_in_set'.
        :param coordinates: the coordinates of which the neighboring coordinates should be calculated
        :param not_in_set: set of coordinates, which should not be included in the result
        :return: a set of coordinates
Karol Actun's avatar
Karol Actun committed
141
142
143
        """
        result = set()
        for d in self.get_directions_list():
144
            n = self.get_coordinates_in_direction(coordinates, d)
Karol Actun's avatar
Karol Actun committed
145
146
147
148
            if n not in not_in_set:
                result.add(n)
        return result

149
    def get_n_sphere(self, coordinates, radius):
Karol Actun's avatar
Karol Actun committed
150
151
        """
        calculates the n-sphere of this grid
152
        :param coordinates: center of the circle/sphere
Karol Actun's avatar
Karol Actun committed
153
        :param radius: radius of the circle/sphere
154
        :return: set of coordinates
Karol Actun's avatar
Karol Actun committed
155
156
        """
        result = set()
157
        ns = self.get_adjacent_coordinates(coordinates)
Karol Actun's avatar
Karol Actun committed
158
159
160
161
162
163
        current_ns = ns
        result.update(ns)

        for i in range(radius):
            tmp = set()
            for n in current_ns:
164
                ns = self._get_adjacent_coordinates_not_in_set(n, result)
Karol Actun's avatar
Karol Actun committed
165
166
167
168
169
170
                tmp.update(ns)
                result.update(ns)
            current_ns = tmp

        return result

171
    def get_n_sphere_border(self, coordinates, radius):
Karol Actun's avatar
Karol Actun committed
172
173
        """
        calculates the border of an n-sphere around the center with the given radius
174
        :param coordinates: center of the ring
Karol Actun's avatar
Karol Actun committed
175
        :param radius: radius of the ring
176
        :return: set of coordinates
Karol Actun's avatar
Karol Actun committed
177
178
179
        """
        if radius == 0:
            r = set()
180
            r.add(coordinates)
Karol Actun's avatar
Karol Actun committed
181
182
183
            return r

        seen = set()
184
        ns = self.get_adjacent_coordinates(coordinates)
Karol Actun's avatar
Karol Actun committed
185
186
        current_ns = ns
        seen.update(ns)
187
        seen.add(coordinates)
Karol Actun's avatar
Karol Actun committed
188
189
190
191

        for i in range(radius-1):
            tmp = set()
            for n in current_ns:
192
                ns = self._get_adjacent_coordinates_not_in_set(n, seen)
Karol Actun's avatar
Karol Actun committed
193
194
195
196
197
                seen.update(ns)
                tmp.update(ns)
            current_ns = tmp

        return current_ns