Agrarsense
DataCapture.cpp
Go to the documentation of this file.
1// Copyright (c) 2024 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
6#include "DataCapture.h"
13
14#include "GeoReferencingSystem.h"
15#include "TimerManager.h"
16
17ADataCapture::ADataCapture(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
18{
19 RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
20 PrimaryActorTick.bCanEverTick = true;
21 PrimaryActorTick.bStartWithTickEnabled = false;
22 PrimaryActorTick.TickGroup = TG_PrePhysics;
23 SetActorTickEnabled(false);
24}
25
27{
28 // Separate Cameras and Lidars from the Sensors array into their respective arrays
29 // after JsonParser has populated the Sensors array.
30 for (ASensor* Sensor : NewCaptureData.Sensors)
31 {
32 if (ACamera* CameraPtr = Cast<ACamera>(Sensor))
33 {
34 NewCaptureData.Cameras.Add(CameraPtr);
35 }
36 else if (ALidar* LidarPtr = Cast<ALidar>(Sensor))
37 {
38 NewCaptureData.Lidars.Add(LidarPtr);
39 }
40 }
41
42 CaptureData = NewCaptureData;
43
45 {
46 AGeoReferencingSystem* GeoReferencingSystem = AGeoReferencingSystem::GetGeoReferencingSystem(GetWorld());
47
48 if (GeoReferencingSystem)
49 {
50 for (FTransform& CaptureTransform : CaptureData.CapturePositions)
51 {
52 FVector Location = CaptureTransform.GetLocation();
53
54 float StoredZ = Location.Z;
55
56 FGeographicCoordinates GeographicCoordinates;
57 GeographicCoordinates.Latitude = Location.X;
58 GeographicCoordinates.Longitude = Location.Y;
59 GeographicCoordinates.Altitude = Location.Z;
60
61 FVector InUnrealCoordinates = UCoordinateConversionUtilities::GeographicToUnrealCoordinates(GeoReferencingSystem, GeographicCoordinates);
62
64 {
65 CaptureTransform.SetLocation(InUnrealCoordinates);
66 }
67 else
68 {
69 // If user gives wanted Z in meters from the ground, compute the height
70 InUnrealCoordinates.Z = StoredZ;
71 CaptureTransform.SetLocation(InUnrealCoordinates);
72 ComputeAndSetZFromGround(CaptureTransform);
73 }
74 }
75 }
76 else
77 {
78 SimulatorLog::Log("Couldn't convert GPS coordinates into Unreal transform because couldn't find GeoReferencingSystem.");
79 }
80 }
81
83 {
84 // Loop through CapturePositions and add 4 additional positions for 360-degree capture
85 TArray<FTransform> NewCapturePositions;
86
87 for (const FTransform& OriginalTransform : CaptureData.CapturePositions)
88 {
89 FVector OriginalPosition = OriginalTransform.GetLocation();
90 FRotator OriginalRotation = OriginalTransform.GetRotation().Rotator();
91 int32 NumPhotos = 4;
92
93 NewCapturePositions.Add(OriginalTransform);
94
95 for (int32 i = 0; i < NumPhotos; i++)
96 {
97 FTransform CameraTransform = FTransform::Identity;
98
99 switch (i)
100 {
101 case 0: // Front
102 CameraTransform.SetLocation(OriginalPosition + FVector(0, 100, 0));
103 CameraTransform.SetRotation(FQuat(OriginalRotation));
104 break;
105 case 1: // Back
106 CameraTransform.SetLocation(OriginalPosition + FVector(0, -100, 0));
107 CameraTransform.SetRotation(FQuat(OriginalRotation + FRotator(0, 180, 0)));
108 break;
109 case 2: // Left
110 CameraTransform.SetLocation(OriginalPosition + FVector(-100, 0, 0));
111 CameraTransform.SetRotation(FQuat(OriginalRotation + FRotator(0, 90, 0)));
112 break;
113 case 3: // Right
114 CameraTransform.SetLocation(OriginalPosition + FVector(100, 0, 0));
115 CameraTransform.SetRotation(FQuat(OriginalRotation + FRotator(0, 270, 0)));
116 break;
117 }
118
119 // Add the new position to NewCapturePositions
120 NewCapturePositions.Add(CameraTransform);
121 }
122 }
123
124 CaptureData.CapturePositions = NewCapturePositions;
125 }
126
127 if (CaptureData.CapturePositions.Num() != 0 && CaptureData.Cameras.Num() != 0)
128 {
129 for (int32 i = 0; i < CaptureData.Cameras.Num(); i++)
130 {
131 ACamera* CameraPtr = CaptureData.Cameras[i];
132 if (CameraPtr)
133 {
134 FCameraBaseParameters params = CameraPtr->GetCameraParameters();
135 params.SaveImageToDisk = false;
136 params.SendDataToROS = false;
137 CameraPtr->ChangeCameraParameters(params);
138 }
139 }
140
142
143 // Enable This Actor tick with delay
144 FTimerHandle Handle;
145 GetWorld()->GetTimerManager().SetTimer(Handle, FTimerDelegate::CreateLambda([this]
146 {
148 SetActorTickEnabled(true);
149 }), 0.1f, false);
150 }
151 else
152 {
154 Destroy();
155 }
156}
157
159{
160 Super::BeginPlay();
161}
162
163void ADataCapture::Tick(float DeltaTime)
164{
165 Super::Tick(DeltaTime);
166 Capture();
167}
168
169void ADataCapture::EndPlay(const EEndPlayReason::Type EndPlayReason)
170{
171 Super::EndPlay(EndPlayReason);
172
173 CaptureData.Cameras.Empty();
175}
176
178{
180 {
181 // if this is the last position, we can stop capturing and destroy the sensors,
182 // as well as this Actor.
183
184 SetActorTickEnabled(false);
185
186 // Destroy this Actor with delay so Camera sensors have time to save the last images
187 FTimerHandle Handle;
188 GetWorld()->GetTimerManager().SetTimer(Handle, FTimerDelegate::CreateLambda([this]
189 {
191 Destroy();
192 }), 1.0f, false);
193
194 return;
195 }
196
197 switch (CaptureStep)
198 {
200 {
201 // Wait one frame before moving actor
203 FrameCounter = 0;
204 break;
205 }
207 {
209
210 // Move to next state
212 FrameCounter = 0;
213 break;
214 }
216 {
217 ++FrameCounter;
219 {
221
222 // Prepare for next wait before moving again
224 FrameCounter = 0;
225 }
226 break;
227 }
229 {
230 ++FrameCounter;
232 {
233 // Move to next position
236 FrameCounter = 0;
237 }
238 break;
239 }
240 }
241}
242
243void ADataCapture::UpdatePositions(const FTransform& Transform)
244{
245 for (int32 i = 0; i < CaptureData.Sensors.Num(); i++)
246 {
247 ASensor* SensorPtr = CaptureData.Sensors[i];
248 if (SensorPtr)
249 {
250 SensorPtr->SetActorTransform(Transform);
251 }
252 }
253
254 for (int32 i = 0; i < CaptureData.Lidars.Num(); i++)
255 {
256 ALidar* LidarPtr = CaptureData.Lidars[i];
257 if (LidarPtr)
258 {
259 // The Lidar sensor generates a full point cloud across multiple frames,
260 // so to ensure accurate data capture after moving the actor, we force a reset of the point cloud capture.
261 LidarPtr->ForceClearContainers();
262 }
263 }
264}
265
267{
268 for (int32 i = 0; i < CaptureData.Cameras.Num(); i++)
269 {
270 ACamera* CameraPtr = CaptureData.Cameras[i];
271 if (CameraPtr)
272 {
273 CameraPtr->SaveCurrentFrameToDisk();
274 }
275 }
276
277 for (int32 i = 0; i < CaptureData.Lidars.Num(); i++)
278 {
279 ALidar* LidarPtr = CaptureData.Lidars[i];
280 if (LidarPtr)
281 {
282 LidarPtr->SaveCurrentPointCloudToDisk();
283 }
284 }
285}
286
288{
289 for (int32 i = 0; i < CaptureData.Sensors.Num(); i++)
290 {
291 ASensor* SensorPtr = CaptureData.Sensors[i];
292 if (SensorPtr)
293 {
294 SensorPtr->Destroy();
295 }
296 }
297}
298
299void ADataCapture::ComputeAndSetZFromGround(FTransform& Transform)
300{
301 UWorld* World = GetWorld();
302 if (!World)
303 {
304 return;
305 }
306
307 FVector Position = Transform.GetLocation();
308 FVector Start = Position;
309 FVector End = Position - FVector(0, 0, 10000); // Trace downwards
310
311 FHitResult HitResult;
312 FCollisionQueryParams QueryParams;
313
314 bool Hit = World->LineTraceSingleByChannel(HitResult, Start, End, ECC_Visibility, QueryParams);
315
316 if (Hit)
317 {
318 float HeightAboveGround = Position.Z;
319 Position.Z = HitResult.ImpactPoint.Z + (HeightAboveGround * 100.0f);
320 Transform.SetLocation(Position);
321 }
322}
@ WaitingAfterPositionUpdate
@ WaitingForPositionUpdate
Definition: Camera.h:53
void ChangeCameraParameters(FCameraBaseParameters newParameters)
Definition: Camera.cpp:55
void SaveCurrentFrameToDisk()
Definition: Camera.h:189
FCameraBaseParameters GetCameraParameters()
Definition: Camera.h:91
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override
int32 FrameCounter
Definition: DataCapture.h:116
void SetupDataCapture(FCaptureData NewCaptureData)
Definition: DataCapture.cpp:26
virtual void Tick(float DeltaTime) override
ADataCapture(const FObjectInitializer &ObjectInitializer)
Definition: DataCapture.cpp:17
FCaptureData CaptureData
Definition: DataCapture.h:112
void UpdatePositions(const FTransform &Transform)
void ComputeAndSetZFromGround(FTransform &Transform)
virtual void BeginPlay() override
void CaptureDataNow()
ECaptureStep CaptureStep
Definition: DataCapture.h:114
void DestroySensors()
Definition: Lidar.h:35
void ForceClearContainers()
Definition: Lidar.h:110
void SaveCurrentPointCloudToDisk()
Definition: Lidar.h:118
Definition: Sensor.h:45
static void Log(const FString &Message, bool LogToTextFile=true, bool LogToROS=true)
static FVector GeographicToUnrealCoordinates(AGeoReferencingSystem *GeoReferencingSystem, const FGeographicCoordinates &GeographicCoordinates)
int32 FramesToKeepInSamePosition
Definition: DataCapture.h:54
bool UseGPSLocation
Definition: DataCapture.h:44
bool UseHeightAboveGround
Definition: DataCapture.h:57
TArray< FTransform > CapturePositions
Definition: DataCapture.h:32
bool CaptureRotatedViews
Definition: DataCapture.h:38
TArray< ACamera * > Cameras
Definition: DataCapture.h:26
TArray< ALidar * > Lidars
Definition: DataCapture.h:29
int32 CurrentCaptureIndex
Definition: DataCapture.h:47
TArray< ASensor * > Sensors
Definition: DataCapture.h:23