CARLA
Loading...
Searching...
No Matches
JsonFileManagerLibrary.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
8
9#include <util/ue-header-guard-begin.h>
10#include "JsonObjectConverter.h"
11#include "Misc/FileHelper.h"
12#include "HAL/PlatformFileManager.h"
13#include "Serialization/JsonSerializer.h"
14#include "Dom/JsonObject.h"
15#include "Kismet/KismetStringLibrary.h"
16#include <util/ue-header-guard-end.h>
17
18DEFINE_LOG_CATEGORY_STATIC(LogJsonFileManagerLibrary, Verbose, All);
19
20bool UJsonFileManagerLibrary::ReadStringFromFile(const FString& FilePath, FString& DataRead)
21{
22 if(!FPlatformFileManager::Get().GetPlatformFile().FileExists(*FilePath))
23 {
24 DataRead = "";
25 return false;
26 }
27
28 if(!FFileHelper::LoadFileToString(DataRead, *FilePath))
29 {
30 DataRead = "";
31 return false;
32 }
33
34 return true;
35}
36
37bool UJsonFileManagerLibrary::WriteStringFromFile(const FString& FilePath, const FString& DataToWrite)
38{
39 if(!FFileHelper::SaveStringToFile(DataToWrite, *FilePath))
40 {
41 return false;
42 }
43
44 return true;
45}
46
47bool UJsonFileManagerLibrary::ReadJson(const FString& JsonFilePath, TSharedPtr<FJsonObject>& JsonObject)
48{
49 FString JsonString;
50 const bool bReadSuccess = UJsonFileManagerLibrary::ReadStringFromFile(JsonFilePath, JsonString);
51 if(!bReadSuccess)
52 {
53 return false;
54 }
55
56 if(!FJsonSerializer::Deserialize(TJsonReaderFactory<>::Create(JsonString), JsonObject))
57 {
58 return false;
59 }
60
61 return true;
62}
63
64bool UJsonFileManagerLibrary::WriteJson(const FString& JsonFilePath, const TSharedPtr<FJsonObject> JsonObject)
65{
66 if(!JsonObject.IsValid())
67 {
68 return false;
69 }
70
71 FString JsonString;
72 if(!FJsonSerializer::Serialize(JsonObject.ToSharedRef(), TJsonWriterFactory<>::Create(&JsonString)))
73 {
74 return false;
75 }
76
77 const bool bWriteSuccess = UJsonFileManagerLibrary::WriteStringFromFile(JsonFilePath, JsonString);
78 if(!bWriteSuccess)
79 {
80 return false;
81 }
82
83 return true;
84}
85
87{
88 InOutVector *= 100.f;
89 InOutVector.X = FGenericPlatformMath::RoundToFloat(InOutVector.X);
90 InOutVector.Y = FGenericPlatformMath::RoundToFloat(InOutVector.Y);
91 InOutVector.Z = FGenericPlatformMath::RoundToFloat(InOutVector.Z);
92 InOutVector /= 100.f;
93}
94
95FVector UJsonFileManagerLibrary::JsonObjectToVector(const TSharedPtr<FJsonObject>& JsonObject)
96{
97 FVector Vector = FVector::ZeroVector;
98 if(!JsonObject.IsValid())
99 {
100 return Vector;
101 }
102
103 const FString VectorStringX = JsonObject->GetStringField(TEXT("X"));
104 const FString VectorStringY = JsonObject->GetStringField(TEXT("Y"));
105 const FString VectorStringZ = JsonObject->GetStringField(TEXT("Z"));
106 Vector = FVector{ FCString::Atof(*VectorStringX),FCString::Atof(*VectorStringY),FCString::Atof(*VectorStringZ) };
107
108 /* Same result than the previous.
109 float ValueParsedX, ValueParsedY, ValueParsedZ;
110 FDefaultValueHelper::ParseFloat(JsonObject->GetStringField(TEXT("X")), ValueParsedX);
111 Vector.X = ValueParsedX;
112 FDefaultValueHelper::ParseFloat(JsonObject->GetStringField(TEXT("Y")), ValueParsedY);
113 Vector.Y = ValueParsedY;
114 FDefaultValueHelper::ParseFloat(JsonObject->GetStringField(TEXT("Z")), ValueParsedZ);
115 Vector.Z = ValueParsedZ;*/
116
118
119 return Vector;
120}
121
122TSharedPtr<FJsonObject> UJsonFileManagerLibrary::VectorToJsonObject(const FVector& Vector)
123{
124 const TSharedPtr<FJsonObject> JsonObject = MakeShared<FJsonObject>();
125 JsonObject->SetStringField(TEXT("X"), FString::SanitizeFloat(Vector.X));
126 JsonObject->SetStringField(TEXT("Y"), FString::SanitizeFloat(Vector.Y));
127 JsonObject->SetStringField(TEXT("Z"), FString::SanitizeFloat(Vector.Z));
128
129 return JsonObject;
130}
131
132bool UJsonFileManagerLibrary::SaveIMUDataToJson(const FString& JsonFilePath, const FVector& Accelerometer,
133 const FVector& Gyroscope, float Compass, const FString& FrameNumber)
134{
135 TArray<TSharedPtr<FJsonValue>> ArrayValue;
136 TSharedPtr<FJsonObject> JsonDataObject = GetSensorJsonData(JsonFilePath, ArrayValue);
137
138 // Accelerometer and Gyroscope
139 const TSharedPtr<FJsonObject> IMUDataObject = MakeShared<FJsonObject>();
140 IMUDataObject->SetStringField(TEXT("Frame"), FrameNumber);
141 IMUDataObject->SetObjectField(TEXT("Accelerometer"), VectorToJsonObject(Accelerometer));
142 IMUDataObject->SetObjectField( TEXT("Gyroscope"), VectorToJsonObject(Gyroscope));
143
144 // Compass
145 const TSharedPtr<FJsonObject> CompassJsonObject = MakeShared<FJsonObject>();
146 FString Heading = Compass > 270.5f || Compass < 89.5f ? "N" : "";
147 Heading += Compass > 90.5f && Compass < 269.5f ? "S" : "";
148 Heading += Compass > 0.5f && Compass < 179.5f ? "E" : "";
149 Heading += Compass > 180.5f && Compass < 359.5f ? "W" : "";
150 CompassJsonObject->SetStringField(TEXT("Degrees"), FString::SanitizeFloat(Compass));
151 CompassJsonObject->SetStringField(TEXT("Sign"), Heading);
152 IMUDataObject->SetObjectField(TEXT("Compass"), CompassJsonObject);
153
154 const bool bWriteSuccess = SaveSensorJsonData(JsonFilePath, IMUDataObject, JsonDataObject, ArrayValue);
155 return bWriteSuccess;
156}
157
158bool UJsonFileManagerLibrary::SaveGnssDataToJson(const FString& JsonFilePath, double Altitude, double Latitude,
159 double Longitude, const FString& FrameNumber)
160{
161 TArray<TSharedPtr<FJsonValue>> ArrayValue;
162 TSharedPtr<FJsonObject> JsonDataObject = GetSensorJsonData(JsonFilePath, ArrayValue);
163
164 const TSharedPtr<FJsonObject> IMUDataObject = MakeShared<FJsonObject>();
165 IMUDataObject->SetStringField(TEXT("Frame"), FrameNumber);
166 IMUDataObject->SetStringField(TEXT("Altitude"), FString::SanitizeFloat(Altitude));
167 IMUDataObject->SetStringField( TEXT("Latitude"), FString::SanitizeFloat(Latitude));
168 IMUDataObject->SetStringField(TEXT("Longitude"), FString::SanitizeFloat(Longitude));
169
170 const bool bWriteSuccess = SaveSensorJsonData(JsonFilePath, IMUDataObject, JsonDataObject, ArrayValue);
171 return bWriteSuccess;
172}
173
174
175bool UJsonFileManagerLibrary::SaveLidarDataToPly(const FString& FilePath, const TArray<float>& PointArray, int ArrayElementSize)
176{
177 FString DataToWrite;
178 const bool bReadSuccess = UJsonFileManagerLibrary::ReadStringFromFile(FilePath, DataToWrite);
179 if(!bReadSuccess)
180 {
181 DataToWrite = "";
182 }
183
184 FString LineTerminator = "\n";
185
186#if PLATFORM_WINDOWS
187 LineTerminator = LINE_TERMINATOR;
188#endif
189
190 // Create header if no data exist
191 DataToWrite += FString("ply") + LineTerminator +
192 FString("format ascii 1.0") + LineTerminator +
193 FString("element vertex ") + FString::FromInt(PointArray.Num()/ArrayElementSize) + LineTerminator +
194 FString("property float32 x") + LineTerminator +
195 FString("property float32 y") + LineTerminator +
196 FString("property float32 z") + LineTerminator +
197 FString("property float32 I") + LineTerminator +
198 FString("end_header") + LineTerminator;
199
200 for(SIZE_T i = 0; i < PointArray.Num(); i+=4)
201 {
202 if(PointArray.IsValidIndex(i+3))
203 {
204 // As Unreal is right handed, some visualizers will see the PointCloud Y axis inverted. If we want to get a left handed mesh output, it is necessary to negate the Y.
205 DataToWrite += FString::SanitizeFloat(PointArray[i]) + " " + FString::SanitizeFloat(PointArray[i+1]) + " " + FString::SanitizeFloat(PointArray[i+2]) + " " + FString::SanitizeFloat(PointArray[i+3]) + LineTerminator;
206 }
207 }
208
209 const bool bWriteSuccess = UJsonFileManagerLibrary::WriteStringFromFile(FilePath, DataToWrite);
210 if(!bWriteSuccess)
211 {
212 return false;
213 }
214
215 return true;
216}
217
218TSharedPtr<FJsonObject> UJsonFileManagerLibrary::GetSensorJsonData(const FString& JsonFilePath, TArray<TSharedPtr<FJsonValue>>& ArrayValue)
219{
220 TSharedPtr<FJsonObject> JsonObject = MakeShared<FJsonObject>();
221 const bool bReadSuccess = ReadJson(JsonFilePath, JsonObject);
222
223 if(!bReadSuccess)
224 {
225 UE_LOG(LogJsonFileManagerLibrary, Log, TEXT("UJsonFileManagerLibrary, file not exist will create a new one: %s"), *JsonFilePath);
226 }
227
228 if(JsonObject->HasField(TEXT("DataArray")))
229 {
230 ArrayValue = JsonObject->GetArrayField(TEXT("DataArray"));
231 }
232
233 return JsonObject;
234}
235
236bool UJsonFileManagerLibrary::SaveSensorJsonData(const FString& JsonFilePath,
237 const TSharedPtr<FJsonObject> SensorDataToSave, TSharedPtr<FJsonObject> JsonDataObject,
238 TArray<TSharedPtr<FJsonValue>>& ArrayValue)
239{
240 // Set array field an write Json
241 const TSharedRef<FJsonValue> IMUJsonValue = MakeShareable(new FJsonValueObject(SensorDataToSave));
242 ArrayValue.Add(IMUJsonValue);
243 JsonDataObject->SetArrayField(TEXT("DataArray"), ArrayValue);
244 const bool bWriteSuccess = WriteJson(JsonFilePath, JsonDataObject);
245
246 return bWriteSuccess;
247}
248
249bool UJsonFileManagerLibrary::SaveRadarDataToJson(const FString& JsonFilePath,
250 const FRadarData& Rays, const FString& FrameNumber)
251{
252 TArray<TSharedPtr<FJsonValue>> ArrayValue;
253 TSharedPtr<FJsonObject> JsonDataObject = GetSensorJsonData(JsonFilePath, ArrayValue);
254 bool bWriteSuccess = true;
255 for( auto& var : Rays.GetDetections() )
256 {
257 const TSharedPtr<FJsonObject> RadarDataObject = MakeShared<FJsonObject>();
258 RadarDataObject->SetStringField(TEXT("Frame"), FrameNumber);
259 RadarDataObject->SetStringField(TEXT("Velocity"), FString::SanitizeFloat(var.velocity));
260 RadarDataObject->SetStringField(TEXT("Azimuth"), FString::SanitizeFloat(var.azimuth));
261 RadarDataObject->SetStringField(TEXT("Altitude"), FString::SanitizeFloat(var.altitude));
262 RadarDataObject->SetStringField(TEXT("Depth"), FString::SanitizeFloat(var.depth));
263 bWriteSuccess &= SaveSensorJsonData(JsonFilePath, RadarDataObject, JsonDataObject, ArrayValue);
264 }
265
266 return bWriteSuccess;
267}
268
DEFINE_LOG_CATEGORY_STATIC(LogJsonFileManagerLibrary, Verbose, All)
static FVector JsonObjectToVector(const TSharedPtr< FJsonObject > &JsonObject)
static bool SaveSensorJsonData(const FString &JsonFilePath, const TSharedPtr< FJsonObject > SensorDataToSave, TSharedPtr< FJsonObject > JsonDataObject, TArray< TSharedPtr< FJsonValue > > &ArrayValue)
static bool WriteJson(const FString &JsonFilePath, const TSharedPtr< FJsonObject > JsonObject)
static bool SaveGnssDataToJson(const FString &JsonFilePath, double Altitude, double Latitude, double Longitude, const FString &FrameNumber)
static TSharedPtr< FJsonObject > GetSensorJsonData(const FString &JsonFilePath, TArray< TSharedPtr< FJsonValue > > &ArrayValue)
static bool ReadStringFromFile(const FString &FilePath, FString &DataRead)
static bool SaveLidarDataToPly(const FString &FilePath, const TArray< float > &PointArray, int ArrayElementSize)
static bool SaveRadarDataToJson(const FString &JsonFilePath, const FRadarData &Rays, const FString &FrameNumber)
static bool ReadJson(const FString &JsonFilePath, TSharedPtr< FJsonObject > &JsonObject)
static bool WriteStringFromFile(const FString &FilePath, const FString &DataToWrite)
static TSharedPtr< FJsonObject > VectorToJsonObject(const FVector &Vector)
static void RoundVectorToTwoDecimals(FVector &InOutVector)
static bool SaveIMUDataToJson(const FString &JsonFilePath, const FVector &Accelerometer, const FVector &Gyroscope, float Compass, const FString &FrameNumber)
const std::vector< RadarDetection > & GetDetections() const
Definition RadarData.h:73