12#include "FileHelper.h"
13#include "HighResScreenshot.h"
16#include "DrawDebugHelpers.h"
21#define LOCTEXT_NAMESPACE "CarlaRoadMap"
29 return FMath::Clamp(FMath::FloorToInt(Value), Min, Max);
36 const FVector2D SphericalCoords = Direction.UnitCartesianToSpherical();
37 return SphericalCoords.Y + PI;
55 return FColor(0u, 0u, 0u, 255u);
57 return FColor(255u, 255u, 255u, 255u);
59 auto ToColor = [](
float X){
60 return FMath::FloorToInt(256.0 * (X + PI) / (2.0f * PI)) % 256;
63 return FColor(0u, 255u, ToColor(Azimuth), 255u);
72 Super(ObjectInitializer),
73 PixelsPerCentimeter(1.0f),
80 "Declaration map of FRoadMapPixelData's value does not match current serialization type");
85 const uint32 inHeight,
86 const float inPixelsPerCentimeter,
87 const FTransform &inWorldToMap,
88 const FVector &inMapOffset)
102 const FTransform &Transform,
103 const bool bInvertDirection)
105 bool bIsRoad =
false;
106 bool bHasDirection =
false;
107 FVector Direction(0.0f, 0.0f, 0.0f);
109 auto Rotator = Transform.GetRotation().Rotator();
115 case ECityMapMeshTag::RoadTwoLanes_LaneRight:
116 case ECityMapMeshTag::Road90DegTurn_Lane1:
117 case ECityMapMeshTag::RoadTIntersection_Lane1:
118 case ECityMapMeshTag::RoadTIntersection_Lane9:
119 case ECityMapMeshTag::RoadXIntersection_Lane1:
120 case ECityMapMeshTag::RoadXIntersection_Lane9:
122 bHasDirection =
true;
123 Rotator.Yaw += 180.0f;
125 case ECityMapMeshTag::RoadTwoLanes_LaneLeft:
126 case ECityMapMeshTag::Road90DegTurn_Lane0:
127 case ECityMapMeshTag::RoadTIntersection_Lane0:
128 case ECityMapMeshTag::RoadTIntersection_Lane2:
129 case ECityMapMeshTag::RoadTIntersection_Lane5:
130 case ECityMapMeshTag::RoadTIntersection_Lane8:
131 case ECityMapMeshTag::RoadXIntersection_Lane0:
132 case ECityMapMeshTag::RoadXIntersection_Lane8:
134 bHasDirection =
true;
136 case ECityMapMeshTag::Road90DegTurn_Lane9:
137 case ECityMapMeshTag::RoadTIntersection_Lane7:
138 case ECityMapMeshTag::RoadXIntersection_Lane7:
139 case ECityMapMeshTag::RoadXIntersection_Lane5:
141 bHasDirection =
true;
142 Rotator.Yaw += 90.0f;
144 case ECityMapMeshTag::Road90DegTurn_Lane7:
146 bHasDirection =
true;
147 Rotator.Yaw += 90.0f;
149 case ECityMapMeshTag::Road90DegTurn_Lane5:
151 bHasDirection =
true;
152 Rotator.Yaw += 90.0f + 35.0f;
154 case ECityMapMeshTag::Road90DegTurn_Lane3:
156 bHasDirection =
true;
157 Rotator.Yaw += 90.0f + 45.0f + 20.5f;
159 case ECityMapMeshTag::Road90DegTurn_Lane8:
160 case ECityMapMeshTag::RoadTIntersection_Lane4:
161 case ECityMapMeshTag::RoadXIntersection_Lane2:
162 case ECityMapMeshTag::RoadXIntersection_Lane4:
164 bHasDirection =
true;
165 Rotator.Yaw += 270.0f;
167 case ECityMapMeshTag::Road90DegTurn_Lane6:
169 bHasDirection =
true;
170 Rotator.Yaw += 270.0f + 50.0f;
172 case ECityMapMeshTag::Road90DegTurn_Lane4:
174 bHasDirection =
true;
175 Rotator.Yaw += 270.0f + 80.0f;
177 case ECityMapMeshTag::Road90DegTurn_Lane2:
179 bHasDirection =
true;
182 case ECityMapMeshTag::RoadTIntersection_Lane3:
183 case ECityMapMeshTag::RoadTIntersection_Lane6:
184 case ECityMapMeshTag::RoadXIntersection_Lane3:
185 case ECityMapMeshTag::RoadXIntersection_Lane6:
187 bHasDirection =
false;
191 FQuat Rotation(Rotator);
193 if (bInvertDirection) {
203 const FVector RelativePosition(
220 const FTransform &BoxTransform,
221 const FVector &BoxExtent,
222 float ChecksPerCentimeter)
const
224 auto DirectionOfMovement = BoxTransform.GetRotation().GetForwardVector();
225 DirectionOfMovement.Z = 0.0f;
226 uint32 CheckCount = 0u;
228 const float Step = 1.0f / ChecksPerCentimeter;
229 for (
float X = -BoxExtent.X; X < BoxExtent.X; X += Step) {
230 for (
float Y = -BoxExtent.Y; Y < BoxExtent.Y; Y += Step) {
232 auto Location = BoxTransform.TransformPosition(FVector(X, Y, 0.0f));
234 if (!Data.IsRoad()) {
236 }
else if (Data.HasDirection() &&
237 0.0f > FVector::DotProduct(Data.GetDirection(), DirectionOfMovement)) {
242 if (CheckCount > 0u) {
243 Result.
OffRoad /=
static_cast<float>(CheckCount);
246 UE_LOG(LogCarla, Warning, TEXT(
"URoadMap::Intersect did zero checks"));
254 UE_LOG(LogCarla, Error, TEXT(
"Cannot save invalid road map to disk"));
258 const FString ImagePath = FPaths::Combine(Folder, MapName + TEXT(
".png"));
259 const FString MetadataPath = FPaths::Combine(Folder, MapName + TEXT(
".txt"));
262 TUniquePtr<TImagePixelData<FColor>> PixelData = MakeUnique<TImagePixelData<FColor>>(DestSize);
270 FFormatNamedArguments Args;
271 Args.Add(
"MapName", FText::FromString(MapName));
275 Args.Add(
"Transform", FText::FromString(
WorldToMap.ToString()));
276 Args.Add(
"Offset", FText::FromString(
MapOffset.ToString()));
277 const auto Contents = FText::Format(
278 LOCTEXT(
"RoadMapMetadata",
279 "Map name = {MapName}\n"
280 "Size = {Width}x{Height} pixels\n"
281 "Density = {CmPerPixel} cm/pixel\n"
282 "World-To-Map Transform (T|R|S) = ({Transform})\n"
283 "Map Offset = ({Offset})\n"),
285 if (!FFileHelper::SaveStringToFile(Contents.ToString(), *MetadataPath)) {
286 UE_LOG(LogCarla, Error, TEXT(
"Failed to save map metadata"));
289 UE_LOG(LogCarla, Log, TEXT(
"Saved road map to \"%s\""), *ImagePath);
295void URoadMap::Log()
const
297 const float MapSizeInMB =
303 TEXT(
"Generated road map %dx%d (%.2fMB) with %.2f cm/pixel"),
310 UE_LOG(LogCarla, Error, TEXT(
"Error generating road map"));
315void URoadMap::DrawDebugPixelsToLevel(UWorld *World,
const bool bJustFlushDoNotDraw)
const
317 const FVector ZOffset(0.0f, 0.0f, 50.0f);
318 FlushPersistentDebugLines(World);
319 if (!bJustFlushDoNotDraw) {
320 for (
auto X = 0u; X <
Width; ++X) {
321 for (
auto Y = 0u; Y <
Height; ++Y) {
324 auto Color = Data.EncodeAsColor();
325 if (Data.HasDirection()) {
326 const FVector ArrowEnd =
Location + 50.0f * Data.GetDirection();
327 DrawDebugDirectionalArrow(World, Location, ArrowEnd, 60.0f, Color,
true);
329 DrawDebugPoint(World, Location, 6.0f, Color,
true);
338#undef LOCTEXT_NAMESPACE
ECityMapMeshTag
Tag to identify the meshes used by the ProceduralMapGenerator.
static uint32 ClampFloatToUInt(const float Value, int32 Min, int32 Max)
static float GetRotatedAzimuthAngle(const FVector &Direction)
static TFuture< bool > SavePixelsToDisk(UTextureRenderTarget2D &RenderTarget, const FString &FilePath)
Asynchronously save the pixels in RenderTarget to disk.
uint32 Height
Height of the map in pixels.
FVector GetWorldLocation(uint32 PixelX, uint32 PixelY) const
Return the world location of a given pixel.
int32 GetIndex(uint32 PixelX, uint32 PixelY) const
void Reset(uint32 Width, uint32 Height, float PixelsPerCentimeter, const FTransform &WorldToMap, const FVector &MapOffset)
Resets current map an initializes an empty map of the given size.
void SetPixelAt(uint32 PixelX, uint32 PixelY, ECityMapMeshTag Tag, const FTransform &Transform, bool bInvertDirection=false)
URoadMap(const FObjectInitializer &ObjectInitializer)
Creates a valid empty map (every point is off-road).
float PixelsPerCentimeter
Number of pixels per centimeter.
TArray< uint16 > RoadMapData
FVector MapOffset
Offset of the map in map coordinates.
uint32 Width
Width of the map in pixels.
FTransform WorldToMap
World-to-map transform.
bool SaveAsPNG(const FString &Folder, const FString &MapName) const
Save the current map as PNG with the pixel data encoded as color.
FRoadMapIntersectionResult Intersect(const FTransform &BoxTransform, const FVector &BoxExtent, float ChecksPerCentimeter) const
Intersect actor bounds with map.
FRoadMapPixelData GetDataAt(uint32 PixelX, uint32 PixelY) const
Retrieve the data stored at a given pixel.
Vector3D GetForwardVector() const
Road map intersection result. See URoadMap.
float OppositeLane
Percentage of the box invading opposite lane (wrong direction).
float OffRoad
Percentage of the box lying off-road.
Data stored in a road map pixel. See URoadMap.
float GetDirectionAzimuthalAngle() const
Get the azimuth angle [-PI, PI] of the road direction (in spherical coordinates) at this pixel.
bool HasDirection() const
Whether this pixel has a direction defined (e.g.
static constexpr uint16 MaximumEncodedAngle
static uint16 Encode(bool IsRoad, bool HasDirection, const FVector &Direction)
bool IsRoad() const
Whether this pixel lies in-road.
static constexpr int HasDirectionRow
static constexpr int IsRoadRow
FColor EncodeAsColor() const