CARLA
RoutePlanner.cpp
Go to the documentation of this file.
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 
17 static 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 
31 static 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 
48 ARoutePlanner::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
73 void 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 
96 void 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 
180 void 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 }
void SetFixedRoute(const TArray< FVector > &Locations, bool bOverwriteCurrent=true)
Set a fixed route to follow if autopilot is enabled.
void AssignRandomRoute(AWheeledVehicleAIController &Controller) const
virtual void BeginPlay() override
ARoutePlanner(const FObjectInitializer &ObjectInitializer)
virtual void BeginDestroy() override
static AWheeledVehicleAIController * GetVehicleController(AActor *Actor)
static bool IsSplineValid(const USplineComponent *SplineComponent)
carla::SharedPtr< cc::Actor > Actor
Wheeled vehicle controller with optional AI.
void AddRoute(float probability, const TArray< FVector > &routePoints)
std::vector< uint8_t > Route
TArray< USplineComponent * > Routes
Definition: RoutePlanner.h:74
int32 GetIntWithWeight(const TArray< float > &Weights)
Definition: RandomEngine.h:128
bool bIsIntersection
Definition: RoutePlanner.h:80
static const USplineComponent * PickARoute(URandomEngine &RandomEngine, const TArray< USplineComponent *> &Routes, const TArray< float > &Probabilities)
UBoxComponent * TriggerVolume
Definition: RoutePlanner.h:71
void OnTriggerBeginOverlap(UPrimitiveComponent *OverlappedComp, AActor *OtherActor, UPrimitiveComponent *OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult &SweepResult)
virtual void EndPlay(EEndPlayReason::Type EndPlayReason) override
TArray< float > Probabilities
Definition: RoutePlanner.h:77