CARLA
 
载入中...
搜索中...
未找到
RoutePlanner.cpp
浏览该文件的文档.
1// Copyright (c) 2017 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"
8#include "RoutePlanner.h"
9
10#include "Util/RandomEngine.h"
13
14#include "Engine/CollisionProfile.h"
15#include "DrawDebugHelpers.h"
16
17static bool IsSplineValid(const USplineComponent *SplineComponent)
18{
19 return (SplineComponent != nullptr) &&
20 (SplineComponent->GetNumberOfSplinePoints() > 1);
21}
22
24{
25 auto *Vehicle = (Actor->IsPendingKill() ? nullptr : Cast<ACarlaWheeledVehicle>(Actor));
26 return (Vehicle != nullptr ?
27 Cast<AWheeledVehicleAIController>(Vehicle->GetController()) :
28 nullptr);
29}
30
31static const USplineComponent *PickARoute(
32 URandomEngine &RandomEngine,
33 const TArray<USplineComponent *> &Routes,
34 const TArray<float> &Probabilities)
35{
36 check(Routes.Num() > 0);
37
38 if (Routes.Num() == 1)
39 {
40 return Routes[0];
41 }
42
43 auto Index = RandomEngine.GetIntWithWeight(Probabilities);
44 check((Index >= 0) && (Index < Routes.Num()));
45 return Routes[Index];
46}
47
48ARoutePlanner::ARoutePlanner(const FObjectInitializer &ObjectInitializer)
49 : Super(ObjectInitializer)
50{
51 RootComponent =
52 ObjectInitializer.CreateDefaultSubobject<USceneComponent>(this, TEXT("SceneRootComponent"));
53 RootComponent->SetMobility(EComponentMobility::Static);
54
55 TriggerVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("TriggerVolume"));
56 TriggerVolume->SetupAttachment(RootComponent);
57 TriggerVolume->SetHiddenInGame(true);
58 TriggerVolume->SetMobility(EComponentMobility::Static);
59 TriggerVolume->SetCollisionProfileName(FName("OverlapAll"));
60 TriggerVolume->SetGenerateOverlapEvents(true);
61
62 // Do not change default value here, our autopilot depends on this.
63 TriggerVolume->SetBoxExtent(FVector{32.0f, 32.0f, 32.0f});
64}
65
67{
68 CleanRoute();
69 Super::BeginDestroy();
70}
71
72#if WITH_EDITOR
73void ARoutePlanner::PostEditChangeProperty(FPropertyChangedEvent &PropertyChangedEvent)
74{
75 Super::PostEditChangeProperty(PropertyChangedEvent);
76 const auto Size = Routes.Num();
77 if (PropertyChangedEvent.Property && (Size != Probabilities.Num()))
78 {
79 Probabilities.Reset(Size);
80 for (auto i = 0; i < Size; ++i)
81 {
82 Probabilities.Add(1.0f / static_cast<float>(Size));
83 if (Routes[i] == nullptr)
84 {
85 Routes[i] = NewObject<USplineComponent>(this);
86 Routes[i]->SetupAttachment(RootComponent);
87 Routes[i]->SetHiddenInGame(true);
88 Routes[i]->SetMobility(EComponentMobility::Static);
89 Routes[i]->RegisterComponent();
90 }
91 }
92 }
93}
94#endif // WITH_EDITOR
95
96void ARoutePlanner::AddRoute(float probability, const TArray<FVector> &routePoints)
97{
98 USplineComponent *NewSpline = NewObject<USplineComponent>(this);
99 NewSpline->bHiddenInGame = true;
100
101 #if WITH_EDITOR
102 NewSpline->EditorUnselectedSplineSegmentColor = FLinearColor(1.f, 0.15f, 0.15f);
103 #endif // WITH_EDITOR
104
105 NewSpline->SetLocationAtSplinePoint(0, routePoints[0], ESplineCoordinateSpace::World, true);
106 NewSpline->SetLocationAtSplinePoint(1, routePoints[1], ESplineCoordinateSpace::World, true);
107
108 for (int i = 2; i < routePoints.Num(); ++i)
109 {
110 NewSpline->AddSplinePoint(routePoints[i], ESplineCoordinateSpace::World, true);
111 }
112
113 Routes.Add(NewSpline);
114 Probabilities.Add(probability);
115}
116
118{
119 Routes.Empty();
120 Probabilities.Empty();
121}
122
124{
125 if (!Controller.IsPendingKill() && (Controller.GetRandomEngine() != nullptr))
126 {
127 auto *RandomEngine = Controller.GetRandomEngine();
128 auto *Route = PickARoute(*RandomEngine, Routes, Probabilities);
129
130 TArray<FVector> WayPoints;
131 const auto Size = Route->GetNumberOfSplinePoints();
132 if (Size > 1)
133 {
134 WayPoints.Reserve(Size);
135 for (auto i = 1; i < Size; ++i)
136 {
137 WayPoints.Add(Route->GetLocationAtSplinePoint(i, ESplineCoordinateSpace::World));
138 }
139
140 Controller.SetFixedRoute(WayPoints);
141 }
142 else
143 {
144 UE_LOG(LogCarla, Error, TEXT("ARoutePlanner '%s' has a route with zero way-points."), *GetName());
145 }
146 }
147
148}
149
151{
152 if (Routes.Num() < 1)
153 {
154 UE_LOG(LogCarla, Warning, TEXT("ARoutePlanner '%s' has no route assigned."), *GetName());
155 return;
156 }
157
158 for (auto &&Route : Routes)
159 {
160 if (!IsSplineValid(Route))
161 {
162 UE_LOG(LogCarla, Error, TEXT("ARoutePlanner '%s' has a route with zero way-points."), *GetName());
163 return;
164 }
165 }
166
167 // Register delegate on begin overlap.
168 if (!TriggerVolume->OnComponentBeginOverlap.IsAlreadyBound(this, &ARoutePlanner::OnTriggerBeginOverlap))
169 {
170 TriggerVolume->OnComponentBeginOverlap.AddDynamic(this, &ARoutePlanner::OnTriggerBeginOverlap);
171 }
172}
173
175{
176 Super::BeginPlay();
177 Init();
178}
179
180void ARoutePlanner::EndPlay(const EEndPlayReason::Type EndPlayReason)
181{
182 // Deregister the delegate.
183 if (TriggerVolume->OnComponentBeginOverlap.IsAlreadyBound(this, &ARoutePlanner::OnTriggerBeginOverlap))
184 {
185 TriggerVolume->OnComponentBeginOverlap.RemoveDynamic(this, &ARoutePlanner::OnTriggerBeginOverlap);
186 }
187
188 Super::EndPlay(EndPlayReason);
189}
190
192 UPrimitiveComponent * /*OverlappedComp*/,
193 AActor *OtherActor,
194 UPrimitiveComponent * /*OtherComp*/,
195 int32 /*OtherBodyIndex*/,
196 bool /*bFromSweep*/,
197 const FHitResult & /*SweepResult*/)
198{
199 auto *Controller = GetVehicleController(OtherActor);
200 if (Controller != nullptr)
201 {
202 AssignRandomRoute(*Controller);
203 }
204}
205
207{
208#if WITH_EDITOR
209 for (int i = 0, lenRoutes = Routes.Num(); i < lenRoutes; ++i)
210 {
211 for (int j = 0, lenNumPoints = Routes[i]->GetNumberOfSplinePoints() - 1; j < lenNumPoints; ++j)
212 {
213 const FVector p0 = Routes[i]->GetLocationAtSplinePoint(j + 0, ESplineCoordinateSpace::World);
214 const FVector p1 = Routes[i]->GetLocationAtSplinePoint(j + 1, ESplineCoordinateSpace::World);
215
216 static const float MinThickness = 3.f;
217 static const float MaxThickness = 15.f;
218
219 const float Dist = (float) j / (float) lenNumPoints;
220 const float OneMinusDist = 1.f - Dist;
221 const float Thickness = OneMinusDist * MaxThickness + MinThickness;
222
223 if (bIsIntersection)
224 {
225 // from blue to black
226 DrawDebugLine(
227 GetWorld(), p0, p1, FColor(0, 0, 255 * OneMinusDist),
228 true, -1.f, 0, Thickness);
229 }
230 else
231 {
232 // from green to black
233 DrawDebugLine(
234 GetWorld(), p0, p1, FColor(0, 255 * OneMinusDist, 0),
235 true, -1.f, 0, Thickness);
236 }
237 }
238 }
239#endif
240}
static AWheeledVehicleAIController * GetVehicleController(AActor *Actor)
static bool IsSplineValid(const USplineComponent *SplineComponent)
static const USplineComponent * PickARoute(URandomEngine &RandomEngine, const TArray< USplineComponent * > &Routes, const TArray< float > &Probabilities)
virtual void BeginPlay() override
virtual void BeginDestroy() override
void AddRoute(float probability, const TArray< FVector > &routePoints)
UBoxComponent * TriggerVolume
ARoutePlanner(const FObjectInitializer &ObjectInitializer)
void AssignRandomRoute(AWheeledVehicleAIController &Controller) const
void OnTriggerBeginOverlap(UPrimitiveComponent *OverlappedComp, AActor *OtherActor, UPrimitiveComponent *OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult &SweepResult)
TArray< USplineComponent * > Routes
TArray< float > Probabilities
virtual void EndPlay(EEndPlayReason::Type EndPlayReason) override
Wheeled vehicle controller with optional AI.
void SetFixedRoute(const TArray< FVector > &Locations, bool bOverwriteCurrent=true)
Set a fixed route to follow if autopilot is enabled.
int32 GetIntWithWeight(const TArray< float > &Weights)