ULP-ActivitySupport – blob

You can use Git to clone the repository via the web URL. Download snapshot (zip)
Take mobility path width requirements into account when routing
[ULP-ActivitySupport] / data.py
1 #!/usr/bin/env python3\r
2 \r
3 import json\r
4 import math\r
5 \r
6 \r
7 class Position:\r
8     def __init__(self, *, lat=None, lon=None, x=None, y=None):\r
9         if lat is not None and lon is not None:\r
10             self.lat = lat\r
11             self.lon = lon\r
12         if x is not None and y is not None:\r
13             self.x = x\r
14             self.y = y\r
15 \r
16     def __str__(self):\r
17         if hasattr(self, 'lat'):\r
18             return "(%f, %f)" % (self.lat, self.lon)\r
19         if hasattr(self, 'x'):\r
20             return "(%f, %f)" % (self.x, self.y)\r
21         return "(None)"\r
22 \r
23     def difference_to(self, goal):\r
24         if hasattr(self, 'lat'):\r
25             return (goal.lat - self.lat, goal.lon - self.lon)\r
26         if hasattr(self, 'x'):\r
27             return (goal.x - self.x, goal.y - self.y)\r
28         return None\r
29 \r
30     def distance(self, goal):\r
31         rel = self.difference_to(goal)\r
32         return math.sqrt(rel[0] ** 2 + rel[1] ** 2)\r
33 \r
34     def move_by(self, vector):\r
35         if hasattr(self, 'lat'):\r
36             self.lat += vector[0]\r
37             self.lon += vector[1]\r
38         if hasattr(self, 'x'):\r
39             self.x += vector[0]\r
40             self.y += vector[1]\r
41 \r
42     def toJSON(self):\r
43         if hasattr(self, 'lat'):\r
44             return {\r
45                 'lat': self.lat,\r
46                 'lon': self.lon,\r
47             }\r
48         if hasattr(self, 'x'):\r
49             return {\r
50                 'x': self.x,\r
51                 'y': self.y,\r
52             }\r
53         return {}\r
54 \r
55 \r
56 class QuestRequirement:\r
57     def __init__(self, req_type):\r
58         self.type = req_type\r
59         if self.type == 'set' or self.type == 'list':\r
60             self.parts = []\r
61             self.minimum = None\r
62             self.ordered = self.type == 'list'\r
63         if self.type == 'position':\r
64             self.position = None\r
65         if self.type == 'suo_proximity':\r
66             self.suo = None\r
67         self.fulfilled = False\r
68 \r
69     def get_active_requirements(self):\r
70         if self.fulfilled:\r
71             return None\r
72         active_requirements = []\r
73         if self.type not in ['set', 'list']:\r
74             active_requirements.append(self)\r
75         else:\r
76             for part in self.parts:\r
77                 if part.is_fulfilled():\r
78                     continue\r
79                 else:\r
80                     active_requirements.extend(part.get_active_requirements())\r
81                     if self.ordered:\r
82                         break\r
83         return active_requirements\r
84 \r
85     def is_fulfilled(self):\r
86         if self.fulfilled:\r
87             return True\r
88         if self.type in ['set', 'list']:\r
89             fulfilled_parts = 0\r
90             for part in self.parts:\r
91                 if part.is_fulfilled():\r
92                     fulfilled_parts += 1\r
93             minimum = self.minimum\r
94             if minimum is None:\r
95                 minimum = len(self.parts)\r
96             if fulfilled_parts >= minimum:\r
97                 self.fulfilled = True\r
98                 return True\r
99         return False\r
100 \r
101     def from_json(self, req_json):\r
102         data = json.loads(req_json)\r
103         for key in data:\r
104             if key == 'parts':\r
105                 self.parts = []\r
106                 for part in data['parts']:\r
107                     part_json = json.dumps(part)\r
108                     new_req = QuestRequirement(part['type'])\r
109                     new_req.from_json(part_json)\r
110                     self.parts.append(new_req)\r
111             else:\r
112                 setattr(self, key, data[key])\r
113 \r
114 \r
115 class Quest:\r
116     def __init__(self, qid = None):\r
117         self.qid = qid\r
118         self.title = None\r
119         self.requirement = None\r
120         self.rewards = None\r
121         self.user = None\r
122 \r
123 \r
124 class Intent:\r
125     def __init__(self, intent_id, position):\r
126         self.id = intent_id\r
127         self.position = position\r
128 \r
129     def toJSON(self):\r
130         return {\r
131             'id': self.id,\r
132             'position': self.position,\r
133         }\r
134 \r
135 \r
136 class User:\r
137     def __init__(self, user_id, name):\r
138         self.id = user_id\r
139         self.name = name\r
140         self.position = None\r
141         self.rotation = 0\r
142         self.color_preference = None\r
143         self.is_virtual = False\r
144         self.intent = {}\r
145         self.mobility = None\r
146 \r
147     def __str__(self):\r
148         return str(self.name) + ": " + str(self.position)\r
149 \r
150     def __repr__(self):\r
151         return "<" + self.__str__() + ">"\r
152 \r
153     def toJSON(self):\r
154         return {\r
155             'id': self.id,\r
156             'name': self.name,\r
157             'position': self.position,\r
158             'rotation': self.rotation,\r
159             'intent': self.intent,\r
160             'color_preference': self.color_preference,\r
161             'mobility': self.mobility,\r
162             'is_virtual': self.is_virtual,\r
163         }\r
164 \r
165     def set_position(self, position):\r
166         self.position = position\r
167 \r
168     def set_rotation(self, rotation):\r
169         self.rotation = rotation\r
170 \r
171     def add_intent(self, intent):\r
172         self.intent[intent.id] = intent\r
173 \r
174 \r
175 class SmartUrbanObject:\r
176     def __init__(self, suo_id, suo_type = None):\r
177         self.id = suo_id\r
178         self.suo_type = suo_type\r
179         self.position = None\r
180         self.rotation = 0\r
181         self.is_virtual = False\r
182 \r
183     def __str__(self):\r
184         return str(self.id) + ": " + str(self.suo_type) + ", " + str(self.position)\r
185 \r
186     def __repr__(self):\r
187         return "<" + self.__str__() + ">"\r
188 \r
189     def toJSON(self):\r
190         return {\r
191             'id': self.id,\r
192             'position': self.position,\r
193             'rotation': self.rotation,\r
194             'suo_type': self.suo_type,\r
195             'range': self.get_range(),\r
196             'is_virtual': self.is_virtual,\r
197         }\r
198 \r
199     def set_position(self, position):\r
200         self.position = position\r
201 \r
202     def set_rotation(self, rotation):\r
203         self.rotation = rotation\r
204 \r
205     def get_range(self):\r
206         return 4\r
207 \r
208     def is_user_in_range(self, user):\r
209         return user.position.distance(self.position) <= self.get_range()\r
210 \r
211 \r
212 class Context:\r
213     def __init__(self, context_id, name = None):\r
214         self.id = context_id\r
215         self.name = name\r
216         self.user = {}\r
217         self.suo = {}\r
218         self.boundaries = {}\r
219 \r
220     def toJSON(self):\r
221         result = {\r
222             'id': self.id,\r
223             'name': self.name,\r
224             'user': self.user,\r
225             'suo': self.suo,\r
226         }\r
227         if 'width' in self.boundaries and 'height' in self.boundaries:\r
228             result['boundaries'] = self.boundaries\r
229         return result;\r
230 \r
231     def add_user(self, user):\r
232         self.user[user.id] = user\r
233 \r
234     def add_suo(self, suo):\r
235         self.suo[suo.id] = suo\r
236 \r
237     def set_boundaries(self, width, height):\r
238         self.boundaries['width'] = width\r
239         self.boundaries['height'] = height\r
240 \r