CARLA
TrafficLightManager.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020 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 "TrafficLightManager.h"
8 #include "Game/CarlaStatics.h"
9 #include "StopSignComponent.h"
10 #include "YieldSignComponent.h"
11 #include "SpeedLimitComponent.h"
12 #include "Components/BoxComponent.h"
13 #include "Runtime/CoreUObject/Public/UObject/ConstructorHelpers.h"
14 
15 #include "UObject/ConstructorHelpers.h"
16 
18 #include <carla/rpc/String.h>
19 #include <carla/road/SignalType.h>
22 
23 #include <string>
24 
26 {
27  PrimaryActorTick.bCanEverTick = false;
28  SceneComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
29  RootComponent = SceneComponent;
30 
31  // Hard codded default traffic light blueprint
32  static ConstructorHelpers::FClassFinder<AActor> TrafficLightFinder(
33  TEXT( "/Game/Carla/Blueprints/TrafficLight/BP_TLOpenDrive" ) );
34  if (TrafficLightFinder.Succeeded())
35  {
36  TSubclassOf<AActor> Model = TrafficLightFinder.Class;
37  TrafficLightModel = Model;
38  }
39  // Default traffic signs models
40  static ConstructorHelpers::FClassFinder<AActor> StopFinder(
41  TEXT( "/Game/Carla/Static/TrafficSign/BP_Stop" ) );
42  if (StopFinder.Succeeded())
43  {
44  TSubclassOf<AActor> StopSignModel = StopFinder.Class;
45  TrafficSignsModels.Add(carla::road::SignalType::StopSign().c_str(), StopSignModel);
46  SignComponentModels.Add(carla::road::SignalType::StopSign().c_str(), UStopSignComponent::StaticClass());
47  }
48  static ConstructorHelpers::FClassFinder<AActor> YieldFinder(
49  TEXT( "/Game/Carla/Static/TrafficSign/BP_Yield" ) );
50  if (YieldFinder.Succeeded())
51  {
52  TSubclassOf<AActor> YieldSignModel = YieldFinder.Class;
53  TrafficSignsModels.Add(carla::road::SignalType::YieldSign().c_str(), YieldSignModel);
54  SignComponentModels.Add(carla::road::SignalType::YieldSign().c_str(), UYieldSignComponent::StaticClass());
55  }
56  static ConstructorHelpers::FClassFinder<AActor> SpeedLimit30Finder(
57  TEXT( "/Game/Carla/Static/TrafficSign/BP_SpeedLimit30" ) );
58  if (SpeedLimit30Finder.Succeeded())
59  {
60  TSubclassOf<AActor> SpeedLimitModel = SpeedLimit30Finder.Class;
61  SpeedLimitModels.Add("30", SpeedLimitModel);
62  }
63  static ConstructorHelpers::FClassFinder<AActor> SpeedLimit40Finder(
64  TEXT( "/Game/Carla/Static/TrafficSign/BP_SpeedLimit40" ) );
65  if (SpeedLimit40Finder.Succeeded())
66  {
67  TSubclassOf<AActor> SpeedLimitModel = SpeedLimit40Finder.Class;
68  SpeedLimitModels.Add("40", SpeedLimitModel);
69  }
70  static ConstructorHelpers::FClassFinder<AActor> SpeedLimit50Finder(
71  TEXT( "/Game/Carla/Static/TrafficSign/BP_SpeedLimit50" ) );
72  if (SpeedLimit50Finder.Succeeded())
73  {
74  TSubclassOf<AActor> SpeedLimitModel = SpeedLimit50Finder.Class;
75  SpeedLimitModels.Add("50", SpeedLimitModel);
76  }
77  static ConstructorHelpers::FClassFinder<AActor> SpeedLimit60Finder(
78  TEXT( "/Game/Carla/Static/TrafficSign/BP_SpeedLimit60" ) );
79  if (SpeedLimit60Finder.Succeeded())
80  {
81  TSubclassOf<AActor> SpeedLimitModel = SpeedLimit60Finder.Class;
82  SpeedLimitModels.Add("60", SpeedLimitModel);
83  }
84  static ConstructorHelpers::FClassFinder<AActor> SpeedLimit70Finder(
85  TEXT( "/Game/Carla/Static/TrafficSign/BP_SpeedLimit70" ) );
86  if (SpeedLimit70Finder.Succeeded())
87  {
88  TSubclassOf<AActor> SpeedLimitModel = SpeedLimit70Finder.Class;
89  SpeedLimitModels.Add("70", SpeedLimitModel);
90  }
91  static ConstructorHelpers::FClassFinder<AActor> SpeedLimit80Finder(
92  TEXT( "/Game/Carla/Static/TrafficSign/BP_SpeedLimit80" ) );
93  if (SpeedLimit80Finder.Succeeded())
94  {
95  TSubclassOf<AActor> SpeedLimitModel = SpeedLimit80Finder.Class;
96  SpeedLimitModels.Add("80", SpeedLimitModel);
97  }
98  static ConstructorHelpers::FClassFinder<AActor> SpeedLimit90Finder(
99  TEXT( "/Game/Carla/Static/TrafficSign/BP_SpeedLimit90" ) );
100  if (SpeedLimit90Finder.Succeeded())
101  {
102  TSubclassOf<AActor> SpeedLimitModel = SpeedLimit90Finder.Class;
103  SpeedLimitModels.Add("90", SpeedLimitModel);
104  }
105  static ConstructorHelpers::FClassFinder<AActor> SpeedLimit100Finder(
106  TEXT( "/Game/Carla/Static/TrafficSign/BP_SpeedLimit100" ) );
107  if (SpeedLimit100Finder.Succeeded())
108  {
109  TSubclassOf<AActor> SpeedLimitModel = SpeedLimit100Finder.Class;
110  SpeedLimitModels.Add("100", SpeedLimitModel);
111  }
112  static ConstructorHelpers::FClassFinder<AActor> SpeedLimit110Finder(
113  TEXT( "/Game/Carla/Static/TrafficSign/BP_SpeedLimit110" ) );
114  if (SpeedLimit110Finder.Succeeded())
115  {
116  TSubclassOf<AActor> SpeedLimitModel = SpeedLimit110Finder.Class;
117  SpeedLimitModels.Add("110", SpeedLimitModel);
118  }
119  static ConstructorHelpers::FClassFinder<AActor> SpeedLimit120Finder(
120  TEXT( "/Game/Carla/Static/TrafficSign/BP_SpeedLimit120" ) );
121  if (SpeedLimit120Finder.Succeeded())
122  {
123  TSubclassOf<AActor> SpeedLimitModel = SpeedLimit120Finder.Class;
124  SpeedLimitModels.Add("120", SpeedLimitModel);
125  }
127 }
128 
129 void ATrafficLightManager::RegisterLightComponentFromOpenDRIVE(UTrafficLightComponent * TrafficLightComponent)
130 {
132  check(GM);
133 
134  // Cast to std::string
135  carla::road::SignId SignId(TCHAR_TO_UTF8(*(TrafficLightComponent->GetSignId())));
136 
137  ATrafficLightGroup* TrafficLightGroup;
138  UTrafficLightController* TrafficLightController;
139 
140  const auto &Signal = GetMap()->GetSignals().at(SignId);
141  if(Signal->GetControllers().size())
142  {
143  // Only one controller per signal
144  auto ControllerId = *(Signal->GetControllers().begin());
145 
146  // Get controller
147  const auto &Controller = GetMap()->GetControllers().at(ControllerId);
148  if(Controller->GetJunctions().empty())
149  {
150  UE_LOG(LogCarla, Error, TEXT("No junctions in controller %d"), *(ControllerId.c_str()) );
151  return;
152  }
153  // Get junction of the controller
154  auto JunctionId = *(Controller->GetJunctions().begin());
155 
156  // Search/create TrafficGroup (junction traffic light manager)
157  if(!TrafficGroups.Contains(JunctionId))
158  {
159  FActorSpawnParameters SpawnParams;
160  SpawnParams.OverrideLevel = GM->GetULevelFromName("TrafficLights");
161  auto * NewTrafficLightGroup =
162  GetWorld()->SpawnActor<ATrafficLightGroup>(SpawnParams);
163  NewTrafficLightGroup->JunctionId = JunctionId;
164  TrafficGroups.Add(JunctionId, NewTrafficLightGroup);
165  }
166  TrafficLightGroup = TrafficGroups[JunctionId];
167 
168  // Search/create controller in the junction
169  if(!TrafficControllers.Contains(ControllerId.c_str()))
170  {
171  auto *NewTrafficLightController = NewObject<UTrafficLightController>();
172  NewTrafficLightController->SetControllerId(ControllerId.c_str());
173  TrafficLightGroup->AddController(NewTrafficLightController);
174  TrafficControllers.Add(ControllerId.c_str(), NewTrafficLightController);
175  }
176  TrafficLightController = TrafficControllers[ControllerId.c_str()];
177  }
178  else
179  {
180  FActorSpawnParameters SpawnParams;
181  SpawnParams.OverrideLevel = GM->GetULevelFromName("TrafficLights");
182  auto * NewTrafficLightGroup =
183  GetWorld()->SpawnActor<ATrafficLightGroup>(SpawnParams);
184  NewTrafficLightGroup->JunctionId = TrafficLightGroupMissingId;
185  TrafficGroups.Add(NewTrafficLightGroup->JunctionId, NewTrafficLightGroup);
186  TrafficLightGroup = NewTrafficLightGroup;
187 
188  auto *NewTrafficLightController = NewObject<UTrafficLightController>();
189  NewTrafficLightController->SetControllerId(FString::FromInt(TrafficLightControllerMissingId));
190  // Set red time longer than the default 2s
191  NewTrafficLightController->SetRedTime(10);
192  TrafficLightGroup->GetControllers().Add(NewTrafficLightController);
193  TrafficControllers.Add(NewTrafficLightController->GetControllerId(), NewTrafficLightController);
194  TrafficLightController = NewTrafficLightController;
195 
198  }
199 
200  // Add signal to controller
201  TrafficLightController->AddTrafficLight(TrafficLightComponent);
202  TrafficLightController->ResetState();
203 
204  // Add signal to map
205  TrafficSignComponents.Add(TrafficLightComponent->GetSignId(), TrafficLightComponent);
206 
207  TrafficLightGroup->ResetGroup();
208 
209 }
210 
212 {
213  auto* Controller = TrafficLight->GetController();
214  auto* Group = TrafficLight->GetGroup();
215  if (!Controller || !Group)
216  {
217  UE_LOG(LogCarla, Error, TEXT("Missing group or controller for traffic light"));
218  return;
219  }
220  if (TrafficLight->GetSignId() == "")
221  {
222  TrafficLight->SetSignId(FString::FromInt(TrafficLightComponentMissingId));
224  }
225  if (Controller->GetControllerId() == "")
226  {
227  Controller->SetControllerId(FString::FromInt(TrafficLightControllerMissingId));
229  }
230  if (Group->GetJunctionId() == -1)
231  {
232  Group->JunctionId = TrafficLightGroupMissingId;
234  }
235 
236  if (!TrafficControllers.Contains(Controller->GetControllerId()))
237  {
238  TrafficControllers.Add(Controller->GetControllerId(), Controller);
239  }
240  if (!TrafficGroups.Contains(Group->GetJunctionId()))
241  {
242  TrafficGroups.Add(Group->GetJunctionId(), Group);
243  }
244  if (!TrafficSignComponents.Contains(TrafficLight->GetSignId()))
245  {
246  TrafficSignComponents.Add(TrafficLight->GetSignId(), TrafficLight);
247  }
248 }
249 
250 const boost::optional<carla::road::Map>& ATrafficLightManager::GetMap()
251 {
252  return UCarlaStatics::GetGameMode(GetWorld())->GetMap();
253 }
254 
256 {
258  {
259  if(!TrafficLightModel)
260  {
261  UE_LOG(LogCarla, Error, TEXT("Missing TrafficLightModel"));
262  return;
263  }
264 
266 
268 
269  SpawnSignals();
270 
271  TrafficLightsGenerated = true;
272  }
273 }
274 
276 {
277  for(auto& Sign : TrafficSigns)
278  {
279  Sign->Destroy();
280  }
281  TrafficSigns.Empty();
282 
283  for(auto& TrafficGroup : TrafficGroups)
284  {
285  TrafficGroup.Value->Destroy();
286  }
287  TrafficGroups.Empty();
288 
289  TrafficControllers.Empty();
290 
291  TrafficLightsGenerated = false;
292 }
293 
295 {
296  TArray<AActor*> Actors;
297  UGameplayStatics::GetAllActorsOfClass(GetWorld(), ATrafficLightBase::StaticClass(), Actors);
298 
299  std::string opendrive_xml = carla::rpc::FromFString(UOpenDrive::GetXODR(GetWorld()));
300  auto Map = carla::opendrive::OpenDriveParser::Load(opendrive_xml);
301 
302  if (!Map)
303  {
304  carla::log_warning("Map not found");
305  return;
306  }
307 
308  TArray<ATrafficLightBase*> TrafficLights;
309  for (AActor* Actor : Actors)
310  {
311  ATrafficLightBase* TrafficLight = Cast<ATrafficLightBase>(Actor);
312  if (TrafficLight)
313  {
314  TrafficLight->GetTrafficLightComponent()->SetSignId("");
315  TrafficLights.Add(TrafficLight);
316  }
317  }
318 
319  if (!TrafficLights.Num())
320  {
321  carla::log_warning("No actors in the map");
322  return;
323  }
324 
325  const auto& Signals = Map->GetSignals();
326  const auto& Controllers = Map->GetControllers();
327 
328  for(const auto& Signal : Signals) {
329  const auto& ODSignal = Signal.second;
330  const FTransform Transform = ODSignal->GetTransform();
331  const FVector Location = Transform.GetLocation();
332  if (ODSignal->GetName() == "")
333  {
334  continue;
335  }
336  ATrafficLightBase* ClosestActor = TrafficLights.Top();
337  float MinDistance = FVector::DistSquaredXY(TrafficLights.Top()->GetActorLocation(), Location);
338  for (ATrafficLightBase* Actor : TrafficLights)
339  {
340  float Distance = FVector::DistSquaredXY(Actor->GetActorLocation(), Location);
341  if (Distance < MinDistance)
342  {
343  MinDistance = Distance;
344  ClosestActor = Actor;
345  }
346  }
347  ATrafficLightBase* TrafficLight = ClosestActor;
348  auto* Component = TrafficLight->GetTrafficLightComponent();
349  if (Component->GetSignId() == "")
350  {
351  Component->SetSignId(carla::rpc::ToFString(ODSignal->GetSignalId()));
352  }
353  else
354  {
355  carla::log_warning("Could not find a suitable traffic light for signal", ODSignal->GetSignalId(),
356  "Closest traffic light has id", carla::rpc::FromFString(Component->GetSignId()));
357  }
358 
359  }
360 }
361 
363 {
364 
365  // Should not run in empty maps
366  if (!GetMap())
367  {
368  carla::log_warning("Coud not generate traffic lights: missing map.");
369  return;
370  }
371 
373  {
375  }
376 }
377 
378 bool MatchSignalAndActor(const carla::road::Signal &Signal, ATrafficSignBase* ClosestTrafficSign)
379 {
380  namespace cr = carla::road;
381  if (ClosestTrafficSign)
382  {
383  if ((Signal.GetType() == cr::SignalType::StopSign()) &&
384  ClosestTrafficSign->GetTrafficSignState() == ETrafficSignState::StopSign)
385  {
386  return true;
387  }
388  else if ((Signal.GetType() == cr::SignalType::YieldSign()) &&
389  ClosestTrafficSign->GetTrafficSignState() == ETrafficSignState::YieldSign)
390  {
391  return true;
392  }
393  else if (cr::SignalType::IsTrafficLight(Signal.GetType()))
394  {
395  if (ClosestTrafficSign->GetTrafficSignState() == ETrafficSignState::TrafficLightRed ||
398  return true;
399  }
400  else if (Signal.GetType() == cr::SignalType::MaximumSpeed())
401  {
402  if (Signal.GetSubtype() == "30" &&
403  ClosestTrafficSign->GetTrafficSignState() == ETrafficSignState::SpeedLimit_30)
404  {
405  return true;
406  }
407  else if (Signal.GetSubtype() == "40" &&
408  ClosestTrafficSign->GetTrafficSignState() == ETrafficSignState::SpeedLimit_40)
409  {
410  return true;
411  }
412  else if (Signal.GetSubtype() == "50" &&
413  ClosestTrafficSign->GetTrafficSignState() == ETrafficSignState::SpeedLimit_50)
414  {
415  return true;
416  }
417  else if (Signal.GetSubtype() == "60" &&
418  ClosestTrafficSign->GetTrafficSignState() == ETrafficSignState::SpeedLimit_60)
419  {
420  return true;
421  }
422  else if (Signal.GetSubtype() == "70" &&
423  ClosestTrafficSign->GetTrafficSignState() == ETrafficSignState::SpeedLimit_60)
424  {
425  return true;
426  }
427  else if (Signal.GetSubtype() == "80" &&
428  ClosestTrafficSign->GetTrafficSignState() == ETrafficSignState::SpeedLimit_90)
429  {
430  return true;
431  }
432  else if (Signal.GetSubtype() == "90" &&
433  ClosestTrafficSign->GetTrafficSignState() == ETrafficSignState::SpeedLimit_90)
434  {
435  return true;
436  }
437  else if (Signal.GetSubtype() == "100" &&
438  ClosestTrafficSign->GetTrafficSignState() == ETrafficSignState::SpeedLimit_100)
439  {
440  return true;
441  }
442  else if (Signal.GetSubtype() == "120" &&
443  ClosestTrafficSign->GetTrafficSignState() == ETrafficSignState::SpeedLimit_120)
444  {
445  return true;
446  }
447  else if (Signal.GetSubtype() == "130" &&
448  ClosestTrafficSign->GetTrafficSignState() == ETrafficSignState::SpeedLimit_130)
449  {
450  return true;
451  }
452  }
453  }
454  return false;
455 }
456 
457 template<typename T = ATrafficSignBase>
458 T * GetClosestTrafficSignActor(const carla::road::Signal &Signal, UWorld* World)
459 {
460  auto CarlaTransform = Signal.GetTransform();
461  FTransform UETransform(CarlaTransform);
462  FVector Location = UETransform.GetLocation();
463  // max distance to match 500cm
464  constexpr float MaxDistanceMatchSqr = 250000.0;
465  T * ClosestTrafficSign = nullptr;
466  TArray<AActor*> Actors;
467  UGameplayStatics::GetAllActorsOfClass(World, T::StaticClass(), Actors);
468  float MinDistance = MaxDistanceMatchSqr;
469  for (AActor* Actor : Actors)
470  {
471  float Dist = FVector::DistSquared(Actor->GetActorLocation(), Location);
472  T * TrafficSign = Cast<T>(Actor);
473  if (Dist < MinDistance && MatchSignalAndActor(Signal, TrafficSign))
474  {
475  ClosestTrafficSign = TrafficSign;
476  MinDistance = Dist;
477  }
478  }
479  return ClosestTrafficSign;
480 }
481 
483 {
484  namespace cr = carla::road;
485  const auto& Signals = GetMap()->GetSignals();
486  std::unordered_set<std::string> SignalsToSpawn;
487  for(const auto& ControllerPair : GetMap()->GetControllers())
488  {
489  const auto& Controller = ControllerPair.second;
490  for(const auto& SignalId : Controller->GetSignals())
491  {
492  auto& Signal = Signals.at(SignalId);
493  if (!cr::SignalType::IsTrafficLight(Signal->GetType()))
494  {
495  continue;
496  }
497  ATrafficLightBase * TrafficLight = GetClosestTrafficSignActor<ATrafficLightBase>(
498  *Signal.get(), GetWorld());
499  if (TrafficLight)
500  {
501  UTrafficLightComponent *TrafficLightComponent = TrafficLight->GetTrafficLightComponent();
502  TrafficLightComponent->SetSignId(SignalId.c_str());
503  }
504  else
505  {
506  SignalsToSpawn.insert(SignalId);
507  }
508  }
509  }
510 
511  for(const auto& SignalPair : Signals)
512  {
513  const auto& SignalId = SignalPair.first;
514  const auto& Signal = SignalPair.second;
515  if(!Signal->GetControllers().size() &&
516  !GetMap()->IsJunction(Signal->GetRoadId()) &&
517  carla::road::SignalType::IsTrafficLight(Signal->GetType()) &&
518  !SignalsToSpawn.count(SignalId))
519  {
520  ATrafficLightBase * TrafficLight = GetClosestTrafficSignActor<ATrafficLightBase>(
521  *Signal.get(), GetWorld());
522  if (TrafficLight)
523  {
524  UTrafficLightComponent *TrafficLightComponent = TrafficLight->GetTrafficLightComponent();
525  TrafficLightComponent->SetSignId(SignalId.c_str());
526  }
527  else
528  {
529  SignalsToSpawn.insert(SignalId);
530  }
531  }
532  }
533 
535  check(GM);
536  for(auto &SignalId : SignalsToSpawn)
537  {
538  // TODO: should this be an assert?
539  // RELEASE_ASSERT(
540  // Signals.count(SignalId) > 0,
541  // "Reference to inexistent signal. Possible OpenDRIVE error.");
542  if (Signals.count(SignalId) == 0)
543  {
544  UE_LOG(LogCarla, Warning,
545  TEXT("Possible OpenDRIVE error, reference to nonexistent signal id: %s"),
546  *carla::rpc::ToFString(SignalId));
547  continue;
548  }
549  const auto& Signal = Signals.at(SignalId);
550  auto CarlaTransform = Signal->GetTransform();
551  FTransform SpawnTransform(CarlaTransform);
552 
553  FVector SpawnLocation = SpawnTransform.GetLocation();
554  FRotator SpawnRotation(SpawnTransform.GetRotation());
555  // Blueprints are all rotated by 90 degrees
556  SpawnRotation.Yaw += 90;
557  // Remove road inclination
558  SpawnRotation.Roll = 0;
559  SpawnRotation.Pitch = 0;
560 
561  FActorSpawnParameters SpawnParams;
562  SpawnParams.Owner = this;
563  SpawnParams.SpawnCollisionHandlingOverride =
564  ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
565  SpawnParams.OverrideLevel = GM->GetULevelFromName("TrafficLights");
566  ATrafficLightBase * TrafficLight = GetWorld()->SpawnActor<ATrafficLightBase>(
568  SpawnLocation,
569  SpawnRotation,
570  SpawnParams);
571 
572  TrafficSigns.Add(TrafficLight);
573 
574  UTrafficLightComponent *TrafficLightComponent = TrafficLight->GetTrafficLightComponent();
575  TrafficLightComponent->SetSignId(SignalId.c_str());
576 
577  auto ClosestWaypointToSignal =
578  GetMap()->GetClosestWaypointOnRoad(CarlaTransform.location);
579  if (ClosestWaypointToSignal)
580  {
581  auto SignalDistanceToRoad =
582  (GetMap()->ComputeTransform(ClosestWaypointToSignal.get()).location - CarlaTransform.location).Length();
583  double LaneWidth = GetMap()->GetLaneWidth(ClosestWaypointToSignal.get());
584 
585  if(SignalDistanceToRoad < LaneWidth * 0.5)
586  {
587  carla::log_warning("Traffic light",
588  TCHAR_TO_UTF8(*TrafficLightComponent->GetSignId()),
589  "overlaps a driving lane. Disabling collision...");
590 
591  TArray<UPrimitiveComponent*> Primitives;
592  TrafficLight->GetComponents(Primitives);
593  for (auto* Primitive : Primitives)
594  {
595  Primitive->SetCollisionProfileName(TEXT("NoCollision"));
596  }
597  }
598  }
599 
600  RegisterLightComponentFromOpenDRIVE(TrafficLightComponent);
601  TrafficLightComponent->InitializeSign(GetMap().get());
602  }
603 }
604 
606 {
608  check(GM);
609 
610  const auto &Signals = GetMap()->GetSignals();
611  for (auto& SignalPair : Signals)
612  {
613  auto &Signal = SignalPair.second;
614  FString SignalType = Signal->GetType().c_str();
615 
616  ATrafficSignBase * ClosestTrafficSign = GetClosestTrafficSignActor(*Signal.get(), GetWorld());
617  if (ClosestTrafficSign)
618  {
619  USignComponent *SignComponent;
620  if (SignComponentModels.Contains(SignalType))
621  {
622  SignComponent =
623  NewObject<USignComponent>(
624  ClosestTrafficSign, SignComponentModels[SignalType]);
625  }
626  else
627  {
628  SignComponent =
629  NewObject<USignComponent>(
630  ClosestTrafficSign);
631  }
632  SignComponent->SetSignId(Signal->GetSignalId().c_str());
633  SignComponent->RegisterComponent();
634  SignComponent->AttachToComponent(
635  ClosestTrafficSign->GetRootComponent(),
636  FAttachmentTransformRules::KeepRelativeTransform);
637  TrafficSignComponents.Add(SignComponent->GetSignId(), SignComponent);
638  TrafficSigns.Add(ClosestTrafficSign);
639  }
640  else if (TrafficSignsModels.Contains(SignalType))
641  {
642  // We do not spawn stops painted in the ground
643  if (Signal->GetName() == "Stencil_STOP")
644  {
645  continue;
646  }
647  auto CarlaTransform = Signal->GetTransform();
648  FTransform SpawnTransform(CarlaTransform);
649  FVector SpawnLocation = SpawnTransform.GetLocation();
650  FRotator SpawnRotation(SpawnTransform.GetRotation());
651  SpawnRotation.Yaw += 90;
652  // Remove road inclination
653  SpawnRotation.Roll = 0;
654  SpawnRotation.Pitch = 0;
655 
656  FActorSpawnParameters SpawnParams;
657  SpawnParams.Owner = this;
658  SpawnParams.SpawnCollisionHandlingOverride =
659  ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
660  SpawnParams.OverrideLevel = GM->GetULevelFromName("TrafficSigns");
661  ATrafficSignBase * TrafficSign = GetWorld()->SpawnActor<ATrafficSignBase>(
662  TrafficSignsModels[SignalType],
663  SpawnLocation,
664  SpawnRotation,
665  SpawnParams);
666 
667  USignComponent *SignComponent =
668  NewObject<USignComponent>(TrafficSign, SignComponentModels[SignalType]);
669  SignComponent->SetSignId(Signal->GetSignalId().c_str());
670  SignComponent->RegisterComponent();
671  SignComponent->AttachToComponent(
672  TrafficSign->GetRootComponent(),
673  FAttachmentTransformRules::KeepRelativeTransform);
674  SignComponent->InitializeSign(GetMap().get());
675 
676  auto ClosestWaypointToSignal =
677  GetMap()->GetClosestWaypointOnRoad(CarlaTransform.location);
678  if (ClosestWaypointToSignal)
679  {
680  auto SignalDistanceToRoad =
681  (GetMap()->ComputeTransform(ClosestWaypointToSignal.get()).location - CarlaTransform.location).Length();
682  double LaneWidth = GetMap()->GetLaneWidth(ClosestWaypointToSignal.get());
683 
684  if(SignalDistanceToRoad < LaneWidth * 0.5)
685  {
686  carla::log_warning("Traffic sign",
687  TCHAR_TO_UTF8(*SignComponent->GetSignId()),
688  "overlaps a driving lane. Disabling collision...");
689 
690  TArray<UPrimitiveComponent*> Primitives;
691  TrafficSign->GetComponents(Primitives);
692  for (auto* Primitive : Primitives)
693  {
694  Primitive->SetCollisionProfileName(TEXT("NoCollision"));
695  }
696  }
697  }
698  TrafficSignComponents.Add(SignComponent->GetSignId(), SignComponent);
699  TrafficSigns.Add(TrafficSign);
700  }
701  else if (Signal->GetType() == carla::road::SignalType::MaximumSpeed() &&
702  SpeedLimitModels.Contains(Signal->GetSubtype().c_str()))
703  {
704  auto CarlaTransform = Signal->GetTransform();
705  FTransform SpawnTransform(CarlaTransform);
706  FVector SpawnLocation = SpawnTransform.GetLocation();
707  FRotator SpawnRotation(SpawnTransform.GetRotation());
708  SpawnRotation.Yaw += 90;
709  // Remove road inclination
710  SpawnRotation.Roll = 0;
711  SpawnRotation.Pitch = 0;
712 
713  FActorSpawnParameters SpawnParams;
714  SpawnParams.Owner = this;
715  SpawnParams.SpawnCollisionHandlingOverride =
716  ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
717  SpawnParams.OverrideLevel = GM->GetULevelFromName("TrafficSigns");
718  ATrafficSignBase * TrafficSign = GetWorld()->SpawnActor<ATrafficSignBase>(
719  SpeedLimitModels[Signal->GetSubtype().c_str()],
720  SpawnLocation,
721  SpawnRotation,
722  SpawnParams);
723 
724  USpeedLimitComponent *SignComponent =
725  NewObject<USpeedLimitComponent>(TrafficSign);
726  SignComponent->SetSignId(Signal->GetSignalId().c_str());
727  SignComponent->RegisterComponent();
728  SignComponent->AttachToComponent(
729  TrafficSign->GetRootComponent(),
730  FAttachmentTransformRules::KeepRelativeTransform);
731  SignComponent->InitializeSign(GetMap().get());
732  SignComponent->SetSpeedLimit(Signal->GetValue());
733 
734  auto ClosestWaypointToSignal =
735  GetMap()->GetClosestWaypointOnRoad(CarlaTransform.location);
736  if (ClosestWaypointToSignal)
737  {
738  auto SignalDistanceToRoad =
739  (GetMap()->ComputeTransform(ClosestWaypointToSignal.get()).location - CarlaTransform.location).Length();
740  double LaneWidth = GetMap()->GetLaneWidth(ClosestWaypointToSignal.get());
741 
742  if(SignalDistanceToRoad < LaneWidth * 0.5)
743  {
744  carla::log_warning("Traffic sign",
745  TCHAR_TO_UTF8(*SignComponent->GetSignId()),
746  "overlaps a driving lane. Disabling collision...");
747 
748  TArray<UPrimitiveComponent*> Primitives;
749  TrafficSign->GetComponents(Primitives);
750  for (auto* Primitive : Primitives)
751  {
752  Primitive->SetCollisionProfileName(TEXT("NoCollision"));
753  }
754  }
755  }
756  TrafficSignComponents.Add(SignComponent->GetSignId(), SignComponent);
757  TrafficSigns.Add(TrafficSign);
758  }
759  }
760 }
761 
763 {
764  bTrafficLightsFrozen = InFrozen;
766  {
767  for (auto& TrafficGroupPair : TrafficGroups)
768  {
769  auto* TrafficGroup = TrafficGroupPair.Value;
770  TrafficGroup->SetFrozenGroup(true);
771  }
772  }
773  else
774  {
775  for (auto& TrafficGroupPair : TrafficGroups)
776  {
777  auto* TrafficGroup = TrafficGroupPair.Value;
778  TrafficGroup->SetFrozenGroup(false);
779  }
780  }
781 }
782 
784 {
785  return bTrafficLightsFrozen;
786 }
787 
789 {
790  if (TrafficGroups.Contains(JunctionId))
791  {
792  return TrafficGroups[JunctionId];
793  }
794  return nullptr;
795 }
796 
797 
799 {
800  if (TrafficControllers.Contains(ControllerId))
801  {
802  return TrafficControllers[ControllerId];
803  }
804  return nullptr;
805 }
806 
808 {
809  if (!TrafficSignComponents.Contains(SignId))
810  {
811  return nullptr;
812  }
814 }
815 
817 {
818  TArray<AActor*> Actors;
819  UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActor::StaticClass(), Actors);
820 
821  // Detect PropsNode Actor which is the father of all the Props imported from Roadrunner
822  AActor* PropsNode = nullptr;
823  for(AActor* Actor : Actors)
824  {
825  const FString Name = UKismetSystemLibrary::GetDisplayName(Actor);
826  if(Name.Equals("PropsNode"))
827  {
828  PropsNode = Actor;
829  break;
830  }
831  }
832 
833  if(PropsNode)
834  {
835  PropsNode->GetAttachedActors(Actors, true);
836  RemoveAttachedProps(Actors);
837  PropsNode->Destroy();
838  }
839 
840 }
841 
842 void ATrafficLightManager::RemoveAttachedProps(TArray<AActor*> Actors) const
843 {
844  for(AActor* Actor : Actors)
845  {
846  TArray<AActor*> AttachedActors;
847  Actor->GetAttachedActors(AttachedActors, true);
848  RemoveAttachedProps(AttachedActors);
849  Actor->Destroy();
850  }
851 }
std::string SignId
Definition: RoadTypes.h:25
void RegisterLightComponentFromOpenDRIVE(UTrafficLightComponent *TrafficLight)
TMap< FString, TSubclassOf< USignComponent > > SignComponentModels
ULevel * GetULevelFromName(FString LevelName)
UTrafficLightComponent * GetTrafficLightComponent()
void RegisterLightComponentGenerated(UTrafficLightComponent *TrafficLight)
const boost::optional< carla::road::Map > & GetMap()
Class which implements the state changing of traffic lights.
TSubclassOf< AActor > TrafficLightModel
T * GetClosestTrafficSignActor(const carla::road::Signal &Signal, UWorld *World)
void MatchTrafficLightActorsWithOpenDriveSignals()
int32_t JuncId
Definition: RoadTypes.h:17
static ACarlaGameModeBase * GetGameMode(const UObject *WorldContextObject)
Definition: CarlaStatics.h:58
static boost::optional< road::Map > Load(const std::string &opendrive)
USceneComponent * SceneComponent
geom::Location Location
Definition: rpc/Location.h:14
TMap< FString, TSubclassOf< AActor > > TrafficSignsModels
TMap< int, ATrafficLightGroup * > TrafficGroups
carla::SharedPtr< cc::Actor > Actor
USignComponent * GetTrafficSign(FString SignId)
const std::string & GetType() const
Definition: Signal.h:127
static const std::string MaximumSpeed()
Definition: SignalType.cpp:78
static const std::string YieldSign()
Definition: SignalType.cpp:30
static const std::string StopSign()
Definition: SignalType.cpp:33
TMap< FString, USignComponent * > TrafficSignComponents
const boost::optional< carla::road::Map > & GetMap() const
void RemoveAttachedProps(TArray< AActor *> Actors) const
ATrafficLightGroup * GetTrafficGroup(int JunctionId)
static FString GetXODR(const UWorld *World)
Return the OpenDrive XML associated to MapName, or empty if the file is not found.
static void log_warning(Args &&... args)
Definition: Logging.h:96
TMap< FString, TSubclassOf< AActor > > SpeedLimitModels
TMap< FString, UTrafficLightController * > TrafficControllers
const geom::Transform & GetTransform() const
Definition: Signal.h:172
void SetFrozen(bool InFrozen)
const std::string & GetSubtype() const
Definition: Signal.h:131
Base class for the CARLA Game Mode.
static bool IsTrafficLight(const std::string &type)
Definition: SignalType.cpp:121
ETrafficSignState GetTrafficSignState() const
bool MatchSignalAndActor(const carla::road::Signal &Signal, ATrafficSignBase *ClosestTrafficSign)
UTrafficLightController * GetController(FString ControllerId)
Maps a controller from OpenDrive.
geom::Transform Transform
Definition: rpc/Transform.h:16
TArray< ATrafficSignBase * > TrafficSigns
void AddTrafficLight(UTrafficLightComponent *TrafficLight)