Agrarsense
OverlapSensor.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
6#include "OverlapSensor.h"
8
12
13#if WITH_EDITOR
14#include "DrawDebugHelpers.h"
15#endif
16
17static constexpr float SIZE_DIVISOR = 70.0f;
18
19AOverlapSensor::AOverlapSensor(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
20{
21 PrimaryActorTick.bCanEverTick = false;
22
23 BoundsComponent = CreateDefaultSubobject<UBoundsVisualizerComponent>(TEXT("BoundsComponent"));
24 BoundsComponent->SetupAttachment(RootComponent);
25 BoundsComponent->SetGenerateOverlapEvents(true);
26 BoundsComponent->SetVisibility(false);
27 BoundsComponent->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
28}
29
31{
32 Parameters = InParameters;
33
34 Vehicle = Cast<AVehicle>(Parameters.OwningActor);
35
36 if (Vehicle)
37 {
38 VehicleName = IActorInformation::Execute_GetActorName(Vehicle);
39 VehicleID = IActorInformation::Execute_GetActorID(Vehicle);
40 }
41
42 UPrimitiveComponent* TriggerComponent = Cast<UPrimitiveComponent>(BoundsComponent);
43
44 // if you change DefaultEngine.ini collision channels then this index must be changed as well!
45 const int32 OverlapSensorIndex = 2;
46 const ECollisionChannel OverlapSensorChannel = UCollisionProfile::Get()->ConvertToCollisionChannel(false, OverlapSensorIndex);
47 BoundsComponent->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
48 BoundsComponent->SetGenerateOverlapEvents(true);
49 BoundsComponent->SetCollisionObjectType(OverlapSensorChannel);
50 BoundsComponent->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
51 BoundsComponent->SetCollisionResponseToChannel(OverlapSensorChannel, ECollisionResponse::ECR_Overlap);
52 BoundsComponent->SetRelativeLocation(Parameters.RelativePosition);
53
54 if (RootComponent)
55 {
56 BoundsComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepWorldTransform);
57 }
58
59 TriggerComponent = BoundsComponent;
60
61 if (TriggerComponent)
62 {
63 SetOverlapBounds(InParameters.Size);
64 //SetRootComponent(TriggerComponent);
66
67 ROSMessages::std_msgs::String StringMsg;
68 ROSMessage = MakeShared<ROSMessages::std_msgs::String>(StringMsg);
69
71 {
73 }
74 }
75
77 {
78 // Adjust the scale of the Sphere/Box component bounds to match the scale of the VisualizerComponent mesh
79 FVector ScaledVector = FVector(Parameters.Size.X / SIZE_DIVISOR, Parameters.Size.Y / SIZE_DIVISOR, Parameters.Size.Z / SIZE_DIVISOR);
80 BoundsComponent->SetRelativeScale3D(ScaledVector);
81 BoundsComponent->SetRelativeLocation(Parameters.RelativePosition);
82
83 if (RootComponent)
84 {
85 BoundsComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepWorldTransform);
86 }
87 }
88
90 {
91 AttachToActor(Parameters.OwningActor, FAttachmentTransformRules::KeepWorldTransform);
92 }
93
95}
96
98{
99 Super::BeginPlay();
100
101 BoundsComponent->OnComponentBeginOverlap.AddDynamic(this, &AOverlapSensor::OnOverlapBegin);
102 BoundsComponent->OnComponentEndOverlap.AddDynamic(this, &AOverlapSensor::OnOverlapEnd);
103}
104
105void AOverlapSensor::EndPlay(const EEndPlayReason::Type EndPlayReason)
106{
107 Super::EndPlay(EndPlayReason);
108
109 BoundsComponent->OnComponentBeginOverlap.RemoveDynamic(this, &AOverlapSensor::OnOverlapBegin);
110 BoundsComponent->OnComponentEndOverlap.RemoveDynamic(this, &AOverlapSensor::OnOverlapEnd);
111}
112
113void AOverlapSensor::SetOverlapBounds(const FVector& NewSize)
114{
115 Parameters.Size = NewSize;
116
117 if (BoundsComponent)
118 {
119 // Adjust the scale of the Sphere/Box component bounds to match the scale of the VisualizerComponent mesh
120 FVector ScaledVector = FVector(Parameters.Size.X / SIZE_DIVISOR, Parameters.Size.Y / SIZE_DIVISOR, Parameters.Size.Z / SIZE_DIVISOR);
121 BoundsComponent->SetRelativeScale3D(ScaledVector);
122 }
123
124 FString ActorID = IActorInformation::Execute_GetActorID(this);
125
126 FString Msg = FString::Printf(TEXT("OverlapSensor with ID: %s changed overlap bounds to: %s"), *ActorID, *NewSize.ToString());
128}
129
131{
132 IsVisible = Visualize;
133
134 if (BoundsComponent)
135 {
136 BoundsComponent->SetVisibility(IsVisible);
137 }
138}
139
141{
143
144 if (BoundsComponent)
145 {
146 BoundsComponent->SetRelativeLocation(Parameters.RelativePosition);
147 }
148
149 FString Msg = FString::Printf(TEXT("OverlapSensor.cpp: Changed overlap relative position to: %s"), *Vector.ToString());
151}
152
153void AOverlapSensor::SetOverlapResponseToAllChannels(const ECollisionResponse Response)
154{
155 if (Response != ECollisionResponse::ECR_Overlap && Response != ECollisionResponse::ECR_Ignore)
156 {
157 // If Response is neither ECR_Overlap nor ECR_Ignore, return
158 return;
159 }
160
161 if (BoundsComponent)
162 {
163 BoundsComponent->SetCollisionResponseToAllChannels(Response);
164 }
165}
166
167void AOverlapSensor::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp,
168 int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
169{
170 // Don't allow Overlapping with other Overlapping sensors..
171 AOverlapSensor* OtherOverlapSensor = Cast<AOverlapSensor>(OtherActor);
172 if (OtherOverlapSensor)
173 {
174 return;
175 }
176
177 BuildAndSendMessage("Overlap Begin with", OtherActor);
178}
179
180void AOverlapSensor::OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
181 UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
182{
183 // Don't allow Overlapping with other Overlapping sensors..
184 AOverlapSensor* OtherOverlapSensor = Cast< AOverlapSensor>(OtherActor);
185 if (OtherOverlapSensor)
186 {
187 return;
188 }
189
190 BuildAndSendMessage("Overlap End with", OtherActor);
191}
192
193void AOverlapSensor::BuildAndSendMessage(const FString& Prefix, AActor* Actor)
194{
195 if (!Actor)
196 {
197 return;
198 }
199
200 FString ID = TryGetID(Actor);
201 FString Message;
202
203 // Calculate distance from sensor parent (vehicle) to incoming Actor
204 AActor* From = this;
205 if (AActor* VehicleActorPtr = GetParentActor())
206 {
207 From = VehicleActorPtr;
208 }
209 float DistanceInMeters = FVector::Dist(From->GetActorLocation(), Actor->GetActorLocation()) / 100.0f;
210
211 // Add distance to the end of the message
212 if (ID.IsEmpty())
213 {
214 Message = FString::Printf(TEXT("%s: %s, Distance: %.2f m"), *Prefix, *Actor->GetName(), DistanceInMeters);
215 }
216 else
217 {
218 Message = FString::Printf(TEXT("%s: %s: ID: %s, Distance: %.2f m"), *Prefix, *Actor->GetName(), *ID, DistanceInMeters);
219 }
220
221 UTopic* Topic = GetROSTopic();
222 if (ROSMessage.IsValid() && Topic && IsROSConnected())
223 {
224 ROSMessage->_Data = Message;
225 Topic->Publish(ROSMessage);
226 }
227
228 WriteToLogFile(Message);
229
230 if (Vehicle)
231 {
232 FString Msg = FString::Printf(TEXT("Actor '%s' with ID: '%s' %s"), *VehicleName, *VehicleID, *Message);
234 }
235}
236
238{
239 if (!FileSavePath.IsEmpty())
240 {
241 return;
242 }
243
244 const FString DataLocation = UAgrarsensePaths::GetDataFolder();
245
246 // Default save path
247 FileSavePath = DataLocation + GetActorID_Implementation() + "/";
248
249 if (AVehicle* AttachedVehicle = IsAttachedToVehicle())
250 {
251 // If sensor is attached to vehicle, save data to vehicle folder
252 FileSavePath = DataLocation + AttachedVehicle->GetActorID_Implementation();
253 }
254}
255
257{
258 if (IsValid(LogFile))
259 {
260 // File has already been created, return
261 return;
262 }
263
265
266 FLogFileSettings Settings;
269 Settings.QueueLength = MAX_int32;
270 Settings.KeepFileOpen = false;
271 Settings.Timestamp = false;
272 Settings.OverrideFilePath = true;
273 Settings.FilePath = FileSavePath;
274
275 UE_LOG(LogTemp, Warning, TEXT("FileSavePath %s"), *FileSavePath);
276
277 LogFile = NewObject<ULogFile>(ULogFile::StaticClass());
278 if (IsValid(LogFile))
279 {
280 FString Prefix;
281 if (AVehicle* AttachedVehicle = IsAttachedToVehicle())
282 {
283 Prefix = AttachedVehicle->GetActorID_Implementation();
284 }
285 FString FileName = Prefix.IsEmpty() ? TEXT("overlap") : Prefix + TEXT("_overlap");
286
287 LogFile->Create(FileName, Settings);
288
289 }
290}
291
292FString AOverlapSensor::TryGetID(AActor* Actor)
293{
294 FString ID;
295
296 if (Actor && Actor->GetClass()->ImplementsInterface(UActorInformation::StaticClass()))
297 {
298 if (Actor->Implements<UActorInformation>())
299 {
300 ID = IActorInformation::Execute_GetActorID(Actor);
301 }
302 }
303
304 return ID;
305}
static constexpr float SIZE_DIVISOR
void OnOverlapEnd(UPrimitiveComponent *OverlappedComponent, AActor *OtherActor, UPrimitiveComponent *OtherComp, int32 OtherBodyIndex)
void CreateDataSavePath() override
void SetOverlapRelativePosition(const FVector &Vector)
TSharedPtr< ROSMessages::std_msgs::String > ROSMessage
AOverlapSensor(const FObjectInitializer &ObjectInitializer)
FString VehicleName
void CreateLogFile() override
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override
virtual void BeginPlay() override
UBoundsVisualizerComponent * BoundsComponent
Definition: OverlapSensor.h:98
void Init(FOverlapSensorParameters InParameters)
void SetVisualizeOverlapArea(bool Visualize)
void SetOverlapBounds(const FVector &NewSize)
FOverlapSensorParameters Parameters
void BuildAndSendMessage(const FString &Prefix, AActor *Actor)
void SetOverlapResponseToAllChannels(const ECollisionResponse Response)
AVehicle * Vehicle
FString TryGetID(AActor *Actor)
void OnOverlapBegin(UPrimitiveComponent *OverlappedComponent, AActor *OtherActor, UPrimitiveComponent *OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult &SweepResult)
void SetSimulateSensor(bool SimulateSensor)
Definition: Sensor.h:160
UTopic * GetROSTopic() const
Definition: Sensor.h:150
AVehicle * IsAttachedToVehicle() const
Definition: Sensor.cpp:152
ULogFile * LogFile
Definition: Sensor.h:367
virtual FString GetActorID_Implementation() const override
Definition: Sensor.h:216
FString FileSavePath
Definition: Sensor.h:372
void WriteToLogFile(const FString &Message)
Definition: Sensor.cpp:294
FORCEINLINE bool IsROSConnected() const
Definition: Sensor.h:201
virtual void CreateROSTopic()
Definition: Sensor.cpp:190
static void Log(const FString &Message, bool LogToTextFile=true, bool LogToROS=true)
static FString GetDataFolder()
void Create(const FString &FileNameWithoutExtension, FLogFileSettings Settings)
Definition: LogFile.cpp:40
bool KeepFileOpen
Definition: LogFile.h:42
bool Timestamp
Definition: LogFile.h:39
FString FilePath
Definition: LogFile.h:54
FFileWriteOptions FileWriteOptions
Definition: LogFile.h:45
int32 QueueLength
Definition: LogFile.h:48
bool OverrideFilePath
Definition: LogFile.h:51
FFileCreationOptions FileCreationOptions
Definition: LogFile.h:36