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 VisualizerComponent = CreateDefaultSubobject<UBoundsVisualizerComponent>(TEXT("BoundsVisualizerComponent"));
24 VisualizerComponent->SetupAttachment(RootComponent);
25 VisualizerComponent->SetGenerateOverlapEvents(false);
26 VisualizerComponent->SetVisibility(false);
27
28 BoxComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComponent"));
29 BoxComponent->SetGenerateOverlapEvents(false);
30 BoxComponent->SetVisibility(false);
31
32 SphereComponent = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComponent"));
33 SphereComponent->SetGenerateOverlapEvents(false);
34 SphereComponent->SetVisibility(false);
35}
36
38{
39 Parameters = InParameters;
40
41 Vehicle = Cast<AVehicle>(Parameters.OwningActor);
42
43 if (Vehicle)
44 {
47 }
48
50
51 UPrimitiveComponent* TriggerComponent = (OverlapShape == ETriggerShape::Box)
52 ? Cast<UPrimitiveComponent>(BoxComponent) : Cast<UPrimitiveComponent>(SphereComponent);
53
54 // if you change DefaultEngine.ini collision channels then this index must be changed as well!
55 const int32 OverlapSensorIndex = 2;
56
58 {
59 BoxComponent->SetGenerateOverlapEvents(true);
60 SphereComponent->SetGenerateOverlapEvents(false);
61 TriggerComponent = BoxComponent;
62
63 const ECollisionChannel OverlapSensorChannel = UCollisionProfile::Get()->ConvertToCollisionChannel(false, OverlapSensorIndex);
64 BoxComponent->SetCollisionObjectType(OverlapSensorChannel);
65 BoxComponent->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
66 BoxComponent->SetCollisionResponseToChannel(OverlapSensorChannel, ECollisionResponse::ECR_Overlap);
67 BoxComponent->SetRelativeLocation(Parameters.RelativePosition);
68
69 SphereComponent->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
70
71 if (RootComponent)
72 {
73 BoxComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepWorldTransform);
74 }
75
77 {
78 VisualizerComponent->SetCubeMesh();
79 }
80 }
82 {
83 BoxComponent->SetGenerateOverlapEvents(false);
84 SphereComponent->SetGenerateOverlapEvents(true);
85
86 const ECollisionChannel OverlapSensorChannel = UCollisionProfile::Get()->ConvertToCollisionChannel(false, OverlapSensorIndex);
87 SphereComponent->SetCollisionObjectType(OverlapSensorChannel);
88 SphereComponent->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
89 SphereComponent->SetCollisionResponseToChannel(OverlapSensorChannel, ECollisionResponse::ECR_Overlap);
90 SphereComponent->SetRelativeLocation(Parameters.RelativePosition);
91
92 BoxComponent->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
93
94 if (RootComponent)
95 {
96 SphereComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepWorldTransform);
97 }
98
99 TriggerComponent = SphereComponent;
100 }
101
102 if (TriggerComponent)
103 {
104 SetOverlapBounds(InParameters.Size);
105 //SetRootComponent(TriggerComponent);
106 SetSimulateSensor(true);
107
108 ROSMessages::std_msgs::String StringMsg;
109 ROSMessage = MakeShared<ROSMessages::std_msgs::String>(StringMsg);
110
112 {
114 }
115 }
116
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 VisualizerComponent->SetRelativeScale3D(ScaledVector);
122 VisualizerComponent->SetRelativeLocation(Parameters.RelativePosition);
123
124 if (RootComponent)
125 {
126 VisualizerComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepWorldTransform);
127 }
128 }
129
131 {
132 AttachToActor(Parameters.OwningActor, FAttachmentTransformRules::KeepWorldTransform);
133 }
134}
135
137{
138 Super::BeginPlay();
139
141 {
142 BoxComponent->OnComponentBeginOverlap.AddDynamic(this, &AOverlapSensor::OnOverlapBegin);
143 BoxComponent->OnComponentEndOverlap.AddDynamic(this, &AOverlapSensor::OnOverlapEnd);
144 }
146 {
147 SphereComponent->OnComponentBeginOverlap.AddDynamic(this, &AOverlapSensor::OnOverlapBegin);
148 SphereComponent->OnComponentEndOverlap.AddDynamic(this, &AOverlapSensor::OnOverlapEnd);
149 }
150}
151
152void AOverlapSensor::EndPlay(const EEndPlayReason::Type EndPlayReason)
153{
154 Super::EndPlay(EndPlayReason);
155
157 {
158 BoxComponent->OnComponentBeginOverlap.RemoveDynamic(this, &AOverlapSensor::OnOverlapBegin);
159 BoxComponent->OnComponentEndOverlap.RemoveDynamic(this, &AOverlapSensor::OnOverlapEnd);
160 }
162 {
163 SphereComponent->OnComponentBeginOverlap.RemoveDynamic(this, &AOverlapSensor::OnOverlapBegin);
164 SphereComponent->OnComponentEndOverlap.RemoveDynamic(this, &AOverlapSensor::OnOverlapEnd);
165 }
166}
167
168void AOverlapSensor::SetOverlapBounds(const FVector& NewSize)
169{
170 Parameters.Size = NewSize;
171
173 {
174 BoxComponent->SetBoxExtent(NewSize);
175 }
177 {
178 SphereComponent->SetSphereRadius(FMath::Max3(NewSize.X, NewSize.Y, NewSize.Z));
179 }
180
182 {
183 // Adjust the scale of the Sphere/Box component bounds to match the scale of the VisualizerComponent mesh
184 FVector ScaledVector = FVector(Parameters.Size.X / SIZE_DIVISOR, Parameters.Size.Y / SIZE_DIVISOR, Parameters.Size.Z / SIZE_DIVISOR);
185 VisualizerComponent->SetRelativeScale3D(ScaledVector);
186 }
187
188 FString Msg = FString::Printf(TEXT("OverlapSensor with ID: %s changed overlap bounds to: %s"), *GetActorID_Implementation(), *NewSize.ToString());
190}
191
193{
194 IsVisible = Visualize;
195
197 {
198 VisualizerComponent->SetVisibility(Visualize);
199 }
200
201#if WITH_EDITOR
202 // Visualize BoxComponent/SphereComponent with DrawDebug for debugging purposes,
203 // BoxComponent/SphereComponent and VisualizerComponent bounds should be equal
204 if (Visualize)
205 {
207 {
208 BoxComponent->SetGenerateOverlapEvents(true);
209 DrawDebugBox(GetWorld(), GetActorLocation(), BoxComponent->GetScaledBoxExtent(), FColor::Red, false, 3.0f);
210 }
212 {
213 SphereComponent->SetGenerateOverlapEvents(true);
214 DrawDebugSphere(GetWorld(), GetActorLocation(), SphereComponent->GetScaledSphereRadius(), 32, FColor::Red, false, 3.0f);
215 }
216 }
217
218 UE_LOG(LogTemp, Warning, TEXT("OverlapSensor.cpp: Visualize overlap bounds: %s"), (Visualize ? TEXT("true") : TEXT("false")));
219#endif
220}
221
223{
225
226 if (SphereComponent)
227 {
228 SphereComponent->SetRelativeLocation(Parameters.RelativePosition);
229 }
230
231 if (BoxComponent)
232 {
233 BoxComponent->SetRelativeLocation(Parameters.RelativePosition);
234 }
235
237 {
238 VisualizerComponent->SetRelativeLocation(Parameters.RelativePosition);
239 }
240
241 FString Msg = FString::Printf(TEXT("OverlapSensor.cpp: Changed overlap relative position to: %s"), *Vector.ToString());
243}
244
245void AOverlapSensor::SetOverlapResponseToAllChannels(const ECollisionResponse Response)
246{
247 if (Response != ECollisionResponse::ECR_Overlap && Response != ECollisionResponse::ECR_Ignore)
248 {
249 // If Response is neither ECR_Overlap nor ECR_Ignore, return
250 return;
251 }
252
253 if (SphereComponent)
254 {
255 SphereComponent->SetCollisionResponseToAllChannels(Response);
256 }
257
258 if (BoxComponent)
259 {
260 BoxComponent->SetCollisionResponseToAllChannels(Response);
261 }
262}
263
264void AOverlapSensor::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp,
265 int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
266{
267 // Don't allow Overlapping with other Overlapping sensors..
268 AOverlapSensor* OtherOverlapSensor = Cast< AOverlapSensor>(OtherActor);
269 if (OtherOverlapSensor)
270 {
271 return;
272 }
273
274 BuildAndSendMessage("Overlap Begin with", OtherActor);
275}
276
277void AOverlapSensor::OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
278 UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
279{
280 // Don't allow Overlapping with other Overlapping sensors..
281 AOverlapSensor* OtherOverlapSensor = Cast< AOverlapSensor>(OtherActor);
282 if (OtherOverlapSensor)
283 {
284 return;
285 }
286
287 BuildAndSendMessage("Overlap End with", OtherActor);
288}
289
290void AOverlapSensor::BuildAndSendMessage(const FString& Prefix, AActor* Actor)
291{
292 if (!Actor)
293 {
294 return;
295 }
296
297 FString ID = TryGetID(Actor);
298 FString Message;
299
300 if (ID.IsEmpty())
301 {
302 Message = FString::Printf(TEXT("%s: %s"), *Prefix, *Actor->GetName());
303 }
304 else
305 {
306 Message = FString::Printf(TEXT("%s: %s: ID: %s"), *Prefix, *Actor->GetName(), *ID);
307 }
308
309 UTopic* Topic = GetROSTopic();
310 if (ROSMessage.IsValid() && Topic && IsROSConnected())
311 {
312 ROSMessage->_Data = Message;
313 Topic->Publish(ROSMessage);
314 }
315
316 WriteToLogFile(Message);
317
318 if (Vehicle)
319 {
320 FString Msg = FString::Printf(TEXT("Actor '%s' with ID: '%s' %s"), *VehicleName, *VehicleID, *Message);
322 }
323}
324
325FString AOverlapSensor::TryGetID(AActor* Actor)
326{
327 FString ID;
328
329 if (Actor && Actor->GetClass()->ImplementsInterface(UActorInformation::StaticClass()))
330 {
331 IActorInformation* ActorInfo = Cast<IActorInformation>(Actor);
332 if (ActorInfo)
333 {
334 ID = ActorInfo->GetActorID_Implementation();
335 }
336 }
337
338 return ID;
339}
static constexpr float SIZE_DIVISOR
void OnOverlapEnd(UPrimitiveComponent *OverlappedComponent, AActor *OtherActor, UPrimitiveComponent *OtherComp, int32 OtherBodyIndex)
USphereComponent * SphereComponent
void SetOverlapRelativePosition(const FVector &Vector)
TSharedPtr< ROSMessages::std_msgs::String > ROSMessage
AOverlapSensor(const FObjectInitializer &ObjectInitializer)
FString VehicleName
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override
virtual void BeginPlay() override
UBoundsVisualizerComponent * VisualizerComponent
UBoxComponent * BoxComponent
ETriggerShape OverlapShape
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:151
UTopic * GetROSTopic() const
Definition: Sensor.h:141
virtual FString GetActorID_Implementation() const override
Definition: Sensor.h:207
bool IsROSConnected() const
Definition: Sensor.h:192
void WriteToLogFile(const FString &Message)
Definition: Sensor.cpp:242
virtual void CreateROSTopic()
Definition: Sensor.cpp:146
virtual FString GetActorID_Implementation() const override
Definition: Vehicle.h:203
virtual FString GetActorName_Implementation() const override
Definition: Vehicle.h:208
static void Log(const FString &Message, bool LogToTextFile=true, bool LogToROS=true)