Kaynağa Gözat

matrix for visibility

Bastien Sevajol 6 yıl önce
ebeveyn
işleme
9e4ba469b2
4 değiştirilmiş dosya ile 167 ekleme ve 1 silme
  1. 28 1
      synergine2_xyz/physics.py
  2. 61 0
      synergine2_xyz/utils.py
  3. 48 0
      tests/test_physics.py
  4. 30 0
      tests/test_share.py

+ 28 - 1
synergine2_xyz/physics.py Dosyayı Görüntüle

@@ -5,6 +5,7 @@ from dijkstar import Graph
5 5
 from dijkstar import find_path
6 6
 
7 7
 from synergine2.config import Config
8
+from synergine2.share import shared
8 9
 from synergine2_xyz.map import TMXMap, XYZTile
9 10
 from synergine2_xyz.subjects import XYZSubject
10 11
 from synergine2_xyz.xyz import get_neighbor_positions
@@ -34,7 +35,32 @@ class MoveCostComputer(object):
34 35
         return 1.0
35 36
 
36 37
 
38
+class VisibilityMatrix(object):
39
+    _matrixes = shared.create('matrixes', value=lambda: {})  # type: typing.Dict[str, typing.Dict[float, typing.List[typing.List[float]]]]  # nopep8
40
+
41
+    def initialize_empty_matrix(self, name: str, height: float, matrix_width: int, matrix_height: int) -> None:
42
+        self._matrixes[name] = {}
43
+        self._matrixes[name][height] = []
44
+
45
+        for y in range(matrix_height):
46
+            x_list = []
47
+            for x in range(matrix_width):
48
+                x_list.append(0.0)
49
+            self._matrixes[name][height].append(x_list)
50
+
51
+    def get_matrix(self, name: str, height: float) -> typing.List[typing.List[float]]:
52
+        return self._matrixes[name][height]
53
+
54
+    def update_matrix(self, name: str, height: float, x: int, y: int, value: float) -> None:
55
+        matrix = self.get_matrix(name, height)
56
+        matrix[y][x] = value
57
+        # TODO: Test if working and needed ? This is not perf friendly ...
58
+        # Force shared data update
59
+        self._matrixes = dict(self._matrixes)
60
+
61
+
37 62
 class Physics(object):
63
+    visibility_matrix = VisibilityMatrix
38 64
     move_cost_computer_class = MoveCostComputer
39 65
 
40 66
     def __init__(
@@ -42,7 +68,8 @@ class Physics(object):
42 68
         config: Config,
43 69
     ) -> None:
44 70
         self.config = config
45
-        self.graph = Graph()
71
+        self.graph = Graph()  # Graph of possible movements for dijkstar algorithm lib
72
+        self.visibility_matrix = self.visibility_matrix()
46 73
         self.move_cost_computer = self.move_cost_computer_class(config)
47 74
 
48 75
     def load(self) -> None:

+ 61 - 0
synergine2_xyz/utils.py Dosyayı Görüntüle

@@ -228,3 +228,64 @@ def get_angle(a: typing.Tuple[int, int], b: typing.Tuple[int, int]) -> int:
228 228
     ang2 = numpy.arctan2(*b[::-1])
229 229
 
230 230
     return numpy.rad2deg((ang1 - ang2) % (2 * numpy.pi))
231
+
232
+
233
+def get_line_xy_path(start, end):
234
+    """
235
+    TODO: copied from http://www.roguebasin.com/index.php?title=Bresenham%27s_Line_Algorithm#Python
236
+    What is the licence ?
237
+    Bresenham's Line Algorithm
238
+    Produces a list of tuples from start and end
239
+
240
+    >>> points1 = get_line((0, 0), (3, 4))
241
+    >>> points2 = get_line((3, 4), (0, 0))
242
+    >>> assert(set(points1) == set(points2))
243
+    >>> print points1
244
+    [(0, 0), (1, 1), (1, 2), (2, 3), (3, 4)]
245
+    >>> print points2
246
+    [(3, 4), (2, 3), (1, 2), (1, 1), (0, 0)]
247
+    """
248
+    # Setup initial conditions
249
+    x1, y1 = start
250
+    x2, y2 = end
251
+    dx = x2 - x1
252
+    dy = y2 - y1
253
+
254
+    # Determine how steep the line is
255
+    is_steep = abs(dy) > abs(dx)
256
+
257
+    # Rotate line
258
+    if is_steep:
259
+        x1, y1 = y1, x1
260
+        x2, y2 = y2, x2
261
+
262
+    # Swap start and end points if necessary and store swap state
263
+    swapped = False
264
+    if x1 > x2:
265
+        x1, x2 = x2, x1
266
+        y1, y2 = y2, y1
267
+        swapped = True
268
+
269
+    # Recalculate differentials
270
+    dx = x2 - x1
271
+    dy = y2 - y1
272
+
273
+    # Calculate error
274
+    error = int(dx / 2.0)
275
+    ystep = 1 if y1 < y2 else -1
276
+
277
+    # Iterate over bounding box generating points between start and end
278
+    y = y1
279
+    points = []
280
+    for x in range(x1, x2 + 1):
281
+        coord = (y, x) if is_steep else (x, y)
282
+        points.append(coord)
283
+        error -= abs(dy)
284
+        if error < 0:
285
+            y += ystep
286
+            error += dx
287
+
288
+    # Reverse the list if the coordinates were swapped
289
+    if swapped:
290
+        points.reverse()
291
+    return points

+ 48 - 0
tests/test_physics.py Dosyayı Görüntüle

@@ -0,0 +1,48 @@
1
+# coding: utf-8
2
+import pytest
3
+
4
+from synergine2_xyz.physics import VisibilityMatrix
5
+from tests import BaseTest
6
+
7
+
8
+class TestVisibilityMatrix(BaseTest):
9
+    def test_initialize_empty_matrix(self):
10
+        visibility = VisibilityMatrix()
11
+        visibility.initialize_empty_matrix('testing', height=0.5, matrix_width=3, matrix_height=2)
12
+        matrix = visibility.get_matrix('testing', height=0.5)
13
+
14
+        assert isinstance(matrix, list)
15
+
16
+        assert [0.0, 0.0, 0.0] == matrix[0]
17
+        assert [0.0, 0.0, 0.0] == matrix[1]
18
+
19
+    def test_update_matrix(self):
20
+        visibility = VisibilityMatrix()
21
+        visibility.initialize_empty_matrix('testing', height=0.5, matrix_width=3, matrix_height=2)
22
+        visibility.update_matrix('testing', height=0.5, x=2, y=1, value=0.5)
23
+        visibility.update_matrix('testing', height=0.5, x=0, y=0, value=0.7)
24
+        matrix = visibility.get_matrix('testing', height=0.5)
25
+
26
+        assert [0.7, 0.0, 0.0] == matrix[0]
27
+        assert [0.0, 0.0, 0.5] == matrix[1]
28
+
29
+    @pytest.mark.skip(reason='Not implemented yet')
30
+    def test_get_path_positions(self):
31
+        visibility = VisibilityMatrix()
32
+        visibility.initialize_empty_matrix('testing', height=0.5, matrix_width=3, matrix_height=2)
33
+        visibility.update_matrix('testing', height=0.5, x=2, y=1, value=0.5)
34
+        visibility.update_matrix('testing', height=0.5, x=0, y=0, value=0.7)
35
+
36
+        path_positions = visibility.get_path_positions(from_=(0, 0), to=(2, 1))
37
+        assert [(0, 0), (0, 1), (1, 2)] == path_positions
38
+
39
+    @pytest.mark.skip(reason='Not implemented yet')
40
+    def test_get_path_values(self):
41
+        visibility = VisibilityMatrix()
42
+        visibility.initialize_empty_matrix('testing', height=0.5, matrix_width=3, matrix_height=2)
43
+        visibility.update_matrix('testing', height=0.5, x=2, y=1, value=0.5)
44
+        visibility.update_matrix('testing', height=0.5, x=0, y=0, value=0.7)
45
+
46
+        path_positions = visibility.get_path_positions(from_=(0, 0), to=(2, 1))
47
+        path_values = visibility.get_values_for_path(path_positions=path_positions)
48
+        assert [0.7, 0.0, 0.5] == path_values

+ 30 - 0
tests/test_share.py Dosyayı Görüntüle

@@ -228,6 +228,36 @@ class TestShare(BaseTest):
228 228
         # In this case local data is used
229 229
         assert shared.get('data') == {'foo': 'buz'}
230 230
 
231
+    def test_update_dict_in_dict_with_pointer(self):
232
+        shared = share.SharedDataManager()
233
+
234
+        class Foo(IdentifiedObject):
235
+            data = shared.create_self('data', lambda: {})
236
+
237
+        foo = Foo()
238
+        foo.data = {'foo': {'bar': 'baz'}}
239
+
240
+        assert foo.data == {'foo': {'bar': 'baz'}}
241
+
242
+        foo.data['foo'] = {'bar': 'baz'}
243
+        # In this case local data is used
244
+        assert foo.data == {'foo': {'bar': 'baz'}}
245
+
246
+        shared.commit()
247
+        shared.purge_data()
248
+
249
+        # In this case, "data" key was pending and has been commit
250
+        assert foo.data == {'foo': {'bar': 'baz'}}
251
+
252
+        # In this case "data" key was NOT pending and has not been commit
253
+        foo.data['foo']['bar'] = 'biz'
254
+        foo.data = dict(foo.data)
255
+
256
+        shared.commit()
257
+        shared.purge_data()
258
+
259
+        assert foo.data == {'foo': {'bar': 'biz'}}
260
+
231 261
 
232 262
 class TestIndexes(BaseTest):
233 263
     def test_list_index(self):