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