pycityagent 1.0.0__py3-none-any.whl → 1.1.1__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 +385 -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/urbanllm/urbanllm.py +2 -2
- {pycityagent-1.0.0.dist-info → pycityagent-1.1.1.dist-info}/METADATA +47 -19
- pycityagent-1.1.1.dist-info/RECORD +58 -0
- {pycityagent-1.0.0.dist-info → pycityagent-1.1.1.dist-info}/WHEEL +1 -1
- pycityagent-1.0.0.dist-info/RECORD +0 -48
- {pycityagent-1.0.0.dist-info → pycityagent-1.1.1.dist-info}/LICENSE +0 -0
- {pycityagent-1.0.0.dist-info → pycityagent-1.1.1.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,145 @@ 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
|
+
- xy (Tuple[float, float]): (x, y)
|
301
|
+
- longlat (Tuple[float, float]): (longitude, latitude)
|
302
|
+
- type (str): 'driving' / 'walking' / 'unspecified'
|
303
|
+
'''
|
304
|
+
radius_ = self._sence_radius
|
305
|
+
if radius != None:
|
306
|
+
radius_ = radius
|
307
|
+
positions = []
|
308
|
+
if 'aoi_position' in self._agent.motion['position'].keys():
|
309
|
+
# agent in aoi
|
310
|
+
positions = []
|
311
|
+
aoi_id = self._agent.motion['position']['aoi_position']['aoi_id']
|
312
|
+
aoi = copy.deepcopy(self._agent._simulator.map.get_aoi(aoi_id))
|
313
|
+
driving_positions = aoi['driving_positions']
|
314
|
+
driving_gates = aoi['driving_gates']
|
315
|
+
walking_positions = aoi['walking_positions']
|
316
|
+
walking_gates = aoi['walking_gates']
|
317
|
+
for i in range(len(driving_positions)):
|
318
|
+
longlat = self._agent._simulator.map.xy2lnglat(x=driving_gates[i]['x'], y=driving_gates[i]['y'])
|
319
|
+
positions.append({
|
320
|
+
'lane_id': driving_positions[i]['lane_id'],
|
321
|
+
's': driving_positions[i]['s'],
|
322
|
+
'xy': (driving_gates[i]['x'], driving_gates[i]['y']),
|
323
|
+
'longlat': longlat,
|
324
|
+
'type': 'driving'
|
325
|
+
})
|
326
|
+
for i in range(len(walking_positions)):
|
327
|
+
longlat = self._agent._simulator.map.xy2lnglat(x=walking_gates[i]['x'], y=walking_gates[i]['y'])
|
328
|
+
positions.append({
|
329
|
+
'lane_id': walking_positions[i]['lane_id'],
|
330
|
+
's': walking_positions[i]['s'],
|
331
|
+
'xy': (walking_gates[i]['x'], walking_gates[i]['y']),
|
332
|
+
'longlat': longlat,
|
333
|
+
'type': 'walking'
|
334
|
+
})
|
335
|
+
else:
|
336
|
+
# agent in lane
|
337
|
+
lane_id = self._agent.motion['position']['lane_position']['lane_id'] # 所在lane_id
|
338
|
+
lane = copy.deepcopy(self._agnet._simualtor.map.get_lane(lane_id)) # 获取lane信息
|
339
|
+
agent_s = self._agent.motion['position']['lane_position']['s'] # 所处位置——用s距离表示
|
340
|
+
nodes = lane['center_line']['nodes']
|
341
|
+
if agent_s == 0:
|
342
|
+
# 处于当前道路的首部端点位置
|
343
|
+
# 1. 当前道路
|
344
|
+
tmp_s = radius_
|
345
|
+
tmp_s = tmp_s if tmp_s <= lane['length'] else lane['length']
|
346
|
+
x, y = get_xy_in_lane(nodes, tmp_s)
|
347
|
+
longlat = self._agent._simulator.map.xy2lnglat(x=x, y=y)
|
348
|
+
type = copy.deepcopy(self._lane_type_mapping.get(lane['type'], 'unspecified'))
|
349
|
+
positions += [{'lane_id': lane_id,
|
350
|
+
's': tmp_s,
|
351
|
+
'xy': (x, y),
|
352
|
+
'longlat': longlat,
|
353
|
+
'type': type}]
|
354
|
+
|
355
|
+
# 2. 前驱道路
|
356
|
+
pre_lanes = lane['predecessors']
|
357
|
+
for pre_lane in pre_lanes:
|
358
|
+
pre_lane_id = pre_lane['id']
|
359
|
+
pre_lane_ = copy.deepcopy(self._agent._simulator.map.get_lane(pre_lane_id))
|
360
|
+
pre_lane_nodes = pre_lane_['center_line']['nodes']
|
361
|
+
tmp_s = pre_lane_['length'] - radius_
|
362
|
+
tmp_s = tmp_s if tmp_s >= 0 else 0
|
363
|
+
x, y = get_xy_in_lane(pre_lane_nodes, tmp_s, 'back')
|
364
|
+
longlat = self._agent._simulator.map.xy2lnglat(x=x, y=y)
|
365
|
+
type = self._lane_type_mapping.get(pre_lane_['type'], 'unspecified')
|
366
|
+
positions += [{'lane_id': pre_lane_id,
|
367
|
+
's': tmp_s,
|
368
|
+
'xy': (x, y),
|
369
|
+
'longlat': longlat,
|
370
|
+
'type': type}]
|
371
|
+
elif agent_s == lane['length']:
|
372
|
+
# 处于当前道路的尾部端点位置
|
373
|
+
# 1. 当前道路
|
374
|
+
tmp_s = agent_s - radius_
|
375
|
+
tmp_s = tmp_s if tmp_s >= 0 else 0
|
376
|
+
x, y = get_xy_in_lane(nodes, tmp_s, 'back')
|
377
|
+
longlat = self._agent._simulator.map.xy2loglat(x=x, y=y)
|
378
|
+
type = self._lane_type_mapping.get(lane['type'], 'unspecified')
|
379
|
+
positions += [{'lane_id': lane_id,
|
380
|
+
's': tmp_s,
|
381
|
+
'xy': (x, y),
|
382
|
+
'longlat': longlat,
|
383
|
+
'type': type}]
|
384
|
+
|
385
|
+
# 2. 后继道路
|
386
|
+
suc_lanes = lane['successors']
|
387
|
+
for suc_lane in suc_lanes:
|
388
|
+
suc_lane_id = suc_lane['id']
|
389
|
+
suc_lane_ = copy.deepcopy(self._agent._simulator.map.get_lane(suc_lane_id))
|
390
|
+
suc_lane_nodes = suc_lane_['center_line']['nodes']
|
391
|
+
tmp_s = radius_
|
392
|
+
tmp_s = tmp_s if tmp_s <= suc_lane_['length'] else suc_lane_['length']
|
393
|
+
x, y = get_xy_in_lane(suc_lane_nodes, tmp_s)
|
394
|
+
longlat = self._agent._simulator.map.xy2loglat(x=x, y=y)
|
395
|
+
type = self._lane_type_mapping.get(lane['type'], 'unspecified')
|
396
|
+
positions += [{'lane_id': suc_lane_id,
|
397
|
+
's': tmp_s,
|
398
|
+
'xy': (x, y),
|
399
|
+
'longlat': longlat,
|
400
|
+
'type': type}]
|
401
|
+
else:
|
402
|
+
# 非端点位置
|
403
|
+
neg_s = agent_s - radius_
|
404
|
+
neg_s = neg_s if neg_s >= 0 else 0
|
405
|
+
x, y = get_xy_in_lane(nodes, neg_s, 'back')
|
406
|
+
longlat = self._agent._simulator.map.xy2loglat(x=x, y=y)
|
407
|
+
type = self._lane_type_mapping.get(lane['type'], 'unspecified')
|
408
|
+
positions += [{'lans_id': lane_id,
|
409
|
+
's': neg_s,
|
410
|
+
'xy': (x, y),
|
411
|
+
'longlat': longlat,
|
412
|
+
'type': type}]
|
413
|
+
|
414
|
+
pos_s = agent_s + radius_
|
415
|
+
pos_s = pos_s if pos_s <= lane['length'] else lane['length']
|
416
|
+
x, y = get_xy_in_lane(nodes, pos_s)
|
417
|
+
longlat = self._agent._simulator.map.xy2loglat(x=x, y=y)
|
418
|
+
type = self._lane_type_mapping.get(lane['type'], 'unspecified')
|
419
|
+
positions += [{'lans_id': lane_id,
|
420
|
+
's': neg_s,
|
421
|
+
'xy': (x, y),
|
422
|
+
'longlat': longlat,
|
423
|
+
'type': type}]
|
424
|
+
return positions
|
425
|
+
|
426
|
+
async def PerceivePoi(self, radius:int=None, category:str=None):
|
164
427
|
"""
|
165
428
|
POI感知
|
166
429
|
Sence POI
|
@@ -170,31 +433,78 @@ class Sence(BrainFunction):
|
|
170
433
|
- category: 6位数字类型编码, 如果为None则获取所有类型POI. 6-digit coding which represents the poi type, if None, then sence all type of poi
|
171
434
|
|
172
435
|
Returns:
|
173
|
-
- List[Tuple[Any, float]]: poi列表,
|
436
|
+
- List[Tuple[Any, float]]: poi列表, 每个元素为:
|
437
|
+
- poi
|
438
|
+
- 距离: 单位m
|
439
|
+
- 步行前往需要的时间: 单位s, -1表示不可达或无需进入城市道路(处于同一aoi)
|
440
|
+
- 步行路线
|
441
|
+
- 驾车前往需要的时间: 单位s, -1表示驾车不可达或无需进入城市道路(处于同一aoi)
|
442
|
+
- 行车路线
|
174
443
|
"""
|
175
444
|
radius_ = self._sence_radius
|
176
445
|
if radius != None:
|
177
446
|
radius_ = radius
|
178
447
|
if category != None:
|
179
448
|
category_prefix = category
|
180
|
-
resp = self._agent._simulator.map.query_pois(
|
449
|
+
resp = copy.deepcopy(self._agent._simulator.map.query_pois(
|
181
450
|
center=(self._agent.motion['position']['xy_position']['x'], self._agent.motion['position']['xy_position']['y']),
|
182
451
|
radius=radius_,
|
183
452
|
category_prefix=category_prefix
|
184
|
-
)
|
453
|
+
))
|
185
454
|
else:
|
186
455
|
resp = []
|
187
456
|
for category_prefix in LEVEL_ONE_PRE:
|
188
|
-
resp += self._agent._simulator.map.query_pois(
|
457
|
+
resp += copy.deepcopy(self._agent._simulator.map.query_pois(
|
189
458
|
center=(self._agent.motion['position']['xy_position']['x'], self._agent.motion['position']['xy_position']['y']),
|
190
459
|
radius=radius_,
|
191
460
|
category_prefix=category_prefix
|
192
|
-
)
|
193
|
-
|
461
|
+
))
|
462
|
+
|
463
|
+
# 从六位代码转变为具体类型
|
464
|
+
results = []
|
465
|
+
start_position = {}
|
466
|
+
if 'aoi_position' in self._agent.motion['position']:
|
467
|
+
start_position = {'aoi_position': {'aoi_id': self._agent.motion['position']['aoi_position']['aoi_id']}}
|
468
|
+
else:
|
469
|
+
start_position = {'lane_position': {'lane_id': self._agent.motion['position']['lane_position']['lane_id'], 's': self._agent.motion['position']['lane_position']['s']}}
|
194
470
|
for poi in resp:
|
195
471
|
cate_str = poi[0]['category']
|
196
472
|
poi[0]['category'] = POI_TYPE_DICT[cate_str]
|
197
|
-
|
473
|
+
info = poi[0]
|
474
|
+
distance = poi[1]
|
475
|
+
# walking
|
476
|
+
rout_walking_res = await self._agent._simulator.routing.GetRoute(
|
477
|
+
{
|
478
|
+
'type': 2,
|
479
|
+
'start': start_position,
|
480
|
+
'end': {'aoi_position': {'aoi_id': info['aoi_id']}},
|
481
|
+
}
|
482
|
+
)
|
483
|
+
if len(rout_walking_res['journeys']) <= 0:
|
484
|
+
walking_time = -1
|
485
|
+
walking_route = []
|
486
|
+
else:
|
487
|
+
walking_time = rout_walking_res['journeys'][0]['walking']['eta']
|
488
|
+
walking_route = rout_walking_res['journeys'][0]['walking']['route']
|
489
|
+
|
490
|
+
# driving
|
491
|
+
rout_driving_res = await self._agent._simulator.routing.GetRoute(
|
492
|
+
{
|
493
|
+
'type': 1,
|
494
|
+
'start': start_position,
|
495
|
+
'end': {'aoi_position': {'aoi_id': info['aoi_id']}},
|
496
|
+
}
|
497
|
+
)
|
498
|
+
if len(rout_driving_res['journeys']) <= 0:
|
499
|
+
driving_time = -1
|
500
|
+
driving_route = []
|
501
|
+
else:
|
502
|
+
driving_time = rout_driving_res['journeys'][0]['driving']['eta']
|
503
|
+
driving_route = rout_driving_res['journeys'][0]['driving']['road_ids']
|
504
|
+
|
505
|
+
# append
|
506
|
+
results.append((info, distance, walking_time, walking_route, driving_time, driving_route))
|
507
|
+
return results
|
198
508
|
|
199
509
|
# * Lane Related
|
200
510
|
def PerceiveLane(self, radius:int=None, type:int=3, only_id:bool=False) -> Union[list, dict]:
|
@@ -224,28 +534,28 @@ class Sence(BrainFunction):
|
|
224
534
|
radius_ = radius
|
225
535
|
if type == 3:
|
226
536
|
resp = {}
|
227
|
-
resp['roadway'] = self._agent._simulator.map.query_lane(
|
537
|
+
resp['roadway'] = copy.deepcopy(self._agent._simulator.map.query_lane(
|
228
538
|
xy=(self._agent.motion['position']['xy_position']['x'], self._agent.motion['position']['xy_position']['y']),
|
229
539
|
radius=radius_,
|
230
540
|
lane_type=1
|
231
|
-
)
|
232
|
-
resp['sidewalk'] = resp = self._agent._simulator.map.query_lane(
|
541
|
+
))
|
542
|
+
resp['sidewalk'] = resp = copy.deepcopy(self._agent._simulator.map.query_lane(
|
233
543
|
xy=(self._agent.motion['position']['xy_position']['x'], self._agent.motion['position']['xy_position']['y']),
|
234
544
|
radius=radius_,
|
235
545
|
lane_type=2
|
236
|
-
)
|
546
|
+
))
|
237
547
|
elif type == 2:
|
238
|
-
resp = self._agent._simulator.map.query_lane(
|
548
|
+
resp = copy.deepcopy(self._agent._simulator.map.query_lane(
|
239
549
|
xy=(self._agent.motion['position']['xy_position']['x'], self._agent.motion['position']['xy_position']['y']),
|
240
550
|
radius=radius_,
|
241
551
|
lane_type=2
|
242
|
-
)
|
552
|
+
))
|
243
553
|
else:
|
244
|
-
resp = self._agent._simulator.map.query_lane(
|
554
|
+
resp = copy.deepcopy(self._agent._simulator.map.query_lane(
|
245
555
|
xy=(self._agent.motion['position']['xy_position']['x'], self._agent.motion['position']['xy_position']['y']),
|
246
556
|
radius=radius_,
|
247
557
|
lane_type=1
|
248
|
-
)
|
558
|
+
))
|
249
559
|
if only_id:
|
250
560
|
ids = []
|
251
561
|
for ele in resp:
|
@@ -256,6 +566,7 @@ class Sence(BrainFunction):
|
|
256
566
|
# * StreetView Related
|
257
567
|
def PerceiveStreetView(
|
258
568
|
self,
|
569
|
+
# engine:str="baidumap",
|
259
570
|
heading:str="front",
|
260
571
|
save:bool=False,
|
261
572
|
save_dir:str=None
|
@@ -271,14 +582,20 @@ class Sence(BrainFunction):
|
|
271
582
|
- save_dir (str): 存储文件夹. save directory
|
272
583
|
|
273
584
|
Returns:
|
274
|
-
- PIL.Image.Image
|
275
|
-
"""
|
585
|
+
- List[PIL.Image.Image] = [left, front, right, back]
|
586
|
+
"""
|
587
|
+
if self._engine == None:
|
588
|
+
print("Can't get streetview, please check the streetview config")
|
589
|
+
return []
|
590
|
+
if self._engine == 'baidumap' and self._baiduAK == None:
|
591
|
+
print("Can't get streetview, please provide a baidumap AK")
|
592
|
+
return []
|
593
|
+
if self._engine == 'googlemap' and self._googleProxy == None:
|
594
|
+
print("Can't get streetview, please provide a googlemap proxy")
|
595
|
+
return []
|
596
|
+
|
276
597
|
coords = [(self._agent.motion['position']['longlat_position']['longitude'], self._agent.motion['position']['longlat_position']['latitude'])]
|
277
|
-
|
278
|
-
模拟人眼视角
|
279
|
-
水平FOV: 160
|
280
|
-
垂直角暂时不支持
|
281
|
-
"""
|
598
|
+
|
282
599
|
if heading == "front":
|
283
600
|
heading_direction = self._agent.motion['direction']
|
284
601
|
elif heading == "back":
|
@@ -289,32 +606,36 @@ class Sence(BrainFunction):
|
|
289
606
|
heading_direction += 90
|
290
607
|
else:
|
291
608
|
print("Wrong HEADING, Use FRONT")
|
292
|
-
|
293
|
-
|
609
|
+
persp = []
|
610
|
+
if self._engine == "baidumap":
|
611
|
+
points = wgs842bd09mc(coords, self._baiduAK)
|
294
612
|
sv = BaiduStreetView.search(points[0][0], points[0][1])
|
295
613
|
eq = Equirectangular(sv)
|
296
|
-
persp
|
614
|
+
persp.append(eq.get_perspective(120, heading_direction-90, 20, 256, 512))
|
615
|
+
persp.append(eq.get_perspective(120, heading_direction, 20, 256, 512))
|
616
|
+
persp.append(eq.get_perspective(120, heading_direction+90, 20, 256, 512))
|
617
|
+
persp.append(eq.get_perspective(120, heading_direction+180, 20, 256, 512))
|
297
618
|
if save:
|
298
619
|
date_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
299
|
-
sv.panorama.save("{}/{}_{}
|
300
|
-
|
620
|
+
sv.panorama.save("{}/{}_{}_panorama_{}.jpg".format(save_dir, self._agent.name, date_time))
|
621
|
+
for i in range(len(persp)):
|
622
|
+
persp[i].save("{}/{}_{}_persp_{}.jpg".format(save_dir, self._agent.name, date_time, i))
|
301
623
|
return persp
|
302
|
-
elif self.
|
624
|
+
elif self._engine == "googlemap":
|
303
625
|
sv = GoogleStreetView.search(
|
304
626
|
points[0][0],
|
305
627
|
points[0][1],
|
306
|
-
proxies=self.
|
628
|
+
proxies=self._googleProxy,
|
307
629
|
cache_dir=save_dir
|
308
630
|
)
|
309
631
|
eq = Equirectangular(sv)
|
310
632
|
persp = eq.get_perspective(120, heading_direction, 20, 256, 512)
|
311
633
|
if save:
|
312
|
-
|
313
|
-
|
634
|
+
date_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
635
|
+
sv.panorama.save("{}/{}_{}_panorama_{}.jpg".format(save_dir, self._agent.name, date_time))
|
636
|
+
for i in range(len(persp)):
|
637
|
+
persp[i].save("{}/{}_{}_persp_{}.jpg".format(save_dir, self._agent.name, date_time, i))
|
314
638
|
return persp
|
315
|
-
else:
|
316
|
-
print("Error StreetView Engine")
|
317
|
-
return None
|
318
639
|
|
319
640
|
# * Person Related
|
320
641
|
def PerceivePersonCircule(self, raduis=30):
|
pycityagent/cc/__init__.py
CHANGED