pycityagent 1.0.0__py3-none-any.whl → 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pycityagent/__init__.py +3 -1
- pycityagent/ac/__init__.py +3 -1
- pycityagent/ac/ac.py +56 -39
- pycityagent/ac/action.py +46 -5
- pycityagent/ac/action_stream.py +25 -0
- pycityagent/ac/citizen_actions/controled.py +16 -0
- pycityagent/ac/citizen_actions/converse.py +34 -0
- pycityagent/ac/citizen_actions/idle.py +20 -0
- pycityagent/ac/citizen_actions/shop.py +82 -0
- pycityagent/ac/citizen_actions/trip.py +41 -0
- pycityagent/ac/hub_actions.py +93 -0
- pycityagent/ac/sim_actions.py +80 -0
- pycityagent/agent.py +97 -143
- pycityagent/agent_citizen.py +158 -0
- pycityagent/agent_func.py +115 -0
- pycityagent/brain/__init__.py +1 -1
- pycityagent/brain/memory.py +200 -106
- pycityagent/brain/sence.py +358 -64
- pycityagent/cc/__init__.py +2 -2
- pycityagent/cc/cc.py +40 -36
- pycityagent/hubconnector/hubconnector.py +23 -31
- pycityagent/image/__init__.py +1 -1
- pycityagent/image/image.py +48 -44
- pycityagent/simulator.py +39 -39
- pycityagent/st/st.py +44 -7
- {pycityagent-1.0.0.dist-info → pycityagent-1.1.0.dist-info}/METADATA +46 -18
- pycityagent-1.1.0.dist-info/RECORD +58 -0
- {pycityagent-1.0.0.dist-info → pycityagent-1.1.0.dist-info}/WHEEL +1 -1
- pycityagent-1.0.0.dist-info/RECORD +0 -48
- {pycityagent-1.0.0.dist-info → pycityagent-1.1.0.dist-info}/LICENSE +0 -0
- {pycityagent-1.0.0.dist-info → pycityagent-1.1.0.dist-info}/top_level.txt +0 -0
pycityagent/brain/sence.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
from typing import Optional, Union
|
2
2
|
from datetime import datetime
|
3
|
+
import math
|
4
|
+
import copy
|
3
5
|
from pycitysim.apphub import UserMessage, AgentMessage
|
4
6
|
from citystreetview import (
|
5
7
|
BaiduStreetView,
|
@@ -10,6 +12,81 @@ from citystreetview import (
|
|
10
12
|
from .brainfc import BrainFunction
|
11
13
|
from .static import POI_TYPE_DICT, LEVEL_ONE_PRE
|
12
14
|
|
15
|
+
def point_on_line_given_distance(start_node, end_node, distance):
|
16
|
+
"""
|
17
|
+
Given two points (start_point and end_point) defining a line, and a distance s to travel along the line,
|
18
|
+
return the coordinates of the point reached after traveling s units along the line, starting from start_point.
|
19
|
+
|
20
|
+
Args:
|
21
|
+
start_point (tuple): Tuple of (x, y) representing the starting point on the line.
|
22
|
+
end_point (tuple): Tuple of (x, y) representing the ending point on the line.
|
23
|
+
distance (float): Distance to travel along the line, starting from start_point.
|
24
|
+
|
25
|
+
Returns:
|
26
|
+
tuple: Tuple of (x, y) representing the new point reached after traveling s units along the line.
|
27
|
+
"""
|
28
|
+
|
29
|
+
x1, y1 = start_node['x'], start_node['y']
|
30
|
+
x2, y2 = end_node['x'], end_node['y']
|
31
|
+
|
32
|
+
# Calculate the slope m and the y-intercept b of the line
|
33
|
+
if x1 == x2:
|
34
|
+
# Vertical line, distance is only along the y-axis
|
35
|
+
return (x1, y1 + distance if distance >= 0 else y1 - abs(distance))
|
36
|
+
else:
|
37
|
+
m = (y2 - y1) / (x2 - x1)
|
38
|
+
b = y1 - m * x1
|
39
|
+
|
40
|
+
# Calculate the direction vector (dx, dy) along the line
|
41
|
+
dx = (x2 - x1) / math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
|
42
|
+
dy = (y2 - y1) / math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
|
43
|
+
|
44
|
+
# Scale the direction vector by the given distance
|
45
|
+
scaled_dx = dx * distance
|
46
|
+
scaled_dy = dy * distance
|
47
|
+
|
48
|
+
# Calculate the new point's coordinates
|
49
|
+
x = x1 + scaled_dx
|
50
|
+
y = y1 + scaled_dy
|
51
|
+
|
52
|
+
return [x, y]
|
53
|
+
|
54
|
+
def get_xy_in_lane(nodes, distance, direction:str='front'):
|
55
|
+
temp_sum = 0
|
56
|
+
remain_s = 0
|
57
|
+
if direction == 'front':
|
58
|
+
# 顺道路方向前进
|
59
|
+
if distance == 0:
|
60
|
+
return [nodes[0]['x'], nodes[0]['y']]
|
61
|
+
key_index = 0
|
62
|
+
for i in range(1, len(nodes)):
|
63
|
+
x1, y1 = nodes[i-1]['x'], nodes[i-1]['y']
|
64
|
+
x2, y2 = nodes[i]['x'], nodes[i]['y']
|
65
|
+
temp_sum += math.sqrt((x2 - x1)**2 + (y2-y1)**2)
|
66
|
+
if temp_sum > distance:
|
67
|
+
remain_s = distance - (temp_sum - math.sqrt((x2 - x1)**2 + (y2-y1)**2))
|
68
|
+
break;
|
69
|
+
key_index += 1
|
70
|
+
if remain_s < 0.5:
|
71
|
+
return [nodes[-1]['x'], nodes[-1]['y']]
|
72
|
+
longlat = point_on_line_given_distance(nodes[key_index], nodes[key_index+1], remain_s)
|
73
|
+
return longlat
|
74
|
+
else:
|
75
|
+
# 逆道路方向前进
|
76
|
+
key_index = len(nodes)
|
77
|
+
for i in range(len(nodes)-1, 0, -1):
|
78
|
+
x1, y1 = nodes[i]['x'], nodes[i]['y']
|
79
|
+
x2, y2 = nodes[i-1]['x'], nodes[i-1]['y']
|
80
|
+
temp_sum += math.sqrt((x2 - x1)**2 + (y2-y1)**2)
|
81
|
+
if temp_sum > distance:
|
82
|
+
remain_s = distance - (temp_sum - math.sqrt((x2 - x1)**2 + (y2-y1)**2))
|
83
|
+
break;
|
84
|
+
key_index -= 1
|
85
|
+
if remain_s < 0.5:
|
86
|
+
return [nodes[0]['x'], nodes[0]['y']]
|
87
|
+
longlat = point_on_line_given_distance(nodes[key_index], nodes[key_index-1], remain_s)
|
88
|
+
return longlat
|
89
|
+
|
13
90
|
class SencePlug:
|
14
91
|
"""
|
15
92
|
感知模块插件
|
@@ -31,35 +108,57 @@ class Sence(BrainFunction):
|
|
31
108
|
"""
|
32
109
|
def __init__(self, agent, sence_raduis:int=10) -> None:
|
33
110
|
super().__init__(agent)
|
34
|
-
|
35
|
-
self.
|
36
|
-
self.
|
111
|
+
|
112
|
+
self._engine = None
|
113
|
+
self._baiduAK = None
|
114
|
+
self._googleProxy = None
|
37
115
|
self._sence_radius = sence_raduis
|
38
116
|
"""
|
39
117
|
感知半径
|
40
118
|
The sence raduis: meter
|
41
119
|
"""
|
120
|
+
|
121
|
+
self._sence_contents = None
|
122
|
+
"""
|
123
|
+
感知内容 如果为None, 则感知所有数据类型
|
124
|
+
Sence content
|
125
|
+
"""
|
126
|
+
|
42
127
|
self.sence_buffer = {}
|
43
128
|
"""
|
44
129
|
感知Buffer: 用于存储感知到的内容
|
45
130
|
Sence Buffer: used to stroe those senced content
|
46
131
|
"""
|
132
|
+
|
47
133
|
self.plugs = []
|
48
134
|
"""
|
49
135
|
感知插件集合
|
50
136
|
Collection of SencePlugs
|
51
137
|
"""
|
138
|
+
|
52
139
|
self.plug_buffer = {}
|
53
140
|
"""
|
54
141
|
感知插件结果Buffer: 用于存储感知插件的输出结果
|
55
142
|
SencePlug Buffer: used to store those sence plug content
|
56
143
|
"""
|
144
|
+
|
57
145
|
self.enable_streeview = False
|
58
146
|
"""
|
59
147
|
街景感知功能接口, 默认为False
|
60
148
|
Interface of streetview function, defualt: False
|
61
149
|
"""
|
62
150
|
|
151
|
+
self._lane_type_mapping = {1: 'driving', 2: 'walking'}
|
152
|
+
|
153
|
+
def set_sence(self, content: list):
|
154
|
+
"""
|
155
|
+
感知配置接口
|
156
|
+
|
157
|
+
Args:
|
158
|
+
- config: 配置选项——包含需要感知的内容
|
159
|
+
"""
|
160
|
+
self._sence_contents = content
|
161
|
+
|
63
162
|
def add_plugs(self, plugs:list[SencePlug]):
|
64
163
|
"""
|
65
164
|
添加感知插件
|
@@ -87,7 +186,7 @@ class Sence(BrainFunction):
|
|
87
186
|
"""
|
88
187
|
return super().state_influence()
|
89
188
|
|
90
|
-
async def Sence(self)
|
189
|
+
async def Sence(self):
|
91
190
|
"""
|
92
191
|
感知功能主体
|
93
192
|
Main function of sence
|
@@ -95,43 +194,71 @@ class Sence(BrainFunction):
|
|
95
194
|
Returns:
|
96
195
|
- (dict): the sence content in dict format
|
97
196
|
- time (int): current time in second (from 00:00:00)
|
98
|
-
- pois ()
|
197
|
+
- pois (list[tuple]): sorted with distance
|
198
|
+
- information of the poi
|
199
|
+
- distance(m)
|
200
|
+
- walking time (s)
|
201
|
+
- walking route (list)
|
202
|
+
- driving time (s)
|
203
|
+
- driving route (list)
|
204
|
+
- poi_time_walk (list[tuple]): sorted with walking time
|
205
|
+
- poi_time_drive (list[tuple]): sorted with driving time
|
206
|
+
- positions (list[position]): reachable positions
|
207
|
+
- lanes
|
208
|
+
- lane_ids
|
209
|
+
- persons
|
210
|
+
- streetview
|
211
|
+
- user_messages
|
212
|
+
- social_messages
|
99
213
|
"""
|
100
|
-
self.state_influence()
|
101
214
|
# * time
|
102
|
-
self.
|
215
|
+
if self._sence_contents == None or 'time' in self._sence_contents:
|
216
|
+
self.sence_buffer['time'] = self._agent._simulator.time
|
103
217
|
|
104
218
|
# * pois
|
105
|
-
self.
|
219
|
+
if self._sence_contents == None or 'poi' in self._sence_contents:
|
220
|
+
self.sence_buffer['pois'] = await self.PerceivePoi()
|
221
|
+
self.sence_buffer['poi_time_walk'] = sorted(self.sence_buffer['pois'], key=lambda x:x[2])
|
222
|
+
self.sence_buffer['poi_time_drive'] = sorted(self.sence_buffer['pois'], key=lambda x:x[4])
|
223
|
+
|
224
|
+
# * reachable positions
|
225
|
+
if self._sence_contents == None or 'position' in self._sence_contents:
|
226
|
+
self.sence_buffer['positions'] = await self.PerceiveReachablePosition()
|
106
227
|
|
107
228
|
# * lanes
|
108
|
-
self.
|
109
|
-
|
110
|
-
|
229
|
+
if self._sence_contents == None or 'lane' in self._sence_contents:
|
230
|
+
self.sence_buffer['lanes'] = self.PerceiveLane()
|
231
|
+
lane_ids = self.PerceiveLane(only_id=True)
|
232
|
+
self.sence_buffer['lane_ids'] = lane_ids
|
111
233
|
|
112
234
|
# * person
|
113
|
-
self.
|
114
|
-
|
115
|
-
self.sence_buffer['persons']
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
235
|
+
if self._sence_contents == None or 'person' in self._sence_contents:
|
236
|
+
lane_ids = self.PerceiveLane(only_id=True)
|
237
|
+
self.sence_buffer['persons'] = []
|
238
|
+
for lane_id in lane_ids:
|
239
|
+
self.sence_buffer['persons'] += await self.PerceivePersonInLanes([lane_id])
|
240
|
+
if 'aoi_position' in self._agent.motion['position'].keys():
|
241
|
+
# 说明agent在aoi中
|
242
|
+
persons_aoi = await self.PerceiveAoi(only_person=True)
|
243
|
+
self.sence_buffer['persons'] += persons_aoi
|
120
244
|
|
121
245
|
# * streetview
|
122
|
-
if self.
|
123
|
-
|
124
|
-
|
125
|
-
|
246
|
+
if self._sence_contents == None or 'streetview' in self._sence_contents:
|
247
|
+
if self.enable_streeview:
|
248
|
+
self.sence_buffer['streetview'] = self.PerceiveStreetView()
|
249
|
+
else:
|
250
|
+
self.sence_buffer['streetview'] = None
|
126
251
|
|
127
252
|
# * user message
|
128
|
-
if self.
|
129
|
-
self.
|
130
|
-
|
131
|
-
|
253
|
+
if self._sence_contents == None or 'user_message' in self._sence_contents:
|
254
|
+
if self._agent.Hub != None:
|
255
|
+
self.sence_buffer['user_messages'] = self.PerceiveUserMessage()
|
256
|
+
else:
|
257
|
+
self.sence_buffer['user_messages'] = []
|
132
258
|
|
133
259
|
# * agent message
|
134
|
-
self.
|
260
|
+
if self._sence_contents == None or 'agent_message' in self._sence_contents:
|
261
|
+
self.sence_buffer['social_messages'] = await self.PerceiveMessageFromPerson()
|
135
262
|
|
136
263
|
# * 插件感知
|
137
264
|
if len(self.plugs) > 0:
|
@@ -140,8 +267,6 @@ class Sence(BrainFunction):
|
|
140
267
|
out = plug.user_func(self.sence_buffer)
|
141
268
|
self.plug_buffer[out_key] = out
|
142
269
|
|
143
|
-
return self.sence_buffer
|
144
|
-
|
145
270
|
# * AOI and POI Related
|
146
271
|
async def PerceiveAoi(self, only_person:bool=False):
|
147
272
|
"""
|
@@ -160,7 +285,118 @@ class Sence(BrainFunction):
|
|
160
285
|
return persons
|
161
286
|
return resp['states'][0]
|
162
287
|
|
163
|
-
def
|
288
|
+
async def PerceiveReachablePosition(self, radius:int=None) -> Optional[list[dict]]:
|
289
|
+
'''
|
290
|
+
可达位置感知
|
291
|
+
Reachable Position Perceive
|
292
|
+
|
293
|
+
Args:
|
294
|
+
- radius (int): 感知半径; Perceive radius
|
295
|
+
|
296
|
+
Returns:
|
297
|
+
- List[dict]: 可达位置列表
|
298
|
+
- lane_id (int)
|
299
|
+
- s (float)
|
300
|
+
- longlat (Tuple[float, float]): [longitude, latitude]
|
301
|
+
- type (str): 'driving' / 'walking' / 'unspecified'
|
302
|
+
'''
|
303
|
+
radius_ = self._sence_radius
|
304
|
+
if radius != None:
|
305
|
+
radius_ = radius
|
306
|
+
positions = []
|
307
|
+
if 'aoi_position' in self._agent.motion['position'].keys():
|
308
|
+
# agent in aoi
|
309
|
+
positions = []
|
310
|
+
aoi_id = self._agent.motion['position']['aoi_position']['aoi_id']
|
311
|
+
aoi = copy.deepcopy(self._agent._simulator.map.get_aoi(aoi_id))
|
312
|
+
driving_positions = aoi['driving_positions']
|
313
|
+
driving_gates = aoi['driving_gates']
|
314
|
+
walking_positions = aoi['walking_positions']
|
315
|
+
walking_gates = aoi['walking_gates']
|
316
|
+
for i in range(len(driving_positions)):
|
317
|
+
longlat = self._agent._simulator.map.xy2lnglat(x=driving_gates[i]['x'], y=driving_gates[i]['y'])
|
318
|
+
positions.append({
|
319
|
+
'lane_id': driving_positions[i]['lane_id'],
|
320
|
+
's': driving_positions[i]['s'],
|
321
|
+
'longlat': longlat,
|
322
|
+
'type': 'driving'
|
323
|
+
})
|
324
|
+
for i in range(len(walking_positions)):
|
325
|
+
longlat = self._agent._simulator.map.xy2lnglat(x=walking_gates[i]['x'], y=walking_gates[i]['y'])
|
326
|
+
positions.append({
|
327
|
+
'lane_id': walking_positions[i]['lane_id'],
|
328
|
+
's': walking_positions[i]['s'],
|
329
|
+
'longlat': longlat,
|
330
|
+
'type': 'walking'
|
331
|
+
})
|
332
|
+
else:
|
333
|
+
# agent in lane
|
334
|
+
lane_id = self._agent.motion['position']['lane_position']['lane_id'] # 所在lane_id
|
335
|
+
lane = copy.deepcopy(self._agnet._simualtor.map.get_lane(lane_id)) # 获取lane信息
|
336
|
+
agent_s = self._agent.motion['position']['lane_position']['s'] # 所处位置——用s距离表示
|
337
|
+
nodes = lane['center_line']['nodes']
|
338
|
+
if agent_s == 0:
|
339
|
+
# 处于当前道路的首部端点位置
|
340
|
+
# 1. 当前道路
|
341
|
+
tmp_s = radius_
|
342
|
+
tmp_s = tmp_s if tmp_s <= lane['length'] else lane['length']
|
343
|
+
x, y = get_xy_in_lane(nodes, tmp_s)
|
344
|
+
longlat = self._agent._simulator.map.xy2lnglat(x=x, y=y)
|
345
|
+
type = copy.deepcopy(self._lane_type_mapping.get(lane['type'], 'unspecified'))
|
346
|
+
positions += [{'lane_id': lane_id, 's': tmp_s, 'longlat': longlat, 'type': type}]
|
347
|
+
|
348
|
+
# 2. 前驱道路
|
349
|
+
pre_lanes = lane['predecessors']
|
350
|
+
for pre_lane in pre_lanes:
|
351
|
+
pre_lane_id = pre_lane['id']
|
352
|
+
pre_lane_ = copy.deepcopy(self._agent._simulator.map.get_lane(pre_lane_id))
|
353
|
+
pre_lane_nodes = pre_lane_['center_line']['nodes']
|
354
|
+
tmp_s = pre_lane_['length'] - radius_
|
355
|
+
tmp_s = tmp_s if tmp_s >= 0 else 0
|
356
|
+
x, y = get_xy_in_lane(pre_lane_nodes, tmp_s, 'back')
|
357
|
+
longlat = self._agent._simulator.map.xy2lnglat(x=x, y=y)
|
358
|
+
type = self._lane_type_mapping.get(pre_lane_['type'], 'unspecified')
|
359
|
+
positions += [{'lane_id': pre_lane_id, 's': tmp_s, 'longlat': longlat, 'type': type}]
|
360
|
+
elif agent_s == lane['length']:
|
361
|
+
# 处于当前道路的尾部端点位置
|
362
|
+
# 1. 当前道路
|
363
|
+
tmp_s = agent_s - radius_
|
364
|
+
tmp_s = tmp_s if tmp_s >= 0 else 0
|
365
|
+
x, y = get_xy_in_lane(nodes, tmp_s, 'back')
|
366
|
+
longlat = self._agent._simulator.map.xy2loglat(x=x, y=y)
|
367
|
+
type = self._lane_type_mapping.get(lane['type'], 'unspecified')
|
368
|
+
positions += [{'lane_id': lane_id, 's': tmp_s, 'longlat': longlat, 'type': type}]
|
369
|
+
|
370
|
+
# 2. 后继道路
|
371
|
+
suc_lanes = lane['successors']
|
372
|
+
for suc_lane in suc_lanes:
|
373
|
+
suc_lane_id = suc_lane['id']
|
374
|
+
suc_lane_ = copy.deepcopy(self._agent._simulator.map.get_lane(suc_lane_id))
|
375
|
+
suc_lane_nodes = suc_lane_['center_line']['nodes']
|
376
|
+
tmp_s = radius_
|
377
|
+
tmp_s = tmp_s if tmp_s <= suc_lane_['length'] else suc_lane_['length']
|
378
|
+
x, y = get_xy_in_lane(suc_lane_nodes, tmp_s)
|
379
|
+
longlat = self._agent._simulator.map.xy2loglat(x=x, y=y)
|
380
|
+
type = self._lane_type_mapping.get(lane['type'], 'unspecified')
|
381
|
+
positions += [{'lane_id': suc_lane_id, 's': tmp_s, 'longlat': longlat, 'type': type}]
|
382
|
+
else:
|
383
|
+
# 非端点位置
|
384
|
+
neg_s = agent_s - radius_
|
385
|
+
neg_s = neg_s if neg_s >= 0 else 0
|
386
|
+
x, y = get_xy_in_lane(nodes, neg_s, 'back')
|
387
|
+
longlat = self._agent._simulator.map.xy2loglat(x=x, y=y)
|
388
|
+
type = self._lane_type_mapping.get(lane['type'], 'unspecified')
|
389
|
+
positions += [{'lans_id': lane_id, 's': neg_s, 'longlat': longlat, 'type': type}]
|
390
|
+
|
391
|
+
pos_s = agent_s + radius_
|
392
|
+
pos_s = pos_s if pos_s <= lane['length'] else lane['length']
|
393
|
+
x, y = get_xy_in_lane(nodes, pos_s)
|
394
|
+
longlat = self._agent._simulator.map.xy2loglat(x=x, y=y)
|
395
|
+
type = self._lane_type_mapping.get(lane['type'], 'unspecified')
|
396
|
+
positions += [{'lans_id': lane_id, 's': neg_s, 'longlat': longlat, 'type': type}]
|
397
|
+
return positions
|
398
|
+
|
399
|
+
async def PerceivePoi(self, radius:int=None, category:str=None):
|
164
400
|
"""
|
165
401
|
POI感知
|
166
402
|
Sence POI
|
@@ -170,31 +406,78 @@ class Sence(BrainFunction):
|
|
170
406
|
- category: 6位数字类型编码, 如果为None则获取所有类型POI. 6-digit coding which represents the poi type, if None, then sence all type of poi
|
171
407
|
|
172
408
|
Returns:
|
173
|
-
- List[Tuple[Any, float]]: poi列表,
|
409
|
+
- List[Tuple[Any, float]]: poi列表, 每个元素为:
|
410
|
+
- poi
|
411
|
+
- 距离: 单位m
|
412
|
+
- 步行前往需要的时间: 单位s, -1表示不可达或无需进入城市道路(处于同一aoi)
|
413
|
+
- 步行路线
|
414
|
+
- 驾车前往需要的时间: 单位s, -1表示驾车不可达或无需进入城市道路(处于同一aoi)
|
415
|
+
- 行车路线
|
174
416
|
"""
|
175
417
|
radius_ = self._sence_radius
|
176
418
|
if radius != None:
|
177
419
|
radius_ = radius
|
178
420
|
if category != None:
|
179
421
|
category_prefix = category
|
180
|
-
resp = self._agent._simulator.map.query_pois(
|
422
|
+
resp = copy.deepcopy(self._agent._simulator.map.query_pois(
|
181
423
|
center=(self._agent.motion['position']['xy_position']['x'], self._agent.motion['position']['xy_position']['y']),
|
182
424
|
radius=radius_,
|
183
425
|
category_prefix=category_prefix
|
184
|
-
)
|
426
|
+
))
|
185
427
|
else:
|
186
428
|
resp = []
|
187
429
|
for category_prefix in LEVEL_ONE_PRE:
|
188
|
-
resp += self._agent._simulator.map.query_pois(
|
430
|
+
resp += copy.deepcopy(self._agent._simulator.map.query_pois(
|
189
431
|
center=(self._agent.motion['position']['xy_position']['x'], self._agent.motion['position']['xy_position']['y']),
|
190
432
|
radius=radius_,
|
191
433
|
category_prefix=category_prefix
|
192
|
-
)
|
193
|
-
|
434
|
+
))
|
435
|
+
|
436
|
+
# 从六位代码转变为具体类型
|
437
|
+
results = []
|
438
|
+
start_position = {}
|
439
|
+
if 'aoi_position' in self._agent.motion['position']:
|
440
|
+
start_position = {'aoi_position': {'aoi_id': self._agent.motion['position']['aoi_position']['aoi_id']}}
|
441
|
+
else:
|
442
|
+
start_position = {'lane_position': {'lane_id': self._agent.motion['position']['lane_position']['lane_id'], 's': self._agent.motion['position']['lane_position']['s']}}
|
194
443
|
for poi in resp:
|
195
444
|
cate_str = poi[0]['category']
|
196
445
|
poi[0]['category'] = POI_TYPE_DICT[cate_str]
|
197
|
-
|
446
|
+
info = poi[0]
|
447
|
+
distance = poi[1]
|
448
|
+
# walking
|
449
|
+
rout_walking_res = await self._agent._simulator.routing.GetRoute(
|
450
|
+
{
|
451
|
+
'type': 2,
|
452
|
+
'start': start_position,
|
453
|
+
'end': {'aoi_position': {'aoi_id': info['aoi_id']}},
|
454
|
+
}
|
455
|
+
)
|
456
|
+
if len(rout_walking_res['journeys']) <= 0:
|
457
|
+
walking_time = -1
|
458
|
+
walking_route = []
|
459
|
+
else:
|
460
|
+
walking_time = rout_walking_res['journeys'][0]['walking']['eta']
|
461
|
+
walking_route = rout_walking_res['journeys'][0]['walking']['route']
|
462
|
+
|
463
|
+
# driving
|
464
|
+
rout_driving_res = await self._agent._simulator.routing.GetRoute(
|
465
|
+
{
|
466
|
+
'type': 1,
|
467
|
+
'start': start_position,
|
468
|
+
'end': {'aoi_position': {'aoi_id': info['aoi_id']}},
|
469
|
+
}
|
470
|
+
)
|
471
|
+
if len(rout_driving_res['journeys']) <= 0:
|
472
|
+
driving_time = -1
|
473
|
+
driving_route = []
|
474
|
+
else:
|
475
|
+
driving_time = rout_driving_res['journeys'][0]['driving']['eta']
|
476
|
+
driving_route = rout_driving_res['journeys'][0]['driving']['road_ids']
|
477
|
+
|
478
|
+
# append
|
479
|
+
results.append((info, distance, walking_time, walking_route, driving_time, driving_route))
|
480
|
+
return results
|
198
481
|
|
199
482
|
# * Lane Related
|
200
483
|
def PerceiveLane(self, radius:int=None, type:int=3, only_id:bool=False) -> Union[list, dict]:
|
@@ -224,28 +507,28 @@ class Sence(BrainFunction):
|
|
224
507
|
radius_ = radius
|
225
508
|
if type == 3:
|
226
509
|
resp = {}
|
227
|
-
resp['roadway'] = self._agent._simulator.map.query_lane(
|
510
|
+
resp['roadway'] = copy.deepcopy(self._agent._simulator.map.query_lane(
|
228
511
|
xy=(self._agent.motion['position']['xy_position']['x'], self._agent.motion['position']['xy_position']['y']),
|
229
512
|
radius=radius_,
|
230
513
|
lane_type=1
|
231
|
-
)
|
232
|
-
resp['sidewalk'] = resp = self._agent._simulator.map.query_lane(
|
514
|
+
))
|
515
|
+
resp['sidewalk'] = resp = copy.deepcopy(self._agent._simulator.map.query_lane(
|
233
516
|
xy=(self._agent.motion['position']['xy_position']['x'], self._agent.motion['position']['xy_position']['y']),
|
234
517
|
radius=radius_,
|
235
518
|
lane_type=2
|
236
|
-
)
|
519
|
+
))
|
237
520
|
elif type == 2:
|
238
|
-
resp = self._agent._simulator.map.query_lane(
|
521
|
+
resp = copy.deepcopy(self._agent._simulator.map.query_lane(
|
239
522
|
xy=(self._agent.motion['position']['xy_position']['x'], self._agent.motion['position']['xy_position']['y']),
|
240
523
|
radius=radius_,
|
241
524
|
lane_type=2
|
242
|
-
)
|
525
|
+
))
|
243
526
|
else:
|
244
|
-
resp = self._agent._simulator.map.query_lane(
|
527
|
+
resp = copy.deepcopy(self._agent._simulator.map.query_lane(
|
245
528
|
xy=(self._agent.motion['position']['xy_position']['x'], self._agent.motion['position']['xy_position']['y']),
|
246
529
|
radius=radius_,
|
247
530
|
lane_type=1
|
248
|
-
)
|
531
|
+
))
|
249
532
|
if only_id:
|
250
533
|
ids = []
|
251
534
|
for ele in resp:
|
@@ -256,6 +539,7 @@ class Sence(BrainFunction):
|
|
256
539
|
# * StreetView Related
|
257
540
|
def PerceiveStreetView(
|
258
541
|
self,
|
542
|
+
# engine:str="baidumap",
|
259
543
|
heading:str="front",
|
260
544
|
save:bool=False,
|
261
545
|
save_dir:str=None
|
@@ -271,14 +555,20 @@ class Sence(BrainFunction):
|
|
271
555
|
- save_dir (str): 存储文件夹. save directory
|
272
556
|
|
273
557
|
Returns:
|
274
|
-
- PIL.Image.Image
|
275
|
-
"""
|
558
|
+
- List[PIL.Image.Image] = [left, front, right, back]
|
559
|
+
"""
|
560
|
+
if self._engine == None:
|
561
|
+
print("Can't get streetview, please check the streetview config")
|
562
|
+
return []
|
563
|
+
if self._engine == 'baidumap' and self._baiduAK == None:
|
564
|
+
print("Can't get streetview, please provide a baidumap AK")
|
565
|
+
return []
|
566
|
+
if self._engine == 'googlemap' and self._googleProxy == None:
|
567
|
+
print("Can't get streetview, please provide a googlemap proxy")
|
568
|
+
return []
|
569
|
+
|
276
570
|
coords = [(self._agent.motion['position']['longlat_position']['longitude'], self._agent.motion['position']['longlat_position']['latitude'])]
|
277
|
-
|
278
|
-
模拟人眼视角
|
279
|
-
水平FOV: 160
|
280
|
-
垂直角暂时不支持
|
281
|
-
"""
|
571
|
+
|
282
572
|
if heading == "front":
|
283
573
|
heading_direction = self._agent.motion['direction']
|
284
574
|
elif heading == "back":
|
@@ -289,32 +579,36 @@ class Sence(BrainFunction):
|
|
289
579
|
heading_direction += 90
|
290
580
|
else:
|
291
581
|
print("Wrong HEADING, Use FRONT")
|
292
|
-
|
293
|
-
|
582
|
+
persp = []
|
583
|
+
if self._engine == "baidumap":
|
584
|
+
points = wgs842bd09mc(coords, self._baiduAK)
|
294
585
|
sv = BaiduStreetView.search(points[0][0], points[0][1])
|
295
586
|
eq = Equirectangular(sv)
|
296
|
-
persp
|
587
|
+
persp.append(eq.get_perspective(120, heading_direction-90, 20, 256, 512))
|
588
|
+
persp.append(eq.get_perspective(120, heading_direction, 20, 256, 512))
|
589
|
+
persp.append(eq.get_perspective(120, heading_direction+90, 20, 256, 512))
|
590
|
+
persp.append(eq.get_perspective(120, heading_direction+180, 20, 256, 512))
|
297
591
|
if save:
|
298
592
|
date_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
299
|
-
sv.panorama.save("{}/{}_{}
|
300
|
-
|
593
|
+
sv.panorama.save("{}/{}_{}_panorama_{}.jpg".format(save_dir, self._agent.name, date_time))
|
594
|
+
for i in range(len(persp)):
|
595
|
+
persp[i].save("{}/{}_{}_persp_{}.jpg".format(save_dir, self._agent.name, date_time, i))
|
301
596
|
return persp
|
302
|
-
elif self.
|
597
|
+
elif self._engine == "googlemap":
|
303
598
|
sv = GoogleStreetView.search(
|
304
599
|
points[0][0],
|
305
600
|
points[0][1],
|
306
|
-
proxies=self.
|
601
|
+
proxies=self._googleProxy,
|
307
602
|
cache_dir=save_dir
|
308
603
|
)
|
309
604
|
eq = Equirectangular(sv)
|
310
605
|
persp = eq.get_perspective(120, heading_direction, 20, 256, 512)
|
311
606
|
if save:
|
312
|
-
|
313
|
-
|
607
|
+
date_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
608
|
+
sv.panorama.save("{}/{}_{}_panorama_{}.jpg".format(save_dir, self._agent.name, date_time))
|
609
|
+
for i in range(len(persp)):
|
610
|
+
persp[i].save("{}/{}_{}_persp_{}.jpg".format(save_dir, self._agent.name, date_time, i))
|
314
611
|
return persp
|
315
|
-
else:
|
316
|
-
print("Error StreetView Engine")
|
317
|
-
return None
|
318
612
|
|
319
613
|
# * Person Related
|
320
614
|
def PerceivePersonCircule(self, raduis=30):
|
pycityagent/cc/__init__.py
CHANGED