CARLA
 
载入中...
搜索中...
未找到
OpenDriveActor.cpp
浏览该文件的文档.
1// Copyright (c) 2019 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
7#include "Carla.h"
9
11
12#include "UObject/ConstructorHelpers.h"
13#include "DrawDebugHelpers.h"
14
15#include "ConstructorHelpers.h"
16#include "Materials/MaterialExpressionTextureSample.h"
17
18#include "DrawDebugHelpers.h"
19
21#include <carla/geom/Math.h>
24#include <carla/rpc/String.h>
26
27#include <algorithm>
28#include <unordered_set>
29
30AOpenDriveActor::AOpenDriveActor(const FObjectInitializer &ObjectInitializer)
31 : Super(ObjectInitializer)
32{
33 PrimaryActorTick.bCanEverTick = false;
34
35 // 用来保存一次性初始化的结构
36 static struct FConstructorStatics
37 {
38 // 用来从资源包里寻找目标渲染纹理图片的工具类
39 ConstructorHelpers::FObjectFinderOptional<UTexture2D> TextureObject;
40 FName Category;
41 FText Name;
42 FConstructorStatics()
43 // 使用这个静态类(结构体)找到渲染纹理图片的路径
44 : TextureObject(TEXT("/Carla/Icons/OpenDriveActorIcon")),
45 Category(TEXT("OpenDriveActor")),
46 Name(NSLOCTEXT("SpriteCategory", "OpenDriveActor", "OpenDriveActor"))
47 {}
48 } ConstructorStatics;
49
50 // 我们需要一个场景组件来附加 Icon sprite
51 USceneComponent *SceneComponent =
52 ObjectInitializer.CreateDefaultSubobject<USceneComponent>(this, TEXT("SceneComp"));
53 RootComponent = SceneComponent;
54 RootComponent->Mobility = EComponentMobility::Static;
55
56#if WITH_EDITORONLY_DATA
58 ObjectInitializer.CreateEditorOnlyDefaultSubobject<UBillboardComponent>(this, TEXT("Sprite"));
60 {
61 // 从辅助类对象中获取sprite纹理。
62 SpriteComponent->Sprite = ConstructorStatics.TextureObject.Get();
63 // 分配sprite类别名称。
64 SpriteComponent->SpriteInfo.Category = ConstructorStatics.Category;
65 // 设置sprite显示名称
66 SpriteComponent->SpriteInfo.DisplayName = ConstructorStatics.Name;
67 // 将sprite附加到场景组件。
68 SpriteComponent->SetupAttachment(RootComponent);
69 SpriteComponent->Mobility = EComponentMobility::Static;
70 SpriteComponent->SetEditorScale(1.f);
71 }
72#endif // WITH_EDITORONLY_DATA
73}
74
75// 如果编译器配置为使用编辑器(即在编辑器环境中)
76#if WITH_EDITOR
77// AOpenDriveActor类的成员函数,用于处理属性更改后的事件
78void AOpenDriveActor::PostEditChangeProperty(struct FPropertyChangedEvent &Event)
79{
80 // 调用父类的PostEditChangeProperty函数
81 Super::PostEditChangeProperty(Event);
82
83 // 获取发生更改的属性名称
84 const FName PropertyName = (Event.Property != NULL ? Event.Property->GetFName() : NAME_None);
85 // 如果更改的属性是bGenerateRoutes
86 if (PropertyName == GET_MEMBER_NAME_CHECKED(AOpenDriveActor, bGenerateRoutes))
87 {
88 // 如果bGenerateRoutes被设置为true
89 if (bGenerateRoutes)
90 {
91 bGenerateRoutes = false;
92
93 RemoveRoutes(); // 移除现有的路线,避免OpenDrive重叠避免OpenDrive重叠
94 RemoveSpawners(); // 如果OpenDRIVE发生了变化,则重新启动生成器。
95 BuildRoutes();// 构建新的路线
96
97 // 如果bAddSpawners为true,则添加生成器
98 if (bAddSpawners)
99 {
100 AddSpawners();
101 }
102 // 如果bShowDebug为true,则显示调试信息
103 if (bShowDebug)
104 {
105 DebugRoutes();
106 }
107 }
108 }
109 // 如果更改的属性是bRemoveRoutes
110 if (PropertyName == GET_MEMBER_NAME_CHECKED(AOpenDriveActor, bRemoveRoutes))
111 {
112 // 如果bRemoveRoutes被设置为true
113 if (bRemoveRoutes)
114 {
115 // 将bRemoveRoutes设置为false,以避免重复执行
116 bRemoveRoutes = false;
117
118 RemoveDebugRoutes();// 移除调试路线
119 RemoveSpawners();// 移除生成器
120 RemoveRoutes(); // 移除路线
121 }
122 }
123 // 如果更改的属性是bShowDebug
124 if (PropertyName == GET_MEMBER_NAME_CHECKED(AOpenDriveActor, bShowDebug))
125 {
126 // 如果bShowDebug被设置为true,则显示调试信息
127 if (bShowDebug)
128 {
129 DebugRoutes();
130 }
131 // 如果bShowDebug被设置为false,则移除调试信息
132 else
133 {
135 }
136 }
137 // 如果更改的属性是bRemoveCurrentSpawners
138 if (PropertyName == GET_MEMBER_NAME_CHECKED(AOpenDriveActor, bRemoveCurrentSpawners))
139 {
140 // 如果bRemoveCurrentSpawners被设置为true
141 if (bRemoveCurrentSpawners)
142 {
143 // 将bRemoveCurrentSpawners设置为false,以避免重复执行
144 bRemoveCurrentSpawners = false;
145
146 // 移除生成器
148 }
149 }
150}
151#endif // WITH_EDITOR
152
154{
155 BuildRoutes(GetWorld()->GetMapName());
156}
157
158void AOpenDriveActor::BuildRoutes(FString MapName)
159{
160 using Waypoint = carla::road::element::Waypoint;
161
162 // 由于OpenDRIVE文件与关卡名称相同,因此使用关卡名称和游戏内容目录构建xodr文件的路径。
163 const FString XodrContent = UOpenDrive::LoadXODR(MapName);
164
165 auto map = carla::opendrive::OpenDriveParser::Load(carla::rpc::FromLongFString(XodrContent));
166
167 if (!map.has_value())
168 {
169 UE_LOG(LogCarla, Error, TEXT("Failed to parse OpenDrive file."));
170 return;
171 }
172
173 // 包含地图每条车道末端路点的一个列表
174 const std::vector<Waypoint> LaneWaypoints =
175 map->GenerateWaypointsOnRoadEntries();
176
177 std::unordered_map<Waypoint, std::vector<Waypoint>> PredecessorMap;
178
179 for (auto &Wp : LaneWaypoints)
180 {
181 const auto PredecessorsList = map->GetPredecessors(Wp);
182 if (PredecessorsList.empty())
183 {
184 continue;
185 }
186 const auto MinRoadId = *std::min_element(
187 PredecessorsList.begin(),
188 PredecessorsList.end(),
189 [](const auto &WaypointA, const auto &WaypointB) {
190 return WaypointA.road_id < WaypointB.road_id;
191 });
192 PredecessorMap[MinRoadId].emplace_back(Wp);
193 }
194
195 for (auto &&PredecessorWp : PredecessorMap)
196 {
197 ARoutePlanner *RoutePlanner = nullptr;
198
199 for (auto &&Wp : PredecessorWp.second)
200 {
201 std::vector<Waypoint> Waypoints;
202 auto CurrentWp = Wp;
203
204 do
205 {
206 Waypoints.emplace_back(CurrentWp);
207 const auto Successors = map->GetNext(CurrentWp, RoadAccuracy);
208 if (Successors.empty())
209 {
210 break;
211 }
212 if (Successors.front().road_id != Wp.road_id)
213 {
214 break;
215 }
216 CurrentWp = Successors.front();
217 } while (CurrentWp.road_id == Wp.road_id);
218
219 // 将当前道路的最后一个路点连接到下一条道路的第一个路点。
220 const auto FollowingWp = map->GetSuccessors(CurrentWp);
221 if (!FollowingWp.empty())
222 {
223 Waypoints.emplace_back(FollowingWp.front());
224 }
225
226 if (Waypoints.size() >= 2)
227 {
228 TArray<FVector> Positions;
229 Positions.Reserve(Waypoints.size());
230 for (int i = 0; i < Waypoints.size(); ++i)
231 {
232 // 添加触发器高度,因为点的Z坐标不影响驾驶员AI,并且在编辑器中易于可视化。
233 Positions.Add(map->ComputeTransform(Waypoints[i]).location +
234 FVector(0.f, 0.f, TriggersHeight));
235 }
236
237 // 如果路线规划器不存在,则创建它。
238 if (RoutePlanner == nullptr )
239 {
240 const auto WpTransform = map->ComputeTransform(Wp);
241 RoutePlanner = GetWorld()->SpawnActor<ARoutePlanner>();
242 RoutePlanner->bIsIntersection = map->IsJunction(Wp.road_id);
243 RoutePlanner->SetBoxExtent(FVector(70.f, 70.f, 50.f));
244 RoutePlanner->SetActorRotation(WpTransform.rotation);
245 RoutePlanner->SetActorLocation(WpTransform.location +
246 FVector(0.f, 0.f, TriggersHeight));
247 }
248
249 if (RoutePlanner != nullptr)
250 {
251 RoutePlanner->AddRoute(1.f, Positions);
252 RoutePlanners.Add(RoutePlanner);
253 }
254 }
255 }
256 }
257}
258
260{
261 const int rp_num = RoutePlanners.Num();
262 for (int i = 0; i < rp_num; i++)
263 {
264 if (RoutePlanners[i] != nullptr)
265 {
266 RoutePlanners[i]->Destroy();
267 }
268 }
269 RoutePlanners.Empty();
270}
271
273{
274 for (int i = 0; i < RoutePlanners.Num(); ++i)
275 {
276 if (RoutePlanners[i] != nullptr)
277 {
278 RoutePlanners[i]->DrawRoutes();
279 }
280 }
281}
282
284{
285#if WITH_EDITOR
286 FlushPersistentDebugLines(GetWorld());
287#endif // WITH_EDITOR
288}
289
291{
292 for (int i = 0; i < RoutePlanners.Num(); ++i)
293 {
294 if (RoutePlanners[i] != nullptr)
295 {
296 if (!bOnIntersections && RoutePlanners[i]->bIsIntersection)
297 {
298 continue;
299 }
300 else
301 {
302 FTransform Trans = RoutePlanners[i]->GetActorTransform();
303 AVehicleSpawnPoint *Spawner = GetWorld()->SpawnActor<AVehicleSpawnPoint>();
304 Spawner->SetActorRotation(Trans.GetRotation());
305 Spawner->SetActorLocation(Trans.GetTranslation() + FVector(0.f, 0.f, SpawnersHeight));
306 VehicleSpawners.Add(Spawner);
307 }
308 }
309 }
310}
311
313{
314 const int vs_num = VehicleSpawners.Num();
315 for (int i = 0; i < vs_num; i++)
316 {
317 if (VehicleSpawners[i] != nullptr)
318 {
319 VehicleSpawners[i]->Destroy();
320 }
321 }
322 VehicleSpawners.Empty();
323}
UE_LOG(LogCarla, Log, TEXT("UActorDispatcher::Destroying actor: '%s' %x"), *Id, Actor)
float TriggersHeight
触发器的高程
float SpawnersHeight
确定生成器放置的高度,相对于每个RoutePlanner。
AOpenDriveActor(const FObjectInitializer &ObjectInitializer)
bool bOnIntersections
如果为true,在交叉路口也放置生成器
float RoadAccuracy
车辆行驶的路径点之间的距离。
bool bAddSpawners
如果编译时包含编辑器数据。
void RemoveRoutes()
根据地图名称构建路径
UBillboardComponent * SpriteComponent
Billboard组件用于显示图标精灵。
void BuildRoutes()
构造函数
void DebugRoutes() const
TArray< ARoutePlanner * > RoutePlanners
TArray< AVehicleSpawnPoint * > VehicleSpawners
定义一个数组属性,存储VehicleSpawnPoint对象
void RemoveDebugRoutes() const
为每个进入触发体积的 ACarlaWheeledVehicle 分配一条随机路线。 将此参与者放入世界后,必须在编辑器中添加路线。样条线切线将被忽略,仅考虑位置来制定路线。
void AddRoute(float probability, const TArray< FVector > &routePoints)
void SetBoxExtent(const FVector &Extent)
Base class for spawner locations for walkers.
static boost::optional< road::Map > Load(const std::string &opendrive)