Agrarsense
SimulatorJsonExporter.cpp
Go to the documentation of this file.
1// Copyright (c) 2023 FrostBit Software Lab at the Lapland University of Applied Sciences
2//
3// This work is licensed under the terms of the MIT license.
4// For a copy, see <https://opensource.org/licenses/MIT>.
5
7
14
19
29
30#include "GenericPlatform/GenericPlatformFile.h"
31#include "Serialization/JsonSerializer.h"
32#include "Serialization/JsonWriter.h"
33#include "Misc/DefaultValueHelper.h"
34#include "HAL/PlatformFileManager.h"
35#include "Misc/FileHelper.h"
36
37#include "Engine/GameViewportClient.h"
38#include "Engine/Engine.h"
39#include "Engine/World.h"
40
41FString USimulatorJsonExporter::ExportVehicleAndSensorsToJSON(FString FileName, AVehicle* Vehicle, bool OverrideTransform, const FTransform& Transform)
42{
43 FString FilePath;
44 if (!Vehicle)
45 {
46 return FilePath;
47 }
48
49 EVehicleTypes VehicleType = Vehicle->GetVehicleType();
50 FString VehicleName;
51
52 switch (VehicleType)
53 {
55 VehicleName = "Forwarder";
56 break;
57
59 VehicleName = "Harvester";
60 break;
61
63 VehicleName = "Drone";
64 break;
65
67 default:
68 break;
69 }
70
71 // If the vehicle name is empty, return
72 if (VehicleName.IsEmpty())
73 {
74 return FilePath;
75 }
76
77 // Remove invalid characters from the filename, and replace them with undescores.
78 // Will not remove spaces, maybe they should be?
79 FString ValidatedFileName = FPaths::MakeValidFileName(FileName, TEXT('_'));
80 FilePath = CreateUniqueFilePath(ValidatedFileName);
81
82 TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
83 TArray<TSharedPtr<FJsonValue>> ObjectsArray;
84
85 TSharedPtr<FJsonObject> VehicleObject = MakeShareable(new FJsonObject);
86 VehicleObject->SetStringField("type", "vehicle");
87 VehicleObject->SetStringField("model", VehicleName);
88 VehicleObject->SetBoolField("teleportSpectator", false);
89 VehicleObject->SetBoolField("followObject", false);
90 VehicleObject->SetBoolField("destroyOverlappingObjects", false);
91 VehicleObject->SetStringField("id", IActorInformation::Execute_GetActorID(Vehicle));
92
93 TSharedPtr<FJsonObject> VehicleSpawnPoint = MakeShareable(new FJsonObject);
94
95 FVector SpawnLocation;
96 FRotator SpawnRotation;
97
98 if (OverrideTransform)
99 {
100 SpawnLocation = Transform.GetLocation();
101 SpawnRotation = Transform.Rotator();
102 }
103 else
104 {
105 SpawnLocation = Vehicle->GetActorLocation();
106 SpawnRotation = Vehicle->GetActorRotation();
107 }
108
109 // Export vehicle spawnpoint to json
110 SetSpawnPoint(VehicleObject, SpawnLocation, SpawnRotation, Transform.GetScale3D());
111
112 // If the vehicle is drone, export its parameters to json
113 if (Vehicle->GetVehicleType() == EVehicleTypes::Drone)
114 {
115 SetDroneParameters(VehicleObject, Vehicle);
116 }
117 else
118 {
119 // If vehicle is not drone, export WheeledVehicleParameters into the json
120 TSharedPtr<FJsonObject> ParametersObject = MakeShareable(new FJsonObject);
121 FWheeledVehicleParameters Params = Vehicle->GetVehicleParameters();
122
123 FJsonObjectConverter::UStructToJsonObject(FWheeledVehicleParameters::StaticStruct(), &Params, ParametersObject.ToSharedRef());
124 VehicleObject->SetObjectField("parameters", ParametersObject);
125 }
126
127 // Export all sensors attached to the vehicle
128 TArray<TSharedPtr<FJsonValue>> SensorsArray;
129
130 USensorsManagerComponent* SensorManager = Vehicle->GetSensorsManager();
131 if (SensorManager)
132 {
133 // Parse different sensor types and add them to the SensorsArray
134 SensorsArray.Append(ParseLidars(SensorManager->GetLidars()));
135 SensorsArray.Append(ParseCameras(SensorManager->GetCameras()));
136 SensorsArray.Append(ParseDepthCameras(SensorManager->GetDepthCameras()));
137 SensorsArray.Append(ParseThermalCameras(SensorManager->GetThermalCameras()));
138 SensorsArray.Append(ParseDVSCameras(SensorManager->GetDVSCameras()));
139 SensorsArray.Append(ParseRadars(SensorManager->GetRadars()));
140 }
141
142 // Add the sensors array to the vehicle object if it's not empty
143 if (SensorsArray.Num() > 0)
144 {
145 VehicleObject->SetArrayField("sensors", SensorsArray);
146 }
147
148 ObjectsArray.Add(MakeShareable(new FJsonValueObject(VehicleObject)));
149
150 JsonObject->SetArrayField("objects", ObjectsArray);
151
152 FString JsonString;
153 TSharedRef<TJsonWriter<TCHAR>> JsonWriter = TJsonWriterFactory<>::Create(&JsonString);
154 FJsonSerializer::Serialize(JsonObject.ToSharedRef(), JsonWriter);
155
156 // Save the JSON string to the file
157 bool Saved = FFileHelper::SaveStringToFile(JsonString, *FilePath);
158 if (!Saved)
159 {
160 // If saving failed, return empty string.
161 return FString();
162 }
163
164 FString Msg = FString::Printf(TEXT("Exported vehicle JSON file to: %s"), *FilePath);
166
167 return FilePath;
168}
169
170FString USimulatorJsonExporter::ExportWeatherToJSON(const FString& FileName, const FWeatherParameters& WeatherParameters)
171{
172 // Remove invalid characters from the filename, and replace them with undescores.
173 // Will not remove spaces, maybe they should be?
174 FString ValidatedFileName = FPaths::MakeValidFileName(FileName, TEXT('_'));
175
176 FString FilePath = CreateUniqueFilePath(ValidatedFileName);
177
178 // Create the JSON object from FWeatherParameters struct
179 TSharedPtr<FJsonObject> ParametersObject = MakeShareable(new FJsonObject);
180 FJsonObjectConverter::UStructToJsonObject(FWeatherParameters::StaticStruct(), &WeatherParameters, ParametersObject.ToSharedRef());
181
182 TSharedPtr<FJsonObject> RootObject = MakeShareable(new FJsonObject);
183 TArray<TSharedPtr<FJsonValue>> ObjectsArray;
184 TSharedPtr<FJsonObject> WeatherObject = MakeShareable(new FJsonObject);
185 WeatherObject->SetStringField("type", "weather");
186
187 WeatherObject->SetObjectField("parameters", ParametersObject);
188
189 ObjectsArray.Add(MakeShareable(new FJsonValueObject(WeatherObject)));
190
191 RootObject->SetArrayField("objects", ObjectsArray);
192
193 FString JsonString;
194 TSharedRef<TJsonWriter<>> JsonWriter = TJsonWriterFactory<>::Create(&JsonString);
195 FJsonSerializer::Serialize(RootObject.ToSharedRef(), JsonWriter);
196
197 bool Saved = FFileHelper::SaveStringToFile(JsonString, *FilePath);
198 if (!Saved)
199 {
200 return FString();
201 }
202
203 // Publish and log info
204 FString Msg = FString::Printf(TEXT("Exported Weather JSON file to: %s"), *FilePath);
206
207 return FilePath;
208}
209
210FString USimulatorJsonExporter::ExportInstancedActorsToJSON(const FString FileName, const TArray<AInstancedActor*>& Actors)
211{
212 // Remove invalid characters from the filename, and replace them with undescores.
213 // Will not remove spaces, maybe they should be?
214 FString ValidatedFileName = FPaths::MakeValidFileName(FileName, TEXT('_'));
215
216 FString FilePath;
217
218 if (Actors.IsEmpty())
219 {
220#if WITH_EDITOR
221 UE_LOG(LogTemp, Warning, TEXT("ROSJsonExporter.cpp: Actors TArray is empty."));
222#endif
223 return FilePath;
224 }
225
226 FilePath = CreateUniqueFilePath(ValidatedFileName);
227
228 TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
229
230 TArray<TSharedPtr<FJsonValue>> ObjectsArray;
231 for (AInstancedActor* Actor : Actors)
232 {
233 if (!Actor)
234 {
235 continue;
236 }
237
238 FString type = Actor->GetTypeIDString();
239 FString model = Actor->GetModelIDString();
240
241 // If these are not set, continue
242 if (type == "none" || model == "none")
243 {
244 continue;
245 }
246
247 TSharedPtr<FJsonObject> ObjectEntry = MakeShareable(new FJsonObject);
248 ObjectEntry->SetStringField("type", type);
249 ObjectEntry->SetStringField("model", model);
250
251 // Create a spawnPoint object
252 TSharedPtr<FJsonObject> SpawnPoint = MakeShareable(new FJsonObject);
253 FVector SpawnLocation = Actor->GetActorLocation();
254 FRotator SpawnRotation = Actor->GetActorRotation();
255 FVector Scale = Actor->GetActorScale();
256 SetSpawnPoint(ObjectEntry, SpawnLocation, SpawnRotation, Scale);
257 ObjectsArray.Add(MakeShareable(new FJsonValueObject(ObjectEntry)));
258 }
259
260 JsonObject->SetArrayField("objects", ObjectsArray);
261
262 FString JsonString;
263 TSharedRef<TJsonWriter<TCHAR>> JsonWriter = TJsonWriterFactory<>::Create(&JsonString);
264 FJsonSerializer::Serialize(JsonObject.ToSharedRef(), JsonWriter);
265
266 bool Saved = FFileHelper::SaveStringToFile(JsonString, *FilePath);
267 if (!Saved)
268 {
269 return FString();
270 }
271
272 // Publish and log info
273 FString Msg = FString::Printf(TEXT("Exported Actors JSON file to: %s"), *FilePath);
275
276 return FilePath;
277}
278
279FString USimulatorJsonExporter::ExportWalkerToJSON(const FString& FileName, AWalker* Walker)
280{
281 FString FilePath;
282 if (!Walker)
283 {
284 return FilePath;
285 }
286
287 // Remove invalid characters from the filename, and replace them with undescores.
288 // Will not remove spaces, maybe they should be?
289 FString ValidatedFileName = FPaths::MakeValidFileName(FileName, TEXT('_'));
290
291 FilePath = CreateUniqueFilePath(ValidatedFileName);
292
293 // Root Json object
294 TSharedPtr<FJsonObject> RootJsonObject = MakeShareable(new FJsonObject);
295
296 // Json structure "Objects" array
297 TArray<TSharedPtr<FJsonValue>> ObjectsArray;
298 TSharedPtr<FJsonObject> ObjectEntry = MakeShareable(new FJsonObject);
299
300 // Get Walker parameters
301 FWalkerParameters WalkerParameters = Walker->GetWalkerParameters();
302
303 // Set type and model
304 ObjectEntry->SetStringField("type", "Walker");
305 ObjectEntry->SetStringField("model", UEnumUtilities::ConvertWalkerTypeToString(WalkerParameters.WalkerType));
306 ObjectEntry->SetStringField("id", IActorInformation::Execute_GetActorID(Walker));
307
308 // Create and set the JSON object from FWeatherParameters struct
309 TSharedPtr<FJsonObject> ParametersObject = MakeShareable(new FJsonObject);
310 FJsonObjectConverter::UStructToJsonObject(FWalkerParameters::StaticStruct(), &WalkerParameters, ParametersObject.ToSharedRef());
311
312 // Remove "Points" field
313 ParametersObject->RemoveField(TEXT("points"));
314
315 if (WalkerParameters.Points.Num() >= 2)
316 {
317 // If we have at least 2 Points, re-create "points" field manually
318 // so it's compatible with ROSJsonParser Transform parsing logic.
319 TSharedPtr<FJsonObject> PointsObject = MakeShareable(new FJsonObject);
320 for (int32 i = 0; i < WalkerParameters.Points.Num(); ++i)
321 {
322 FString PointName = FString::Printf(TEXT("point%d"), i);
323
324 FTransform Transform = WalkerParameters.Points[i];
325 FVector Location = Transform.GetLocation();
326 FRotator Rotation = Transform.Rotator();
327
328 // Adding location and rotation to the point data
329 TSharedPtr<FJsonObject> PointData = MakeShareable(new FJsonObject);
330 PointData->SetNumberField(TEXT("x"), Location.X);
331 PointData->SetNumberField(TEXT("y"), Location.Y);
332 PointData->SetNumberField(TEXT("z"), Location.Z);
333 PointData->SetNumberField(TEXT("roll"), Rotation.Roll);
334 PointData->SetNumberField(TEXT("pitch"), Rotation.Pitch);
335 PointData->SetNumberField(TEXT("yaw"), Rotation.Yaw);
336
337 // Adding point data to the PointsObject
338 PointsObject->SetObjectField(PointName, PointData);
339 }
340
341 // Add created PointsObject to ParametersObject "points" field
342 ParametersObject->SetObjectField(TEXT("points"), PointsObject);
343 }
344 else
345 {
346 // else create a "spawnPoint" since we don't have enough Points in the WalkerParameters.
347 TSharedPtr<FJsonObject> SpawnPoint = MakeShareable(new FJsonObject);
348
349 FVector SpawnLocation;
350 FRotator SpawnRotation;
351 if (WalkerParameters.Points.IsEmpty())
352 {
353 // If for whatever reason Points is empty,
354 // use Walker current location and rotation.
355 SpawnLocation = Walker->GetActorLocation();
356 SpawnRotation = Walker->GetActorRotation();
357 }
358 else
359 {
360 // Else use first point which should be the spawn point of the Walker
361 FTransform Transform = WalkerParameters.Points[0];
362 SpawnLocation = Transform.GetLocation();
363 SpawnRotation = Transform.Rotator();
364 }
365
366 SetSpawnPoint(ParametersObject, SpawnLocation, SpawnRotation, Walker->GetActorScale());
367 }
368
369 // Set the parameters object in the entry
370 ObjectEntry->SetObjectField("parameters", ParametersObject);
371
372 // Add the entry to the ObjectsArray
373 ObjectsArray.Add(MakeShareable(new FJsonValueObject(ObjectEntry)));
374
375 // Set the ObjectsArray in the root JSON object
376 RootJsonObject->SetArrayField("objects", ObjectsArray);
377
378 // Serialize the root JSON object to a string
379 FString JsonString;
380 TSharedRef<TJsonWriter<TCHAR>> JsonWriter = TJsonWriterFactory<>::Create(&JsonString);
381 FJsonSerializer::Serialize(RootJsonObject.ToSharedRef(), JsonWriter);
382
383 // Save the JSON string to a file
384 bool Saved = FFileHelper::SaveStringToFile(JsonString, *FilePath);
385 if (!Saved)
386 {
387 // If saving fails, return empty string
388 return FString();
389 }
390
391 // Publish and log info
392 FString Msg = FString::Printf(TEXT("Exported Actors JSON file to: %s"), *FilePath);
394
395 return FilePath;
396}
397
398FString USimulatorJsonExporter::ExportSensorToJSON(const FString& FileName, ASensor* Sensor)
399{
400 FString FilePath;
401 if (!Sensor)
402 {
403 return FilePath;
404 }
405
406 // Remove invalid characters from the filename, and replace them with undescores.
407 // Will not remove spaces, maybe they should be?
408 FString ValidatedFileName = FPaths::MakeValidFileName(FileName, TEXT('_'));
409
410 FilePath = CreateUniqueFilePath(ValidatedFileName);
411
412 ESensorTypes SensorType = Sensor->GetSensorType();
413 FString SensorTypeString = UEnumUtilities::ConvertSensorTypeToString(SensorType);
414
415 TSharedPtr<FJsonObject> ParametersObject = MakeShareable(new FJsonObject);
416
417 bool Success = false;
418
419 switch (SensorType)
420 {
422 {
423 ALidar* LidarPtr = Cast<ALidar>(Sensor);
424 if (LidarPtr)
425 {
426 FLidarParameters LidarParameters = LidarPtr->GetLidarParameters();
427 FJsonObjectConverter::UStructToJsonObject(FLidarParameters::StaticStruct(), &LidarParameters, ParametersObject.ToSharedRef());
428 Success = true;
429 }
430 }
431 break;
432
433 // RGB and Semantic segmentation cameras share same parameters
436 {
437 ACamera* CameraPtr = Cast<ACamera>(Sensor);
438 if (CameraPtr)
439 {
440 ParametersObject = CameraParametersToJSONObject(CameraPtr->GetCameraParameters());
441 Success = true;
442 }
443 }
444 break;
445
447 {
448 AThermalCamera* ThermalCameraPtr = Cast<AThermalCamera>(Sensor);
449 if (ThermalCameraPtr)
450 {
451 FThermalCameraParameters ThermalCameraParameters = ThermalCameraPtr->GetThermalCameraParameters();
452 FJsonObjectConverter::UStructToJsonObject(FThermalCameraParameters::StaticStruct(), &ThermalCameraParameters, ParametersObject.ToSharedRef());
453 Success = true;
454 }
455 }
456 break;
457
459 {
460 ACamera* CameraPtr = Cast<ACamera>(Sensor);
461 if (CameraPtr)
462 {
463 ADepthCamera* DepthCameraPtr = Cast<ADepthCamera>(Sensor);
464 if (DepthCameraPtr)
465 {
466 FDepthCameraParameters DepthCameraParameters = DepthCameraPtr->GetDepthCameraParameters();
467 FJsonObjectConverter::UStructToJsonObject(FDepthCameraParameters::StaticStruct(), &DepthCameraParameters, ParametersObject.ToSharedRef());
468 }
469 Success = true;
470 }
471 }
472 break;
473
475 {
476 ADVSCamera* DVSPtr = Cast<ADVSCamera>(Sensor);
477 if (DVSPtr)
478 {
479 FDVSCameraParameters CameraParameters = DVSPtr->GetDVSCameraParameters();
480 FJsonObjectConverter::UStructToJsonObject(FDVSCameraParameters::StaticStruct(), &CameraParameters, ParametersObject.ToSharedRef());
481 Success = true;
482 }
483 }
484 break;
485
487 {
488 ARadar* RadaPtr = Cast<ARadar>(Sensor);
489 if (RadaPtr)
490 {
491 FRadarParameters RadarParameters = RadaPtr->GetRadarParameters();
492 FJsonObjectConverter::UStructToJsonObject(FRadarParameters::StaticStruct(), &RadarParameters, ParametersObject.ToSharedRef());
493 Success = true;
494 }
495 }
496 break;
497
498 // Don't export these sensors since these are automatically created for Vehicles
502#if WITH_EDITOR
503 UE_LOG(LogTemp, Warning, TEXT("ROSJsonExporter.cpp: Exporting Collision/Transform or Overlap sensor is not supported."));
504#endif
505 break;
506
507 default:
508 break;
509 }
510
511 if (!Success)
512 {
513 return FString();
514 }
515
516 // Root Json object
517 TSharedPtr<FJsonObject> RootJsonObject = MakeShareable(new FJsonObject);
518
519 // Json structure "Objects" array
520 TArray<TSharedPtr<FJsonValue>> ObjectsArray;
521 TSharedPtr<FJsonObject> ObjectEntry = MakeShareable(new FJsonObject);
522
523 // Set type and model
524 ObjectEntry->SetStringField("type", "Sensor");
525 ObjectEntry->SetStringField("model", SensorTypeString);
526 ObjectEntry->SetStringField("id", IActorInformation::Execute_GetActorID(Sensor));
527
528 FVector SpawnLocation = Sensor->GetActorLocation();
529 FRotator SpawnRotation = Sensor->GetActorRotation();
530 SetSpawnPoint(ObjectEntry, SpawnLocation, SpawnRotation, Sensor->GetActorScale());
531
532 // Set the parameters object to ObjectEntry
533 ObjectEntry->SetObjectField("parameters", ParametersObject);
534
535 // Add the entry to ObjectsArray
536 ObjectsArray.Add(MakeShareable(new FJsonValueObject(ObjectEntry)));
537
538 // Set the ObjectsArray in the root JSON object
539 RootJsonObject->SetArrayField("objects", ObjectsArray);
540
541 // Serialize the root JSON object to a string
542 FString JsonString;
543 TSharedRef<TJsonWriter<TCHAR>> JsonWriter = TJsonWriterFactory<>::Create(&JsonString);
544 FJsonSerializer::Serialize(RootJsonObject.ToSharedRef(), JsonWriter);
545
546 // Save the JSON string to a file
547 bool Saved = FFileHelper::SaveStringToFile(JsonString, *FilePath);
548 if (!Saved)
549 {
550 return FString();
551 }
552
553 // Publish and log info
554 FString Msg = FString::Printf(TEXT("Exported Actors JSON file to: %s"), *FilePath);
556
557 return FilePath;
558}
559
560TArray<TSharedPtr<FJsonValue>> USimulatorJsonExporter::ParseLidars(const TArray<ALidar*>& Lidars)
561{
562 TArray<TSharedPtr<FJsonValue>> LidarArray;
563
564 for (ALidar* Lidar : Lidars)
565 {
566 if (!Lidar)
567 {
568 continue;
569 }
570
571 FTransform Transform = Lidar->GetRootComponent()->GetRelativeTransform();
572 TSharedPtr<FJsonObject> SensorObject = CreateSensorJSONObject(Cast<ASensor>(Lidar), "Lidar");
573
574 TSharedPtr<FJsonObject> ParametersObject = MakeShareable(new FJsonObject);
575 FLidarParameters Params = Lidar->GetLidarParameters();
576
577 FJsonObjectConverter::UStructToJsonObject(FLidarParameters::StaticStruct(), &Params, ParametersObject.ToSharedRef());
578
579 SensorObject->SetObjectField("parameters", ParametersObject);
580
581 LidarArray.Add(MakeShareable(new FJsonValueObject(SensorObject)));
582 }
583
584 return LidarArray;
585}
586
587TArray<TSharedPtr<FJsonValue>> USimulatorJsonExporter::ParseCameras(const TArray<ACamera*>& Cameras)
588{
589 TArray<TSharedPtr<FJsonValue>> CameraArray;
590
591 for (ACamera* Camera : Cameras)
592 {
593 if (!Camera)
594 {
595 continue;
596 }
597
598 FTransform Transform = Camera->GetRootComponent()->GetRelativeTransform();
599 TSharedPtr<FJsonObject> SensorObject = CreateSensorJSONObject(Cast<ASensor>(Camera), "RGBCamera");
600
601 FCameraBaseParameters Params = Camera->GetCameraParameters();
602
603 TSharedPtr<FJsonObject> ParametersObject = CameraParametersToJSONObject(Params);
604
605 SensorObject->SetObjectField("parameters", ParametersObject);
606
607 CameraArray.Add(MakeShareable(new FJsonValueObject(SensorObject)));
608 }
609
610 return CameraArray;
611}
612
613TArray<TSharedPtr<FJsonValue>> USimulatorJsonExporter::ParseDepthCameras(const TArray<ADepthCamera*>& DepthCameras)
614{
615 TArray<TSharedPtr<FJsonValue>> CameraArray;
616
617 for (ADepthCamera* Camera : DepthCameras)
618 {
619 if (!Camera)
620 {
621 continue;
622 }
623
624 FTransform Transform = Camera->GetRootComponent()->GetRelativeTransform();
625 TSharedPtr<FJsonObject> SensorObject = CreateSensorJSONObject(Cast<ASensor>(Camera), "DepthCamera");
626
627 TSharedPtr<FJsonObject> DepthCameraParametersObject = MakeShareable(new FJsonObject);
628
629 FDepthCameraParameters Params = Camera->GetDepthCameraParameters();
630 FJsonObjectConverter::UStructToJsonObject(FDepthCameraParameters::StaticStruct(), &Params, DepthCameraParametersObject.ToSharedRef());
631
632 SensorObject->SetObjectField("parameters", DepthCameraParametersObject);
633
634 CameraArray.Add(MakeShareable(new FJsonValueObject(SensorObject)));
635 }
636
637 return CameraArray;
638}
639
640TArray<TSharedPtr<FJsonValue>> USimulatorJsonExporter::ParseThermalCameras(const TArray<AThermalCamera*>& ThermalCameras)
641{
642 TArray<TSharedPtr<FJsonValue>> CameraArray;
643
644 for (AThermalCamera* Camera : ThermalCameras)
645 {
646 if (!Camera)
647 {
648 continue;
649 }
650
651 FTransform Transform = Camera->GetRootComponent()->GetRelativeTransform();
652 TSharedPtr<FJsonObject> SensorObject = CreateSensorJSONObject(Cast<ASensor>(Camera), "ThermalCamera");
653
654 TSharedPtr<FJsonObject> ThermalCameraParametersObject = MakeShareable(new FJsonObject);
655
656 FThermalCameraParameters Params = Camera->GetThermalCameraParameters();
657 FJsonObjectConverter::UStructToJsonObject(FThermalCameraParameters::StaticStruct(), &Params, ThermalCameraParametersObject.ToSharedRef());
658
659 SensorObject->SetObjectField("parameters", ThermalCameraParametersObject);
660
661 CameraArray.Add(MakeShareable(new FJsonValueObject(SensorObject)));
662 }
663
664 return CameraArray;
665}
666
667TArray<TSharedPtr<FJsonValue>> USimulatorJsonExporter::ParseDVSCameras(const TArray<ADVSCamera*>& DVSCameras)
668{
669 TArray<TSharedPtr<FJsonValue>> CameraArray;
670
671 for (ADVSCamera* Camera : DVSCameras)
672 {
673 if (!Camera)
674 {
675 continue;
676 }
677
678 FTransform Transform = Camera->GetRootComponent()->GetRelativeTransform();
679 TSharedPtr<FJsonObject> SensorObject = CreateSensorJSONObject(Cast<ASensor>(Camera), "DVSCamera");
680
681 TSharedPtr<FJsonObject> DVSCameraParametersObject = MakeShareable(new FJsonObject);
682
683 FDVSCameraParameters Params = Camera->GetDVSCameraParameters();
684 FJsonObjectConverter::UStructToJsonObject(FDVSCameraParameters::StaticStruct(), &Params, DVSCameraParametersObject.ToSharedRef());
685
686 SensorObject->SetObjectField("parameters", DVSCameraParametersObject);
687
688 CameraArray.Add(MakeShareable(new FJsonValueObject(SensorObject)));
689 }
690
691 return CameraArray;
692}
693
694TArray<TSharedPtr<FJsonValue>> USimulatorJsonExporter::ParseRadars(const TArray<ARadar*>& Radars)
695{
696 TArray<TSharedPtr<FJsonValue>> RadarArray;
697
698 for (ARadar* Radar : Radars)
699 {
700 if (!Radar)
701 {
702 continue;
703 }
704
705 FTransform Transform = Radar->GetRootComponent()->GetRelativeTransform();
706 TSharedPtr<FJsonObject> SensorObject = CreateSensorJSONObject(Cast<ASensor>(Radar), "Radar");
707
708 TSharedPtr<FJsonObject> RadarParametersObject = MakeShareable(new FJsonObject);
709
710 FRadarParameters Params = Radar->GetRadarParameters();
711 FJsonObjectConverter::UStructToJsonObject(FRadarParameters::StaticStruct(), &Params, RadarParametersObject.ToSharedRef());
712
713 SensorObject->SetObjectField("parameters", RadarParametersObject);
714
715 RadarArray.Add(MakeShareable(new FJsonValueObject(SensorObject)));
716 }
717
718 return RadarArray;
719}
720
721TSharedPtr<FJsonObject> USimulatorJsonExporter::CreateSensorJSONObject(const ASensor* SensorPtr, FString SensorName)
722{
723 TSharedPtr<FJsonObject> SensorObject = MakeShareable(new FJsonObject);
724
725 if (!SensorPtr)
726 {
727#if WITH_EDITOR
728 UE_LOG(LogTemp, Warning, TEXT("ROSJsonExporter.cpp: SensorPtr is nullptr!"));
729#endif
730 return SensorObject;
731 }
732
733 FJsonObject* SensorJsonObject = SensorObject.Get();
734 SensorJsonObject->SetStringField("type", "sensor");
735 SensorJsonObject->SetStringField("model", SensorName);
736 SensorJsonObject->SetStringField("name", SensorPtr->GetSensorName());
737 SensorJsonObject->SetStringField("id", IActorInformation::Execute_GetActorID(SensorPtr));
738 SensorJsonObject->SetStringField("attachedToComponent", SensorPtr->AttachedToComponent);
739 SensorJsonObject->SetStringField("attachedToBone", SensorPtr->AttachedToBone.ToString());
740
741 FTransform Transform = SensorPtr->GetRootComponent()->GetRelativeTransform();
742 FVector SensorLocation = Transform.GetLocation();
743 FRotator SensorRotation = Transform.Rotator();
744 SetSpawnPoint(SensorObject, SensorLocation, SensorRotation, Transform.GetScale3D());
745
746 return SensorObject;
747}
748
750{
751 TSharedPtr<FJsonObject> ParametersObject = MakeShareable(new FJsonObject);
752 FJsonObjectConverter::UStructToJsonObject(FCameraBaseParameters::StaticStruct(), &Parameters, ParametersObject.ToSharedRef());
753
754 return ParametersObject;
755}
756
757void USimulatorJsonExporter::SetSpawnPoint(TSharedPtr<FJsonObject>& ObjectEntry, const FVector& Location, const FRotator& Rotation, const FVector& Scale)
758{
759 TSharedPtr<FJsonObject> SpawnPoint = MakeShareable(new FJsonObject);
760
761 // Set Location
762 SpawnPoint->SetNumberField("x", Location.X);
763 SpawnPoint->SetNumberField("y", Location.Y);
764 SpawnPoint->SetNumberField("z", Location.Z);
765
766 // Set Rotation
767 SpawnPoint->SetNumberField("roll", Rotation.Roll);
768 SpawnPoint->SetNumberField("pitch", Rotation.Pitch);
769 SpawnPoint->SetNumberField("yaw", Rotation.Yaw);
770
771 // Set Scale
772 SpawnPoint->SetNumberField("scaleX", Scale.X);
773 SpawnPoint->SetNumberField("scaleY", Scale.Y);
774 SpawnPoint->SetNumberField("scaleZ", Scale.Z);
775
776 ObjectEntry->SetObjectField("spawnPoint", SpawnPoint);
777}
778
779void USimulatorJsonExporter::SetDroneParameters(TSharedPtr<FJsonObject>& ObjectEntry, AVehicle* VehiclePtr)
780{
781 APIDDrone* DronePtr = Cast<APIDDrone>(VehiclePtr);
782 if (!ObjectEntry.IsValid() || !DronePtr)
783 {
784 return;
785 }
786
787 TSharedPtr<FJsonObject> VehicleParams = MakeShareable(new FJsonObject);
788
789 FDroneParameters DroneParams = DronePtr->GetDroneParameters();
790
791 FString DroneActionString = UEnum::GetDisplayValueAsText(DroneParams.DroneAction).ToString();
792 VehicleParams->SetStringField("droneAction", DroneActionString);
793
794 FString DroneEndActionString = UEnum::GetDisplayValueAsText(DroneParams.DroneEndAction).ToString();
795 VehicleParams->SetStringField("DroneEndAction", DroneEndActionString);
796
797 if (!DroneParams.Points.IsEmpty())
798 {
799 // Create an array to hold the points
800 TArray<TSharedPtr<FJsonValue>> PointsArray;
801 PointsArray.Reserve(DroneParams.Points.Num());
802
803 for (const FTransform& Transform : DroneParams.Points)
804 {
805 TSharedPtr<FJsonObject> PointObject = MakeShareable(new FJsonObject);
806
807 // Serialize translation
808 FVector Translation = Transform.GetLocation();
809 PointObject->SetNumberField("X", Translation.X);
810 PointObject->SetNumberField("Y", Translation.Y);
811 PointObject->SetNumberField("Z", Translation.Z);
812
813 // Serialize rotation (as a rotator or quaternion)
814 FRotator Rotation = Transform.GetRotation().Rotator();
815 PointObject->SetNumberField("Pitch", Rotation.Pitch);
816 PointObject->SetNumberField("Yaw", Rotation.Yaw);
817 PointObject->SetNumberField("Roll", Rotation.Roll);
818
819 // Add the point object to the array
820 PointsArray.Add(MakeShareable(new FJsonValueObject(PointObject)));
821 }
822
823 // Add the points array to the VehicleParams JSON object
824 VehicleParams->SetArrayField("points", PointsArray);
825 }
826
827 // Add the VehicleParams object to the main VehicleObject
828 ObjectEntry->SetObjectField("parameters", VehicleParams);
829}
830
832{
833 if (FileName.IsEmpty())
834 {
835 // If user didn't specify file name, give it a default name
836 FileName = "ExportedJsonFile";
837 }
838
839 // Trim leading and trailing whitespace
840 FileName = FileName.TrimStartAndEnd();
841
842 // Check for invalid characters
843 FString InvalidChars = TEXT("\\/:*?\"<>|");
844 for (TCHAR InvalidChar : InvalidChars)
845 {
846 FileName.ReplaceCharInline(InvalidChar, TEXT('_'), ESearchCase::CaseSensitive);
847 }
848
849 FString DataPathFolder = UAgrarsensePaths::GetDataFolder();
850 FString BaseFileName = FileName;
851 FString FinalPath;
852
853 int32 FileIndex = 0;
854
855 // To avoid overriding existing file,
856 // find available filename by adding FILENAME_[NUM].json to the end
857 do
858 {
859 FString IndexString = (FileIndex > 0) ? FString::Printf(TEXT("_%d"), FileIndex) : FString();
860 FinalPath = DataPathFolder / FString::Printf(TEXT("ExportedJsonFiles/%s%s.json"), *BaseFileName, *IndexString);
861 FileIndex++;
862 } while (FPlatformFileManager::Get().GetPlatformFile().FileExists(*FinalPath));
863
864
865 return FinalPath;
866}
867
868bool USimulatorJsonExporter::ExportCaptureLocations(TArray<FTransform> Transforms)
869{
870 FString AsDrone = ExportAsDroneFollowPath("DroneFollowPathExport", Transforms);
871 FString AsDataCapture = ExportAsDataCapture("DataCaptureExport", Transforms);
872
873 if (!AsDrone.IsEmpty() || !AsDataCapture.IsEmpty())
874 {
875 return true;
876 }
877
878 return false;
879}
880
881FString USimulatorJsonExporter::ExportAsDroneFollowPath(const FString& FileName, TArray<FTransform>& Transforms)
882{
883 if (Transforms.IsEmpty())
884 {
885 return FString();
886 }
887
888 // Export as Drone follow path with dataCapture, here's example json.
889
890 FString ValidatedFileName = FPaths::MakeValidFileName(FileName, TEXT('_'));
891 FString FilePath = CreateUniqueFilePath(ValidatedFileName);
892
893 TSharedPtr<FJsonObject> RootJsonObject = MakeShareable(new FJsonObject);
894 TArray<TSharedPtr<FJsonValue>> ObjectsArray;
895
896 // Create object entry that contains both type and parameters
897 TSharedPtr<FJsonObject> ObjectEntry = MakeShareable(new FJsonObject);
898 ObjectEntry->SetStringField(TEXT("type"), TEXT("Vehicle"));
899 ObjectEntry->SetStringField(TEXT("model"), TEXT("Drone"));
900 ObjectEntry->SetStringField(TEXT("id"), TEXT("drone"));
901 ObjectEntry->SetBoolField(TEXT("teleportSpectator"), true);
902 ObjectEntry->SetBoolField(TEXT("followObject"), true);
903
904 // Add spawnPoint to the object entry
905 TSharedPtr<FJsonObject> SpawnPointObject = MakeShareable(new FJsonObject);
906 const FVector SpawnLocation = Transforms[0].GetLocation();
907 const FRotator SpawnRotation = Transforms[0].Rotator();
908 SpawnPointObject->SetNumberField(TEXT("x"), SpawnLocation.X);
909 SpawnPointObject->SetNumberField(TEXT("y"), SpawnLocation.Y);
910 SpawnPointObject->SetNumberField(TEXT("z"), SpawnLocation.Z);
911 SpawnPointObject->SetNumberField(TEXT("roll"), SpawnRotation.Roll);
912 SpawnPointObject->SetNumberField(TEXT("pitch"), SpawnRotation.Pitch);
913 SpawnPointObject->SetNumberField(TEXT("yaw"), SpawnRotation.Yaw);
914
915 ObjectEntry->SetObjectField(TEXT("spawnPoint"), SpawnPointObject);
916
917 TSharedPtr<FJsonObject> ParametersObject = MakeShareable(new FJsonObject);
918 ParametersObject->SetStringField(TEXT("droneAction"), TEXT("FollowPath"));
919 ParametersObject->SetStringField(TEXT("droneEndAction"), TEXT("destroy"));
920 ParametersObject->SetBoolField(TEXT("showForwardArrow"), true);
921
922 // Create Points Object
923 TSharedPtr<FJsonObject> PointsObject = MakeShareable(new FJsonObject);
924 for (int32 i = 0; i < Transforms.Num(); ++i)
925 {
926 FString PointName = FString::Printf(TEXT("point%d"), i);
927 const FVector Location = Transforms[i].GetLocation();
928 const FRotator Rotation = Transforms[i].Rotator();
929
930 TSharedPtr<FJsonObject> PointData = MakeShareable(new FJsonObject);
931 PointData->SetNumberField(TEXT("x"), Location.X);
932 PointData->SetNumberField(TEXT("y"), Location.Y);
933 PointData->SetNumberField(TEXT("z"), Location.Z);
934 PointData->SetNumberField(TEXT("roll"), Rotation.Roll);
935 PointData->SetNumberField(TEXT("pitch"), Rotation.Pitch);
936 PointData->SetNumberField(TEXT("yaw"), Rotation.Yaw);
937
938 PointsObject->SetObjectField(PointName, PointData);
939 }
940
941 ParametersObject->SetObjectField(TEXT("points"), PointsObject);
942 ObjectEntry->SetObjectField(TEXT("parameters"), ParametersObject);
943
944 ObjectsArray.Add(MakeShareable(new FJsonValueObject(ObjectEntry)));
945
946 RootJsonObject->SetArrayField(TEXT("objects"), ObjectsArray);
947
948 FString JsonString;
949 TSharedRef<TJsonWriter<TCHAR>> JsonWriter = TJsonWriterFactory<>::Create(&JsonString);
950 FJsonSerializer::Serialize(RootJsonObject.ToSharedRef(), JsonWriter);
951
952 if (!FFileHelper::SaveStringToFile(JsonString, *FilePath))
953 {
954 return FString();
955 }
956
957 SimulatorLog::Log(FString::Printf(TEXT("Exported Actors JSON file to: %s"), *FilePath));
958 return FilePath;
959}
960
961FString USimulatorJsonExporter::ExportAsDataCapture(const FString& FileName, TArray<FTransform>& Transforms)
962{
963 if (Transforms.IsEmpty())
964 {
965 return FString();
966 }
967
968 FString ValidatedFileName = FPaths::MakeValidFileName(FileName, TEXT('_'));
969 FString FilePath = CreateUniqueFilePath(ValidatedFileName);
970
971 TSharedPtr<FJsonObject> RootJsonObject = MakeShareable(new FJsonObject);
972 TArray<TSharedPtr<FJsonValue>> ObjectsArray;
973
974 // Create object entry that contains both type and parameters
975 TSharedPtr<FJsonObject> ObjectEntry = MakeShareable(new FJsonObject);
976 ObjectEntry->SetStringField(TEXT("type"), TEXT("dataCapture"));
977
978 TSharedPtr<FJsonObject> ParametersObject = MakeShareable(new FJsonObject);
979 TSharedPtr<FJsonObject> PointsObject = MakeShareable(new FJsonObject);
980
981 for (int32 i = 0; i < Transforms.Num(); ++i)
982 {
983 FString PointName = FString::Printf(TEXT("point%d"), i);
984 const FVector Location = Transforms[i].GetLocation();
985 const FRotator Rotation = Transforms[i].Rotator();
986
987 TSharedPtr<FJsonObject> PointData = MakeShareable(new FJsonObject);
988 PointData->SetNumberField(TEXT("x"), Location.X);
989 PointData->SetNumberField(TEXT("y"), Location.Y);
990 PointData->SetNumberField(TEXT("z"), Location.Z);
991 PointData->SetNumberField(TEXT("roll"), Rotation.Roll);
992 PointData->SetNumberField(TEXT("pitch"), Rotation.Pitch);
993 PointData->SetNumberField(TEXT("yaw"), Rotation.Yaw);
994
995 PointsObject->SetObjectField(PointName, PointData);
996 }
997
998 ParametersObject->SetBoolField(TEXT("useGPSLocation"), false);
999 ParametersObject->SetBoolField(TEXT("captureRotatedViews"), false);
1000 ParametersObject->SetBoolField(TEXT("zIsHeightAboveGround"), false);
1001 ParametersObject->SetObjectField(TEXT("points"), PointsObject);
1002
1003 ObjectEntry->SetObjectField(TEXT("parameters"), ParametersObject);
1004 ObjectsArray.Add(MakeShareable(new FJsonValueObject(ObjectEntry)));
1005
1006 RootJsonObject->SetArrayField(TEXT("objects"), ObjectsArray);
1007
1008 FString JsonString;
1009 TSharedRef<TJsonWriter<TCHAR>> JsonWriter = TJsonWriterFactory<>::Create(&JsonString);
1010 FJsonSerializer::Serialize(RootJsonObject.ToSharedRef(), JsonWriter);
1011
1012 if (!FFileHelper::SaveStringToFile(JsonString, *FilePath))
1013 {
1014 return FString();
1015 }
1016
1017 SimulatorLog::Log(FString::Printf(TEXT("Exported Actors JSON file to: %s"), *FilePath));
1018 return FilePath;
1019}
ESensorTypes
Definition: SensorTypes.h:15
@ SemanticSegmentationCamera
EVehicleTypes
Definition: VehicleTypes.h:15
Definition: Camera.h:53
FCameraBaseParameters GetCameraParameters()
Definition: Camera.h:91
FDVSCameraParameters GetDVSCameraParameters() const
Definition: DVSCamera.h:58
FDepthCameraParameters GetDepthCameraParameters()
Definition: DepthCamera.h:44
Definition: Lidar.h:35
FLidarParameters GetLidarParameters() const
Definition: Lidar.h:83
FDroneParameters GetDroneParameters() const
Definition: PIDDrone.h:68
Definition: Radar.h:26
FRadarParameters GetRadarParameters()
Definition: Radar.h:64
Definition: Sensor.h:45
FString GetSensorName() const
Definition: Sensor.h:96
virtual ESensorTypes GetSensorType() const
Definition: Sensor.h:65
FString AttachedToComponent
Definition: Sensor.h:286
FName AttachedToBone
Definition: Sensor.h:289
FThermalCameraParameters GetThermalCameraParameters() const
Definition: ThermalCamera.h:33
Definition: Walker.h:28
static void Log(const FString &Message, bool LogToTextFile=true, bool LogToROS=true)
static FString GetDataFolder()
static FString ConvertSensorTypeToString(ESensorTypes Sensortype)
static FString ConvertWalkerTypeToString(EWalkerType WalkerType)
static bool ExportCaptureLocations(TArray< FTransform > Transforms)
static FString ExportWalkerToJSON(const FString &FileName, AWalker *Walker)
static FString ExportWeatherToJSON(const FString &FileName, const FWeatherParameters &WeatherParameters)
static FString CreateUniqueFilePath(FString FileName)
static FString ExportVehicleAndSensorsToJSON(FString FileName, AVehicle *Vehicle, bool OverrideTransform=false, const FTransform &Transform=FTransform())
static FString ExportSensorToJSON(const FString &FileName, ASensor *Sensor)
static TArray< TSharedPtr< FJsonValue > > ParseDepthCameras(const TArray< ADepthCamera * > &DepthCameras)
static FString ExportAsDroneFollowPath(const FString &FileName, TArray< FTransform > &Transforms)
static TArray< TSharedPtr< FJsonValue > > ParseDVSCameras(const TArray< ADVSCamera * > &DVSCameras)
static TArray< TSharedPtr< FJsonValue > > ParseLidars(const TArray< ALidar * > &Lidars)
static TArray< TSharedPtr< FJsonValue > > ParseThermalCameras(const TArray< AThermalCamera * > &ThermalCameras)
static TSharedPtr< FJsonObject > CreateSensorJSONObject(const ASensor *SensorPtr, FString SensorName)
static FString ExportInstancedActorsToJSON(FString FileName, const TArray< AInstancedActor * > &Actors)
static FString ExportAsDataCapture(const FString &FileName, TArray< FTransform > &Transforms)
static void SetSpawnPoint(TSharedPtr< FJsonObject > &ObjectEntry, const FVector &Location, const FRotator &Rotation, const FVector &Scale)
static void SetDroneParameters(TSharedPtr< FJsonObject > &ObjectEntry, AVehicle *VehiclePtr)
static TSharedPtr< FJsonObject > CameraParametersToJSONObject(const FCameraBaseParameters &Parameters)
static TArray< TSharedPtr< FJsonValue > > ParseCameras(const TArray< ACamera * > &Cameras)
static TArray< TSharedPtr< FJsonValue > > ParseRadars(const TArray< ARadar * > &Radars)
EDroneEndAction DroneEndAction
EDroneAction DroneAction
TArray< FTransform > Points
TArray< FTransform > Points
EWalkerType WalkerType