Fix #15 Implement area detection
This commit is contained in:
parent
a9f0049e03
commit
21528cf10f
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"FileVersion": 3,
|
||||
"Version": 1,
|
||||
"VersionName": "0.2.1",
|
||||
"VersionName": "0.2.2",
|
||||
"FriendlyName": "CARLA",
|
||||
"Description": "",
|
||||
"Category": "Science",
|
||||
|
|
|
@ -4,6 +4,12 @@
|
|||
#include "CityMapGenerator.h"
|
||||
|
||||
#include "MapGen/GraphGenerator.h"
|
||||
#include "MapGen/RoadMap.h"
|
||||
#include "Tagger.h"
|
||||
|
||||
#include "Components/InstancedStaticMeshComponent.h"
|
||||
#include "Engine/World.h"
|
||||
#include "Paths.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -16,7 +22,10 @@
|
|||
// =============================================================================
|
||||
|
||||
ACityMapGenerator::ACityMapGenerator(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer) {}
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
RoadMap = ObjectInitializer.CreateDefaultSubobject<URoadMap>(this, TEXT("RoadMap"));
|
||||
}
|
||||
|
||||
ACityMapGenerator::~ACityMapGenerator() {}
|
||||
|
||||
|
@ -24,15 +33,31 @@ ACityMapGenerator::~ACityMapGenerator() {}
|
|||
// -- Map construction and update related methods ------------------------------
|
||||
// =============================================================================
|
||||
|
||||
void ACityMapGenerator::UpdateMap() {
|
||||
void ACityMapGenerator::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
// We definitively need the map at this point.
|
||||
check(RoadMap != nullptr);
|
||||
if (!RoadMap->IsValid()) {
|
||||
GenerateRoadMap();
|
||||
}
|
||||
}
|
||||
|
||||
void ACityMapGenerator::UpdateMap()
|
||||
{
|
||||
UpdateSeeds();
|
||||
GenerateGraph();
|
||||
if (bGenerateRoads) {
|
||||
GenerateRoads();
|
||||
}
|
||||
if (bGenerateRoadMap) {
|
||||
GenerateRoadMap();
|
||||
}
|
||||
}
|
||||
|
||||
void ACityMapGenerator::UpdateSeeds() {
|
||||
void ACityMapGenerator::UpdateSeeds()
|
||||
{
|
||||
if (!bUseFixedSeed) {
|
||||
bUseMultipleFixedSeeds = false;
|
||||
FRandomStream randomStream;
|
||||
|
@ -44,7 +69,8 @@ void ACityMapGenerator::UpdateSeeds() {
|
|||
}
|
||||
}
|
||||
|
||||
void ACityMapGenerator::GenerateGraph() {
|
||||
void ACityMapGenerator::GenerateGraph()
|
||||
{
|
||||
if ((MapSizeX < 5u) || (MapSizeY < 5u)) {
|
||||
MapSizeX = 5u;
|
||||
MapSizeY = 5u;
|
||||
|
@ -87,7 +113,8 @@ void ACityMapGenerator::GenerateGraph() {
|
|||
#endif // CARLA_ROAD_GENERATOR_EXTRA_LOG
|
||||
}
|
||||
|
||||
void ACityMapGenerator::GenerateRoads() {
|
||||
void ACityMapGenerator::GenerateRoads()
|
||||
{
|
||||
check(Dcel != nullptr);
|
||||
using Graph = MapGen::DoublyConnectedEdgeList;
|
||||
const Graph &graph = *Dcel;
|
||||
|
@ -157,3 +184,105 @@ void ACityMapGenerator::GenerateRoads() {
|
|||
|
||||
#undef ADD_INTERSECTION
|
||||
}
|
||||
|
||||
// Find first component of type road (checking at its stencil value).
|
||||
static bool LineTrace(
|
||||
UWorld *World,
|
||||
const FVector &Start,
|
||||
const FVector &End,
|
||||
FHitResult &HitResult)
|
||||
{
|
||||
TArray <FHitResult> OutHits;
|
||||
static FName TraceTag = FName(TEXT("RoadTrace"));
|
||||
const bool Success = World->LineTraceMultiByObjectType(
|
||||
OutHits,
|
||||
Start,
|
||||
End,
|
||||
FCollisionObjectQueryParams(ECollisionChannel::ECC_WorldDynamic),
|
||||
FCollisionQueryParams(TraceTag, true));
|
||||
|
||||
if (Success) {
|
||||
for (FHitResult &Item : OutHits) {
|
||||
if (Item.Component->CustomDepthStencilValue == static_cast<uint8>(CityObjectLabel::Roads)) {
|
||||
HitResult = Item;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ACityMapGenerator::GenerateRoadMap()
|
||||
{
|
||||
UE_LOG(LogCarla, Log, TEXT("Generating road map..."));
|
||||
|
||||
auto World = GetWorld();
|
||||
check(GetWorld() != nullptr);
|
||||
check(RoadMap != nullptr);
|
||||
|
||||
ATagger::TagActorsInLevel(*GetWorld()); // We need the tags.
|
||||
|
||||
const float IntersectionSize = CityMapMeshTag::GetRoadIntersectionSize();
|
||||
const uint32 Margin = IntersectionSize / 2u;
|
||||
const float Offset = GetMapScale() * Margin;
|
||||
|
||||
const float CmPerPixel = GetMapScale() / static_cast<float>(PixelsPerMapUnit);
|
||||
|
||||
const uint32 SizeX = PixelsPerMapUnit * (MapSizeX + 2u * Margin);
|
||||
const uint32 SizeY = PixelsPerMapUnit * (MapSizeY + 2u * Margin);
|
||||
|
||||
const FTransform &ActorTransform = GetActorTransform();
|
||||
|
||||
RoadMap->RoadMap.Empty();
|
||||
for (uint32 PixelY = 0u; PixelY < SizeY; ++PixelY) {
|
||||
for (uint32 PixelX = 0u; PixelX < SizeX; ++PixelX) {
|
||||
const float X = static_cast<float>(PixelX) * CmPerPixel - Offset;
|
||||
const float Y = static_cast<float>(PixelY) * CmPerPixel - Offset;
|
||||
const FVector Start = ActorTransform.TransformPosition(FVector(X, Y, 50.0f));
|
||||
const FVector End = ActorTransform.TransformPosition(FVector(X, Y, -50.0f));
|
||||
|
||||
bool Success = false;
|
||||
|
||||
// Do the ray tracing.
|
||||
FHitResult Hit;
|
||||
if (LineTrace(World, Start, End, Hit)) {
|
||||
auto InstancedStaticMeshComponent = Cast<UInstancedStaticMeshComponent>(Hit.Component.Get());
|
||||
if (InstancedStaticMeshComponent == nullptr) {
|
||||
UE_LOG(LogCarla, Error, TEXT("Road component is not UInstancedStaticMeshComponent"));
|
||||
} else {
|
||||
FTransform InstanceTransform;
|
||||
if (!InstancedStaticMeshComponent->GetInstanceTransform(Hit.Item, InstanceTransform, true)) {
|
||||
UE_LOG(LogCarla, Error, TEXT("Failed to get instance's transform"));
|
||||
} else {
|
||||
RoadMap->AppendPixel(
|
||||
GetTag(*InstancedStaticMeshComponent->GetStaticMesh()),
|
||||
InstanceTransform);
|
||||
Success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Success) {
|
||||
RoadMap->AppendEmptyPixel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const FTransform FinalTransform(
|
||||
ActorTransform.GetRotation(),
|
||||
ActorTransform.GetTranslation() - FVector(Offset, Offset, 0.0f),
|
||||
ActorTransform.GetScale3D());
|
||||
RoadMap->Set(SizeX, SizeY, 1.0f / CmPerPixel, FinalTransform.Inverse());
|
||||
UE_LOG(LogCarla, Log, TEXT("Generated road map %dx%d (%d)"), RoadMap->GetWidth(), RoadMap->GetHeight(), RoadMap->RoadMap.Num());
|
||||
|
||||
if (!RoadMap->IsValid()) {
|
||||
UE_LOG(LogCarla, Error, TEXT("Error generating road map"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (bSaveRoadMapToDisk) {
|
||||
const FString MapName = World->GetMapName() + TEXT(".png");
|
||||
const FString FilePath = FPaths::Combine(FPaths::GameSavedDir(), MapName);
|
||||
RoadMap->SaveAsPNG(FilePath);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
#include "MapGen/GraphParser.h"
|
||||
#include "CityMapGenerator.generated.h"
|
||||
|
||||
class URoadMap;
|
||||
|
||||
/// Generates a random city using the meshes provided.
|
||||
///
|
||||
/// @note At this point it only generates roads and sidewalks.
|
||||
UCLASS(HideCategories=(Rendering, Input))
|
||||
UCLASS(HideCategories=(Input))
|
||||
class CARLA_API ACityMapGenerator : public ACityMapMeshHolder
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
@ -30,8 +32,17 @@ public:
|
|||
/// @name Map construction and update related methods
|
||||
// ===========================================================================
|
||||
/// @{
|
||||
public:
|
||||
|
||||
URoadMap *GetRoadMap()
|
||||
{
|
||||
return RoadMap;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
/// Update the map based on the current settings.
|
||||
virtual void UpdateMap() override;
|
||||
|
||||
|
@ -44,6 +55,9 @@ private:
|
|||
/// Add the road meshes to the scene based on the current DCEL.
|
||||
void GenerateRoads();
|
||||
|
||||
/// Generate the road map image and save to disk if requested.
|
||||
void GenerateRoadMap();
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
/// @name Map generation properties
|
||||
|
@ -79,6 +93,25 @@ private:
|
|||
UPROPERTY(Category = "Map Generation", EditAnywhere, AdvancedDisplay, meta = (EditCondition = bUseMultipleFixedSeeds))
|
||||
int32 RoadPlanningSeed;
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
/// @name Road Map
|
||||
// ===========================================================================
|
||||
/// @{
|
||||
private:
|
||||
|
||||
UPROPERTY(Category = "Road Map", EditAnywhere)
|
||||
bool bGenerateRoadMap = false;
|
||||
|
||||
UPROPERTY(Category = "Road Map", EditAnywhere, meta = (ClampMin = "1", ClampMax = "500", EditCondition = bGenerateRoadMap))
|
||||
uint32 PixelsPerMapUnit = 50u;
|
||||
|
||||
UPROPERTY(Category = "Road Map", EditAnywhere, meta = (EditCondition = bGenerateRoadMap))
|
||||
bool bSaveRoadMapToDisk = true;
|
||||
|
||||
UPROPERTY(Category = "Road Map", VisibleAnywhere, AdvancedDisplay)
|
||||
URoadMap *RoadMap;
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
/// @name Other private members
|
||||
|
|
|
@ -47,7 +47,9 @@ private:
|
|||
|
||||
CarlaGameControllerBase *GameController;
|
||||
|
||||
UPROPERTY()
|
||||
UCarlaGameInstance *GameInstance;
|
||||
|
||||
UPROPERTY()
|
||||
AController *PlayerController;
|
||||
};
|
||||
|
|
|
@ -3,10 +3,13 @@
|
|||
#include "Carla.h"
|
||||
#include "CarlaVehicleController.h"
|
||||
|
||||
#include "SceneCaptureCamera.h"
|
||||
|
||||
#include "Camera/CameraComponent.h"
|
||||
#include "Components/BoxComponent.h"
|
||||
#include "EngineUtils.h"
|
||||
#include "GameFramework/Pawn.h"
|
||||
#include "GameFramework/SpringArmComponent.h"
|
||||
#include "SceneCaptureCamera.h"
|
||||
#include "WheeledVehicle.h"
|
||||
#include "WheeledVehicleMovementComponent.h"
|
||||
|
||||
|
@ -82,6 +85,14 @@ void ACarlaVehicleController::Possess(APawn *aPawn)
|
|||
// Get vehicle movement component.
|
||||
MovementComponent = WheeledVehicle->GetVehicleMovementComponent();
|
||||
check(MovementComponent != nullptr);
|
||||
// Get vehicle box component.
|
||||
TArray<UBoxComponent *> BoundingBoxes;
|
||||
WheeledVehicle->GetComponents<UBoxComponent>(BoundingBoxes);
|
||||
if (BoundingBoxes.Num() > 0) {
|
||||
VehicleBounds = BoundingBoxes[0];
|
||||
} else {
|
||||
UE_LOG(LogCarla, Error, TEXT("Pawn is missing the bounding box!"));
|
||||
}
|
||||
// Get custom player state.
|
||||
CarlaPlayerState = Cast<ACarlaPlayerState>(PlayerState);
|
||||
check(CarlaPlayerState != nullptr);
|
||||
|
@ -111,6 +122,11 @@ void ACarlaVehicleController::BeginPlay()
|
|||
Image.PostProcessEffect = Camera->GetPostProcessEffect();
|
||||
}
|
||||
}
|
||||
|
||||
TActorIterator<ACityMapGenerator> It(GetWorld());
|
||||
if (It) {
|
||||
RoadMap = It->GetRoadMap();
|
||||
}
|
||||
}
|
||||
|
||||
void ACarlaVehicleController::Tick(float DeltaTime)
|
||||
|
@ -126,7 +142,7 @@ void ACarlaVehicleController::Tick(float DeltaTime)
|
|||
const FVector CurrentSpeed = CarlaPlayerState->ForwardSpeed * CarlaPlayerState->Orientation;
|
||||
CarlaPlayerState->Acceleration = (CurrentSpeed - PreviousSpeed) / DeltaTime;
|
||||
CarlaPlayerState->CurrentGear = GetVehicleCurrentGear();
|
||||
/// @todo #15 Set intersection factors.
|
||||
IntersectPlayerWithRoadMap();
|
||||
const auto NumberOfCameras = SceneCaptureCameras.Num();
|
||||
check(NumberOfCameras == CarlaPlayerState->Images.Num());
|
||||
for (auto i = 0; i < NumberOfCameras; ++i) {
|
||||
|
@ -283,3 +299,29 @@ void ACarlaVehicleController::ChangeCameraRight(float Value)
|
|||
Rotation.Yaw -= Value;
|
||||
SpringArm->SetRelativeRotation(Rotation);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// -- Other --------------------------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
void ACarlaVehicleController::IntersectPlayerWithRoadMap()
|
||||
{
|
||||
if (RoadMap == nullptr) {
|
||||
UE_LOG(LogCarla, Error, TEXT("Controller doesn't have a road map"));
|
||||
return;
|
||||
} else if (VehicleBounds == nullptr) {
|
||||
UE_LOG(LogCarla, Error, TEXT("Vehicle doesn't have a bounding box"));
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr float ChecksPerCentimeter = 0.1f;
|
||||
constexpr bool LeftHandDriving = false;
|
||||
auto Result = RoadMap->Intersect(
|
||||
GetPawn()->GetTransform(),
|
||||
VehicleBounds->GetScaledBoxExtent(),
|
||||
ChecksPerCentimeter,
|
||||
LeftHandDriving);
|
||||
|
||||
CarlaPlayerState->OffRoadIntersectionFactor = Result.OffRoad;
|
||||
CarlaPlayerState->OtherLaneIntersectionFactor = Result.OppositeLane;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
class ACarlaHUD;
|
||||
class ACarlaPlayerState;
|
||||
class ASceneCaptureCamera;
|
||||
class UBoxComponent;
|
||||
class UCameraComponent;
|
||||
class URoadMap;
|
||||
class USpringArmComponent;
|
||||
class UWheeledVehicleMovementComponent;
|
||||
struct FCameraDescription;
|
||||
|
@ -160,6 +162,22 @@ private:
|
|||
|
||||
void SetupControllerInput();
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
/// @name Other
|
||||
// ===========================================================================
|
||||
/// @{
|
||||
public:
|
||||
|
||||
void SetRoadMap(URoadMap *inRoadMap)
|
||||
{
|
||||
RoadMap = inRoadMap;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void IntersectPlayerWithRoadMap();
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
// -- Member variables -------------------------------------------------------
|
||||
|
@ -181,6 +199,12 @@ private:
|
|||
UPROPERTY()
|
||||
TArray<ASceneCaptureCamera *> SceneCaptureCameras;
|
||||
|
||||
UPROPERTY()
|
||||
URoadMap *RoadMap;
|
||||
|
||||
UPROPERTY()
|
||||
UBoxComponent *VehicleBounds;
|
||||
|
||||
// Cast for quick access to the custom player state.
|
||||
UPROPERTY()
|
||||
ACarlaPlayerState *CarlaPlayerState;
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#include "Carla.h"
|
||||
#include "RoadMap.h"
|
||||
|
||||
#include "CapturedImage.h"
|
||||
|
||||
static FVector2D Decode(const FColor &Color);
|
||||
|
||||
// void RoadMap::SetCapture(FCapturedImage &inMapCapture, const FVector2D &inMapSizeInCm)
|
||||
// {
|
||||
// MapCapture = &inMapCapture;
|
||||
// MapSizeInCm = inMapSizeInCm
|
||||
// }
|
||||
|
||||
// bool RoadMap::IsValid() const
|
||||
// {
|
||||
// return ((MapCapture != nullptr) &&
|
||||
// (MapCapture->BitMap.Num() > 0) &&
|
||||
// (MapSizeInCm.X > 0.0f) &&
|
||||
// (MapSizeInCm.Y > 0.0f));
|
||||
// }
|
||||
|
||||
// FVector2D RoadMap::GetDirectionAt(const FVector &Location) const
|
||||
// {
|
||||
// check(IsValid());
|
||||
// return FVector2D();
|
||||
// }
|
|
@ -1,29 +0,0 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Math/Vector.h"
|
||||
|
||||
struct FCapturedImage;
|
||||
|
||||
/// Road map of the level. Contains information in 2D of which areas are road
|
||||
/// and lane directions.
|
||||
class CARLA_API RoadMap
|
||||
{
|
||||
public:
|
||||
|
||||
void SetCapture(
|
||||
const FCapturedImage &MapCapture,
|
||||
const FVector2D &Origin,
|
||||
const FVector2D &MapExtent);
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
FVector2D GetDirectionAt(const FVector &Location) const;
|
||||
|
||||
private:
|
||||
|
||||
uint32 GetPixelIndexAt(const FVector2D &Location) const;
|
||||
|
||||
TArray<FVector2D> DirectionMap;
|
||||
};
|
|
@ -67,6 +67,9 @@ FVector ACityMapMeshHolder::GetTileLocation(uint32 X, uint32 Y) const
|
|||
void ACityMapMeshHolder::SetStaticMesh(ECityMapMeshTag Tag, UStaticMesh *Mesh)
|
||||
{
|
||||
StaticMeshes[Tag] = Mesh;
|
||||
if (Mesh != nullptr) {
|
||||
TagMap.Add(Mesh, Tag);
|
||||
}
|
||||
}
|
||||
|
||||
UStaticMesh *ACityMapMeshHolder::GetStaticMesh(ECityMapMeshTag Tag)
|
||||
|
@ -79,6 +82,12 @@ const UStaticMesh *ACityMapMeshHolder::GetStaticMesh(ECityMapMeshTag Tag) const
|
|||
return StaticMeshes[Tag];
|
||||
}
|
||||
|
||||
ECityMapMeshTag ACityMapMeshHolder::GetTag(const UStaticMesh &StaticMesh) const
|
||||
{
|
||||
const ECityMapMeshTag *Tag = TagMap.Find(&StaticMesh);
|
||||
return (Tag != nullptr ? *Tag : ECityMapMeshTag::INVALID);
|
||||
}
|
||||
|
||||
void ACityMapMeshHolder::AddInstance(ECityMapMeshTag Tag, uint32 X, uint32 Y)
|
||||
{
|
||||
AddInstance(Tag, FTransform(GetTileLocation(X, Y)));
|
||||
|
|
|
@ -38,6 +38,11 @@ protected:
|
|||
// ===========================================================================
|
||||
protected:
|
||||
|
||||
float GetMapScale() const
|
||||
{
|
||||
return MapScale;
|
||||
}
|
||||
|
||||
/// Return the 3D world location (relative to this actor) of the given 2D
|
||||
/// tile.
|
||||
FVector GetTileLocation(uint32 X, uint32 Y) const;
|
||||
|
@ -51,6 +56,9 @@ protected:
|
|||
/// Return the static mesh corresponding to @a Tag.
|
||||
const UStaticMesh *GetStaticMesh(ECityMapMeshTag Tag) const;
|
||||
|
||||
/// Return the tag corresponding to @a StaticMesh.
|
||||
ECityMapMeshTag GetTag(const UStaticMesh &StaticMesh) const;
|
||||
|
||||
/// Add an instance of a mesh with a given tile location.
|
||||
/// @param Tag The mesh' tag
|
||||
/// @param X Tile coordinate X
|
||||
|
@ -92,6 +100,9 @@ private:
|
|||
UPROPERTY(Category = "Meshes", EditAnywhere)
|
||||
TMap<ECityMapMeshTag, UStaticMesh *> StaticMeshes;
|
||||
|
||||
UPROPERTY()
|
||||
TMap<UStaticMesh *, ECityMapMeshTag> TagMap;
|
||||
|
||||
UPROPERTY(Category = "Meshes|Debug", VisibleAnywhere)
|
||||
float MapScale;
|
||||
|
||||
|
|
|
@ -46,7 +46,8 @@ enum class ECityMapMeshTag : uint8
|
|||
RoadXIntersection_Sidewalk3 UMETA(DisplayName = "Road: X-Intersection - Sidewalk 3"),
|
||||
RoadXIntersection_LaneMarking UMETA(DisplayName = "Road: X-Intersection - Lane Marking"),
|
||||
|
||||
NUMBER_OF_TAGS UMETA(Hidden)
|
||||
NUMBER_OF_TAGS UMETA(Hidden),
|
||||
INVALID UMETA(Hidden)
|
||||
};
|
||||
|
||||
/// Helper class for working with ECityMapMeshTag.
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#include "Carla.h"
|
||||
#include "RoadMap.h"
|
||||
|
||||
#include "HighResScreenshot.h"
|
||||
|
||||
static uint32 ClampFloatToUInt(const float Value, int32 Min, int32 Max)
|
||||
{
|
||||
return FMath::Clamp(FMath::FloorToInt(Value), Min, Max);
|
||||
}
|
||||
|
||||
const FRoadMapPixelData &URoadMap::GetDataAt(const FVector &WorldLocation) const
|
||||
{
|
||||
const FVector Location = WorldToMap.TransformPosition(WorldLocation);
|
||||
uint32 X = ClampFloatToUInt(PixelsPerCentimeter * Location.X, 0, Width);
|
||||
uint32 Y = ClampFloatToUInt(PixelsPerCentimeter * Location.Y, 0, Height);
|
||||
return GetDataAt(X, Y);
|
||||
}
|
||||
|
||||
FRoadMapIntersectionResult URoadMap::Intersect(
|
||||
const FTransform &BoxTransform,
|
||||
const FVector &BoxExtent,
|
||||
float ChecksPerCentimeter,
|
||||
const bool LeftHandDriving) const
|
||||
{
|
||||
auto DirectionOfMovement = BoxTransform.GetRotation().GetForwardVector();
|
||||
if (LeftHandDriving) {
|
||||
DirectionOfMovement *= -1.0f;
|
||||
}
|
||||
|
||||
uint32 CheckCount = 0u;
|
||||
FRoadMapIntersectionResult Result = {0.0f, 0.0f};
|
||||
const float Step = 1.0f / ChecksPerCentimeter;
|
||||
for (float X = -BoxExtent.X; X < BoxExtent.X; X += Step) {
|
||||
for (float Y = -BoxExtent.Y; Y < BoxExtent.Y; Y += Step) {
|
||||
++CheckCount;
|
||||
auto Location = BoxTransform.TransformPosition(FVector(X, Y, 0.0f));
|
||||
auto &Data = GetDataAt(Location);
|
||||
if (Data.bIsOffRoad) {
|
||||
Result.OffRoad += 1.0f;
|
||||
} else if (Data.bHasDirection &&
|
||||
0.0f < FVector::DotProduct(Data.Direction, DirectionOfMovement)) {
|
||||
Result.OppositeLane += 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CheckCount > 0u) {
|
||||
Result.OffRoad /= static_cast<float>(CheckCount);
|
||||
Result.OppositeLane /= static_cast<float>(CheckCount);
|
||||
} else {
|
||||
UE_LOG(LogCarla, Warning, TEXT("URoadMap::Intersect did zero checks"));
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
static FColor Encode(const FRoadMapPixelData &Data)
|
||||
{
|
||||
if (Data.bIsOffRoad) {
|
||||
return FColor(0u, 0u, 0u, 255u);
|
||||
} else if (!Data.bHasDirection) {
|
||||
return FColor(255u, 255u, 255u, 255u);
|
||||
} else {
|
||||
// Assumes normalized direction.
|
||||
auto ToColor = [](float X){
|
||||
return FMath::FloorToInt(255.0 * (X + 1.0f) / 2.0f);
|
||||
};
|
||||
return FColor(ToColor(Data.Direction.X), ToColor(Data.Direction.Y), ToColor(Data.Direction.Z));
|
||||
}
|
||||
}
|
||||
|
||||
bool URoadMap::SaveAsPNG(const FString &Path) const
|
||||
{
|
||||
if (!IsValid()) {
|
||||
UE_LOG(LogCarla, Error, TEXT("Cannot save invalid road map to disk"));
|
||||
return false;
|
||||
}
|
||||
|
||||
TArray<FColor> BitMap;
|
||||
for (auto &Data : RoadMap) {
|
||||
BitMap.Emplace(Encode(Data));
|
||||
}
|
||||
|
||||
FIntPoint DestSize(Width, Height);
|
||||
FString ResultPath;
|
||||
FHighResScreenshotConfig& HighResScreenshotConfig = GetHighResScreenshotConfig();
|
||||
HighResScreenshotConfig.SaveImage(Path, BitMap, DestSize, &ResultPath);
|
||||
UE_LOG(LogCarla, Log, TEXT("Saved road map to \"%s\""), *ResultPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
void URoadMap::AppendPixel(ECityMapMeshTag Tag, const FTransform &Transform)
|
||||
{
|
||||
AppendEmptyPixel();
|
||||
auto &Data = RoadMap.Last();
|
||||
Data.bIsOffRoad = false;
|
||||
|
||||
auto Rotator = Transform.GetRotation().Rotator();
|
||||
switch (Tag) {
|
||||
case ECityMapMeshTag::RoadTwoLanes_LaneRight:
|
||||
case ECityMapMeshTag::Road90DegTurn_Lane0:
|
||||
Data.bHasDirection = true;
|
||||
break;
|
||||
case ECityMapMeshTag::RoadTwoLanes_LaneLeft:
|
||||
case ECityMapMeshTag::Road90DegTurn_Lane1:
|
||||
Rotator.Yaw += 180.0f;
|
||||
Data.bHasDirection = true;
|
||||
break;
|
||||
case ECityMapMeshTag::Road90DegTurn_Lane2:
|
||||
Rotator.Yaw += 90.0f;
|
||||
Data.bHasDirection = true;
|
||||
break;
|
||||
case ECityMapMeshTag::Road90DegTurn_Lane3:
|
||||
Rotator.Yaw += 270.0f;
|
||||
Data.bHasDirection = true;
|
||||
break;
|
||||
}
|
||||
if (Data.bHasDirection) {
|
||||
FQuat Rotation(Rotator);
|
||||
Data.Direction = Rotation.GetForwardVector();
|
||||
}
|
||||
}
|
||||
|
||||
void URoadMap::Set(
|
||||
const uint32 inWidth,
|
||||
const uint32 inHeight,
|
||||
const float inPinxelsPerCentimeter,
|
||||
const FTransform &inWorldToMap)
|
||||
{
|
||||
Width = inWidth;
|
||||
Height = inHeight;
|
||||
PixelsPerCentimeter = inPinxelsPerCentimeter;
|
||||
WorldToMap = inWorldToMap;
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "UObject/NoExportTypes.h"
|
||||
#include "RoadMap.generated.h"
|
||||
|
||||
USTRUCT()
|
||||
struct FRoadMapIntersectionResult
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** Percentage of the box lying off-road */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
||||
float OffRoad;
|
||||
|
||||
/** Percentage of the box invading opposite lane (wrong direction) */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
||||
float OppositeLane;
|
||||
};
|
||||
|
||||
USTRUCT()
|
||||
struct FRoadMapPixelData
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
||||
bool bIsOffRoad = true;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
||||
bool bHasDirection = false;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
||||
FVector Direction;
|
||||
};
|
||||
|
||||
/// Road map of the level. Contains information in 2D of which areas are road
|
||||
/// and lane directions.
|
||||
UCLASS()
|
||||
class CARLA_API URoadMap : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
bool IsValid() const
|
||||
{
|
||||
return ((RoadMap.Num() > 0) && (RoadMap.Num() == Height * Width));
|
||||
}
|
||||
|
||||
uint32 GetWidth() const
|
||||
{
|
||||
return Width;
|
||||
}
|
||||
|
||||
uint32 GetHeight() const
|
||||
{
|
||||
return Height;
|
||||
}
|
||||
|
||||
const FRoadMapPixelData &GetDataAt(uint32 PixelX, uint32 PixelY) const
|
||||
{
|
||||
check(IsValid());
|
||||
return RoadMap[PixelX + Height * PixelY];
|
||||
}
|
||||
|
||||
/** Clamps value if lies outside map limits */
|
||||
UFUNCTION(BlueprintCallable)
|
||||
const FRoadMapPixelData &GetDataAt(const FVector &WorldLocation) const;
|
||||
|
||||
/** Intersect actor bounds with map.
|
||||
*
|
||||
* Bounds box is projected to the map and checked against it for possible
|
||||
* intersections with off-road areas and opposite lanes.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable)
|
||||
FRoadMapIntersectionResult Intersect(
|
||||
const FTransform &BoxTransform,
|
||||
const FVector &BoxExtent,
|
||||
float ChecksPerCentimeter,
|
||||
bool LeftHandDriving) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
bool SaveAsPNG(const FString &Path) const;
|
||||
|
||||
private:
|
||||
|
||||
friend class ACityMapGenerator;
|
||||
|
||||
void AppendEmptyPixel()
|
||||
{
|
||||
RoadMap.AddDefaulted(1);
|
||||
}
|
||||
|
||||
void AppendPixel(ECityMapMeshTag Tag, const FTransform &Transform);
|
||||
|
||||
void Set(uint32 Width, uint32 Height, float PixelsPerCentimeter, const FTransform &WorldToMap);
|
||||
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
FTransform WorldToMap;
|
||||
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
float PixelsPerCentimeter = 0.0f;
|
||||
|
||||
/** Width of the map in pixels */
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
uint32 Width = 0u;
|
||||
|
||||
/** Height of the map in pixels */
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
uint32 Height = 0u;
|
||||
|
||||
UPROPERTY()
|
||||
TArray<FRoadMapPixelData> RoadMap;
|
||||
};
|
|
@ -9,22 +9,6 @@
|
|||
#include "Components/SkeletalMeshComponent.h"
|
||||
#include "PhysicsEngine/PhysicsAsset.h"
|
||||
|
||||
enum class CityObjectLabel : uint8
|
||||
{
|
||||
None = 0u,
|
||||
Buildings = 1u,
|
||||
Fences = 2u,
|
||||
Other = 3u,
|
||||
Pedestrians = 4u,
|
||||
Poles = 5u,
|
||||
RoadLines = 6u,
|
||||
Roads = 7u,
|
||||
Sidewalks = 8u,
|
||||
Vegetation = 9u,
|
||||
Vehicles = 10u,
|
||||
Walls = 11u,
|
||||
};
|
||||
|
||||
#ifdef CARLA_TAGGER_EXTRA_LOG
|
||||
static FString GetLabelAsString(const CityObjectLabel Label)
|
||||
{
|
||||
|
|
|
@ -5,6 +5,22 @@
|
|||
#include "GameFramework/Actor.h"
|
||||
#include "Tagger.generated.h"
|
||||
|
||||
enum class CityObjectLabel : uint8
|
||||
{
|
||||
None = 0u,
|
||||
Buildings = 1u,
|
||||
Fences = 2u,
|
||||
Other = 3u,
|
||||
Pedestrians = 4u,
|
||||
Poles = 5u,
|
||||
RoadLines = 6u,
|
||||
Roads = 7u,
|
||||
Sidewalks = 8u,
|
||||
Vegetation = 9u,
|
||||
Vehicles = 10u,
|
||||
Walls = 11u,
|
||||
};
|
||||
|
||||
/// Sets actors' custom depth stencil value for semantic segmentation according
|
||||
/// to their meshes.
|
||||
///
|
||||
|
|
Loading…
Reference in New Issue