Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 221 additions & 5 deletions Source/CarlaDigitalTwinsTool/Private/Generation/OpenDriveToMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
#include "DrawDebugHelpers.h"
#include "Paths/GenerationPathsHelper.h"
#include "StreetMapActor.h"

#include "Misc/Paths.h"
#if WITH_EDITOR

#include "Generation/OpenDriveToMap.h"
Expand Down Expand Up @@ -487,7 +487,14 @@ void UOpenDriveToMap::GenerateTileStandalone(){
#if PLATFORM_WINDOWS
GenerateTile();
#else

if (bSatelliteSegmentationTrees)
{
RunTreeSegmentation();
}

GenerateTile();

#endif
UEditorLoadingAndSavingUtils::SaveDirtyPackages(true, true);
UEditorLevelLibrary::SaveCurrentLevel();
Expand Down Expand Up @@ -797,13 +804,27 @@ void UOpenDriveToMap::GenerateAll(const boost::optional<carla::road::Map>& Param
{
UE_LOG(LogCarlaDigitalTwinsTool, Log, TEXT("UOpenDriveToMap::GenerateAll() Generating Roads..... "));
GenerateRoadMesh(ParamCarlaMap, MinLocation, MaxLocation);

UE_LOG(LogCarlaDigitalTwinsTool, Log, TEXT("UOpenDriveToMap::GenerateAll() Generating Lane Marks..... "));
GenerateLaneMarks(ParamCarlaMap, MinLocation, MaxLocation);

// GenerateSpawnPoints(ParamCarlaMap, MinLocation, MaxLocation);

UE_LOG(LogCarlaDigitalTwinsTool, Log, TEXT("UOpenDriveToMap::GenerateAll() Generating Terrain..... "));
CreateTerrain(5,5, 64);

UE_LOG(LogCarlaDigitalTwinsTool, Log, TEXT("UOpenDriveToMap::GenerateAll() Generating Tree positions..... "));
GenerateTreePositions(ParamCarlaMap, MinLocation, MaxLocation);
if (bSatelliteSegmentationTrees)
{
UE_LOG(LogTemp, Log, TEXT("Generate trees spawning points from satellite segmentation"));
GenerateSatelliteSegmentationTreePositions();
}
else
{
UE_LOG(LogTemp, Log, TEXT("Generate trees spawning points from default method"));
GenerateDefaultTreePositions(ParamCarlaMap, MinLocation, MaxLocation);
}

UE_LOG(LogCarlaDigitalTwinsTool, Log, TEXT("UOpenDriveToMap::GenerateAll() Generating Misc stuff..... "));
GenerationFinished(MinLocation, MaxLocation);
}
Expand Down Expand Up @@ -1107,13 +1128,13 @@ void UOpenDriveToMap::GenerateSpawnPoints( const boost::optional<carla::road::Ma
}
*/

void UOpenDriveToMap::GenerateTreePositions( const boost::optional<carla::road::Map>& ParamCarlaMap, FVector MinLocation, FVector MaxLocation )
void UOpenDriveToMap::GenerateDefaultTreePositions( const boost::optional<carla::road::Map>& ParamCarlaMap, FVector MinLocation, FVector MaxLocation )
{
carla::geom::Vector3D CarlaMinLocation(MinLocation.X / 100, MinLocation.Y / 100, MinLocation.Z /100);
carla::geom::Vector3D CarlaMaxLocation(MaxLocation.X / 100, MaxLocation.Y / 100, MaxLocation.Z /100);

std::vector<std::pair<carla::geom::Transform, std::string>> Locations =
ParamCarlaMap->GetTreesTransform(CarlaMinLocation, CarlaMaxLocation,DistanceBetweenTrees, DistanceFromRoadEdge );
ParamCarlaMap->GetTreesTransform(CarlaMinLocation, CarlaMaxLocation, DistanceBetweenTrees, DistanceFromRoadEdge);
int i = 0;
for (auto &cl : Locations)
{
Expand All @@ -1135,6 +1156,201 @@ void UOpenDriveToMap::GenerateTreePositions( const boost::optional<carla::road::
}
}

void UOpenDriveToMap::RunTreeSegmentation(){

UE_LOG(LogTemp, Log, TEXT("Running Python Segmentation Script..."));

FString PythonExe = PythonBinPath;
FString PluginPath = FPaths::ConvertRelativePathToFull(FPaths::ProjectPluginsDir() / TEXT("carla-digitaltwins"));
FString ScriptPath = PluginPath / TEXT("Content/Python/tree_segmenter.py");
// Hardcoded values for testing

FString Args;
Args += FString::Printf(TEXT("\"%s\" "), *ScriptPath);
Args += FString::Printf(TEXT("--plugin_path=\"%s\" "), *PluginPath);
Args += FString::Printf(TEXT("--lon_min=%.8f "), OriginGeoCoordinates.Y);
Args += FString::Printf(TEXT("--lat_min=%.8f "), OriginGeoCoordinates.X);
Args += FString::Printf(TEXT("--lon_max=%.8f "), FinalGeoCoordinates.Y);
Args += FString::Printf(TEXT("--lat_max=%.8f "), FinalGeoCoordinates.X);
Args += FString::Printf(TEXT("--zoom=%d "), SatelliteSegmentationZoom);
Args += FString::Printf(TEXT("--threshold=%.8f "), SatelliteSegmentationThreshold);
Args += FString::Printf(TEXT("--tree_radius=%.8f "), TreeEffectiveRadius);

// Create communication pipes
void* ReadPipe = nullptr;
void* WritePipe = nullptr;
FPlatformProcess::CreatePipe(ReadPipe, WritePipe);

// Launch process
FProcHandle ProcHandle = FPlatformProcess::CreateProc(
*PythonExe,
*Args,
true, // bLaunchDetached
false, // bLaunchHidden
false, // bLaunchReallyHidden
nullptr,
0,
nullptr,
WritePipe, // Pipe for stdout/stderr
WritePipe
);

if (!ProcHandle.IsValid())
{
UE_LOG(LogTemp, Error, TEXT("Failed to launch Python script."));
FPlatformProcess::ClosePipe(ReadPipe, WritePipe);
return;
}

// Read output
FString Output;
while (FPlatformProcess::IsProcRunning(ProcHandle))
{
FString NewOutput = FPlatformProcess::ReadPipe(ReadPipe);
Output += NewOutput;
FPlatformProcess::Sleep(0.01f);
}

// Read any remaining output
Output += FPlatformProcess::ReadPipe(ReadPipe);

// Clean up
FPlatformProcess::CloseProc(ProcHandle);
FPlatformProcess::ClosePipe(ReadPipe, WritePipe);

// Print result to Unreal log
UE_LOG(LogTemp, Display, TEXT("Python Output:\n%s"), *Output);

}

TArray<FVector2D> UOpenDriveToMap::ReadCSVCoordinates(FString path)
{
UE_LOG(LogTemp, Warning, TEXT("Reading latlon coordinates"));

TArray<FVector2D> Coordinates;

FString PluginPath = FPaths::ConvertRelativePathToFull(FPaths::ProjectPluginsDir() / TEXT("carla-digitaltwins"));
FString FilePositionsPath = PluginPath / path;
FString FileContent;

if (FFileHelper::LoadFileToString(FileContent, *FilePositionsPath))
{
TArray<FString> Lines;
FileContent.ParseIntoArrayLines(Lines);

for (int32 i = 0; i < Lines.Num(); ++i)
{
FString Line = Lines[i];
TArray<FString> Columns;
Line.ParseIntoArray(Columns, TEXT(","), true);

if (Columns.Num() >= 2)
{
float X = FCString::Atof(*Columns[0]);
float Y = FCString::Atof(*Columns[1]);
FVector2D Pos = UMapGenFunctionLibrary::GetTransversemercProjection( Y, X, OriginGeoCoordinates.X, OriginGeoCoordinates.Y );
Coordinates.Add(Pos);
}
}
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Failed to read file at: %s"), *FilePositionsPath);
}

return Coordinates;
}

void UOpenDriveToMap::GenerateSatelliteSegmentationTreePositions()
{
FString Path = FPaths::ConvertRelativePathToFull(FPaths::ProjectPluginsDir() / TEXT("carla-digitaltwins") / TEXT("PythonIntermediate/tree_masks.geojson"));
TArray<USplineComponent*> Splines = UGeometryImporter::ImportGeoJsonPolygonsToSplines(UEditorLevelLibrary::GetEditorWorld(), Path, OriginGeoCoordinates);

// TArray<FVector2D> TreeCoordinates = ReadCSVCoordinates("PythonIntermediate/tree_points.csv");

// SpawnTrees(TreeCoordinates, "TreeSpawnPosition");

if (bShowDebugTreeAreas){

TArray<FVector2D> PolylinesCoordinates = ReadCSVCoordinates("PythonIntermediate/tree_polylines.csv");

SpawnPlaceholders(PolylinesCoordinates, "PolylinesCoordinates");
}

}

void UOpenDriveToMap::SpawnTrees(TArray<FVector2D> TreeCoordinates, FString Label)
{
int i = 0;
for (const FVector2D& Coord : TreeCoordinates)
{
FVector TreePos3D;
TreePos3D.X = Coord.X;
TreePos3D.Y = Coord.Y;
const FVector scale{ 1.0f, 1.0f, 1.0f };
TreePos3D.Z = GetHeight(Coord.X, Coord.Y) + 0.3f;
FTransform NewTransform ( FRotator(), TreePos3D, scale );
NewTransform = GetSnappedPosition(NewTransform);

AActor* Spawner = UEditorLevelLibrary::GetEditorWorld()->SpawnActor<AStaticMeshActor>(AStaticMeshActor::StaticClass(),
NewTransform.GetLocation(), NewTransform.Rotator());

Spawner->Tags.Add(FName(Label));
Spawner->SetActorLabel(Label + FString::FromInt(i) + GetStringForCurrentTile() );
++i;
}
}

void UOpenDriveToMap::SpawnPlaceholders(TArray<FVector2D> Coordinates, FString Label)
{
UStaticMesh* SphereMesh = LoadObject<UStaticMesh>(nullptr, TEXT("/Engine/BasicShapes/Sphere.Sphere"));
UMaterialInterface* MarkerMaterial = LoadObject<UMaterialInterface>(
nullptr,
TEXT("/CarlaDigitalTwinsTool/digitalTwins/Static/Static/Materials/FireHydrant/M_FireHydrant.M_FireHydrant")
); // Use this material to better visualize the boundaries of the masks

int i = 0;
for (const FVector2D& Coord : Coordinates)
{
FVector Pos3D;
Pos3D.X = Coord.X;
Pos3D.Y = Coord.Y;
Pos3D.Z = GetHeight(Coord.X, Coord.Y) + 0.3f;

FTransform Transform(FRotator(), Pos3D, FVector(0.5f)); // Smaller spheres

Transform = GetSnappedPosition(Transform);

AStaticMeshActor* MarkerActor = UEditorLevelLibrary::GetEditorWorld()->SpawnActor<AStaticMeshActor>(
AStaticMeshActor::StaticClass(),
Transform.GetLocation(),
Transform.Rotator()
);

if (MarkerActor && SphereMesh)
{
UStaticMeshComponent* MeshComp = MarkerActor->GetStaticMeshComponent();
MeshComp->SetStaticMesh(SphereMesh);

MeshComp->SetCollisionEnabled(ECollisionEnabled::NoCollision);
MeshComp->SetCollisionProfileName(TEXT("NoCollision"));
MarkerActor->SetActorEnableCollision(false);
MeshComp->SetSimulatePhysics(false);
MeshComp->SetEnableGravity(false);

if (MarkerMaterial)
{
MeshComp->SetMaterial(0, MarkerMaterial);
}

MarkerActor->Tags.Add(FName(Label));
MarkerActor->SetActorLabel(Label + FString::FromInt(i) + GetStringForCurrentTile());
}

++i;
}
}

float UOpenDriveToMap::GetHeight(float PosX, float PosY, bool bDrivingLane){
if (DefaultHeightmap && HeightmapPixels.Num() > 0)
{
Expand Down Expand Up @@ -1549,7 +1765,7 @@ void UOpenDriveToMap::RenderRoadToTexture(UWorld* World)
FVector2D(Center.X, Center.Y),
FVector2D(Extent.X, Extent.Y));

auto JsonPath = PluginPath / TEXT("PythonIntermediate") / TEXT("contours.json");
auto JsonPath = PluginPath / TEXT("PythonIntermediate") / TEXT("road_contours.json");

auto RoadSplines = UGeometryImporter::CreateSplinesFromJson(
World,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ TArray<USplineComponent*> UGeometryImporter::ImportGeoJsonPolygonsToSplines(UWor
i++;
}

UE_LOG(LogGeometryImporter, Log, TEXT("Splines created from GeoJson file."));

return CreatedSplines;
}

Expand Down
43 changes: 36 additions & 7 deletions Source/CarlaDigitalTwinsTool/Public/Generation/OpenDriveToMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,27 @@ class CARLADIGITALTWINSTOOL_API UOpenDriveToMap : public UEditorUtilityObject
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Settings")
FVector2D OriginGeoCoordinates;

UPROPERTY( EditAnywhere, BlueprintReadWrite, Category="Settings" )
float DistanceBetweenTrees = 50.0f;

UPROPERTY( EditAnywhere, BlueprintReadWrite, Category="Settings" )
float DistanceFromRoadEdge = 3.0f;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Settings")
bool bSatelliteSegmentationTrees = true;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Settings")
int SatelliteSegmentationZoom = 20;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Settings")
float SatelliteSegmentationThreshold = 0.2f;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Settings")
float TreeEffectiveRadius = 7.0f;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Settings")
bool bShowDebugTreeAreas = false;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Defaults")
UMaterialInstance* DefaultRoadMaterial;

Expand All @@ -168,12 +189,6 @@ class CARLADIGITALTWINSTOOL_API UOpenDriveToMap : public UEditorUtilityObject
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Parameters")
FOpenDriveFileGenerationParameters OpenDriveGenParams;

UPROPERTY( EditAnywhere, BlueprintReadWrite, Category="Settings" )
float DistanceBetweenTrees = 50.0f;

UPROPERTY( EditAnywhere, BlueprintReadWrite, Category="Settings" )
float DistanceFromRoadEdge = 3.0f;

UPROPERTY( EditAnywhere, BlueprintReadWrite, Category="Stage" )
bool bHasStarted = false;

Expand Down Expand Up @@ -266,9 +281,23 @@ class CARLADIGITALTWINSTOOL_API UOpenDriveToMap : public UEditorUtilityObject
void LoadMap();

void GenerateAll(const boost::optional<carla::road::Map>& ParamCarlaMap, FVector MinLocation, FVector MaxLocation);

void GenerateRoadMesh(const boost::optional<carla::road::Map>& ParamCarlaMap, FVector MinLocation, FVector MaxLocation);

// void GenerateSpawnPoints(const carla::road::Map& ParamCarlaMap, FVector MinLocation, FVector MaxLocation);
void GenerateTreePositions(const boost::optional<carla::road::Map>& ParamCarlaMap, FVector MinLocation, FVector MaxLocation);

void GenerateDefaultTreePositions(const boost::optional<carla::road::Map>& ParamCarlaMap, FVector MinLocation, FVector MaxLocation);

void RunTreeSegmentation();

TArray<FVector2D> ReadCSVCoordinates(FString path);

void GenerateSatelliteSegmentationTreePositions();

void SpawnTrees(TArray<FVector2D> TreeCoordinates, FString Label);

void SpawnPlaceholders(TArray<FVector2D> Coordinates, FString Label);

void GenerateLaneMarks(const boost::optional<carla::road::Map>& ParamCarlaMap, FVector MinLocation, FVector MaxLocation);

FTransform GetSnappedPosition(FTransform Origin);
Expand Down