// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Curves/CurveFloat.h" #include "LidarPointCloudShared.h" #include "LidarPointCloudOctree.h" #include "HAL/ThreadSafeBool.h" #include "Engine/EngineTypes.h" #include "LidarPointCloudSettings.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "Engine/LatentActionManager.h" #include "ConvexVolume.h" #include "Interfaces/Interface_CollisionDataProvider.h" #include "GameFramework/Volume.h" #include "LidarPointCloud.generated.h" class ALidarPointCloudActor; class ULidarPointCloudComponent; class UBodySetup; class FLidarPointCloudCollisionRendering; class FLidarPointCloudNotification; namespace LidarPointCloudMeshing { struct FMeshBuffers; }; /** * Used for ULidarPointCloud::CreateFromXXXX calls */ struct FLidarPointCloudAsyncParameters { /** Should the creation use async operation */ bool bUseAsync; /** * Called every time at least 1% progress is generated. * The parameter is within 0.0 - 1.0 range. */ TFunction ProgressCallback; /** * Called once, when the operation completes. * The parameter specifies whether it has been executed successfully. */ TFunction CompletionCallback; FLidarPointCloudAsyncParameters(bool bUseAsync, TFunction ProgressCallback = nullptr, TFunction CompletionCallback = nullptr) : bUseAsync(bUseAsync) , ProgressCallback(MoveTemp(ProgressCallback)) , CompletionCallback(MoveTemp(CompletionCallback)) { } }; /** Used to notify the component it should refresh its state. */ DECLARE_EVENT(ULidarPointCloud, FOnPointCloudChanged); /** * Represents the Point Cloud asset */ UCLASS(BlueprintType, AutoExpandCategories=("Performance", "Rendering|Sprite"), AutoCollapseCategories=("Import Settings")) class LIDARPOINTCLOUDRUNTIME_API ULidarPointCloud : public UObject, public IInterface_CollisionDataProvider { GENERATED_BODY() private: /** Stores the path to the original source file. Empty if dynamically created. */ UPROPERTY(EditAnywhere, Category = "Import Settings", meta = (AllowPrivateAccess = "true")) FFilePath SourcePath; public: /** * Determines the maximum error (in cm) of the collision for this point cloud. * NOTE: Lower values will require more time to build. * Rebuild collision for the changes to take effect. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Collision") float MaxCollisionError; UPROPERTY(meta = (DeprecatedProperty, DeprecationMessage = "Use MaxCollisionError instead.")) float CollisionAccuracy_DEPRECATED; /** Higher values will generally result in more accurate calculations, at the expense of time */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Normals", meta = (ClampMin = "1", ClampMax = "100", DisplayName = "Quality")) int32 NormalsQuality; /** * Higher values are less susceptible to noise, but will most likely lose finer details, especially around hard edges. * Lower values retain more detail, at the expense of time. * NOTE: setting this too low will cause visual artifacts and geometry holes in noisier datasets. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Normals", meta = (ClampMin = "0.0", DisplayName = "Noise Tolerance")) float NormalsNoiseTolerance; /** Stores the original offset as a double. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Coordinates") FVector OriginalCoordinates; private: /** * Disables the LOD pipeline, allowing for much faster data operations (insert/remove/set) * at a potential expense of runtime performance. The whole asset will be treated as a single, * large asset with no granular density control, nor occlusion culling. * * Recommended for assets, which have their data updated per-frame (such as live streaming). */ UPROPERTY(EditAnywhere, Category = "Performance", meta = (AllowPrivateAccess = "true")) bool bOptimizedForDynamicData; public: /** Holds pointer to the Import Settings used for the import. */ TSharedPtr ImportSettings; FLidarPointCloudOctree Octree; FLidarPointCloudCollisionRendering* CollisionRendering; /** Contains an offset to be added to all points when rendering */ UPROPERTY() FVector LocationOffset; /** Required for file versioning */ static const FGuid PointCloudFileGUID; static const int32 PointCloudFileVersion; private: /** Used for caching the asset registry tag data. */ struct FLidarPointCloudAssetRegistryCache { FString PointCount; FString ApproxSize; } PointCloudAssetRegistryCache; /** Contains the list of imported classification IDs */ UPROPERTY() TArray ClassificationsImported; /** Used for async processing */ FThreadSafeBool bAsyncCancelled; FCriticalSection ProcessingLock; /** Notifications we hold on to, that indicate status and progress. */ class FLidarPointCloudNotificationManager { TArray> Notifications; TWeakObjectPtr Owner; public: FLidarPointCloudNotificationManager() : FLidarPointCloudNotificationManager(nullptr) {} FLidarPointCloudNotificationManager(TWeakObjectPtr Owner) : Owner(Owner) {} TSharedRef Create(const FString& Text, FThreadSafeBool* bCancelPtr = nullptr, const FString& Icon = "ClassIcon32.LidarPointCloud"); void CloseAll(); } Notifications; /** Description of collision */ UPROPERTY(transient, duplicatetransient) TObjectPtr BodySetup; UPROPERTY(transient, duplicatetransient) TObjectPtr NewBodySetup; /** Used for collision building */ FThreadSafeBool bCollisionBuildInProgress; FOnPointCloudChanged OnPointCloudRebuiltEvent; FOnPointCloudChanged OnPointCloudUpdateCollisionEvent; FOnPointCloudChanged OnPointCloudNormalsUpdatedEvent; FOnPointCloudChanged OnPreSaveCleanupEvent; public: ULidarPointCloud(); FOnPointCloudChanged& OnPointCloudRebuilt() { return OnPointCloudRebuiltEvent; } FOnPointCloudChanged& OnPointCloudCollisionUpdated() { return OnPointCloudUpdateCollisionEvent; } FOnPointCloudChanged& OnPointCloudNormalsUpdated() { return OnPointCloudNormalsUpdatedEvent; } FOnPointCloudChanged& OnPreSaveCleanup() { return OnPreSaveCleanupEvent; } // Begin UObject Interface. virtual void Serialize(FArchive& Ar) override; virtual void PostLoad() override; virtual void GetAssetRegistryTags(FAssetRegistryTagsContext Context) const override; UE_DEPRECATED(5.4, "Implement the version that takes FAssetRegistryTagsContext instead.") virtual void GetAssetRegistryTags(TArray& OutTags) const override; virtual void BeginDestroy() override; virtual void PreSave(FObjectPreSaveContext ObjectSaveContext) override; #if WITH_EDITOR virtual void ClearAllCachedCookedPlatformData() override; virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; #endif // End UObject Interface. UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud", meta=(ScriptName="GetNumLods;GetNumLODs")) int32 GetNumLODs() const { return Octree.GetNumLODs(); } UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") int64 GetNumPoints() const { return Octree.GetNumPoints(); } UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") int64 GetNumVisiblePoints() const { return Octree.GetNumVisiblePoints(); } UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") int32 GetNumNodes() const { return Octree.GetNumNodes(); } UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") FORCEINLINE float GetEstimatedPointSpacing() const { return Octree.GetEstimatedPointSpacing(); } /** Returns the amount of memory in MB used to store the point cloud. */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") int32 GetDataSize() const; UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") FString GetSourcePath() const { return SourcePath.FilePath; } UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") bool IsOptimizedForDynamicData() const { return bOptimizedForDynamicData; } UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") FBox GetBounds(bool bUseOriginalCoordinates = false) const { return Octree.GetBounds().ShiftBy(bUseOriginalCoordinates ? OriginalCoordinates : LocationOffset); } /** Recalculates and updates points bounds. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void RefreshBounds(); /** Returns true, if the Octree has collision built */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") bool HasCollisionData() const; /** Returns the number of polygons in the collider or 0 if no collider is built */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") int32 GetColliderPolys() const; UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void RefreshRendering(); TArray GetClassificationsImported() { return ClassificationsImported; } /** Returns true if there are any points within the given sphere. */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") bool HasPointsInSphere(FVector Center, float Radius, bool bVisibleOnly) const { return HasPointsInSphere(FSphere(Center, Radius), bVisibleOnly); } bool HasPointsInSphere(const FSphere& Sphere, bool bVisibleOnly) const { return Octree.HasPointsInSphere(FSphere(Sphere.Center - LocationOffset, Sphere.W), bVisibleOnly); } /** Returns true if there are any points within the given box. */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") bool HasPointsInBox(FVector Center, FVector Extent, bool bVisibleOnly) const { return HasPointsInBox(FBox(Center - Extent, Center + Extent), bVisibleOnly); } bool HasPointsInBox(const FBox& Box, bool bVisibleOnly) const { return Octree.HasPointsInBox(Box.ShiftBy(-LocationOffset), bVisibleOnly); } /** Returns true if there are any points hit by the given ray. */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") bool HasPointsByRay(FVector Origin, FVector Direction, float Radius, bool bVisibleOnly) const { return HasPointsByRay(FLidarPointCloudRay(Origin, Direction), Radius, bVisibleOnly); } bool HasPointsByRay(const FLidarPointCloudRay& Ray, float Radius, bool bVisibleOnly) const { return Octree.HasPointsByRay(Ray.ShiftBy(-LocationOffset), Radius, bVisibleOnly); } /** Populates the given array with points from the tree */ void GetPoints(TArray& Points, int64 StartIndex = 0, int64 Count = -1); void GetPoints(TArray64& Points, int64 StartIndex = 0, int64 Count = -1); /** Populates the array with the list of points within the given sphere. */ void GetPointsInSphere(TArray& SelectedPoints, const FSphere& Sphere, const bool& bVisibleOnly); void GetPointsInSphere(TArray64& SelectedPoints, const FSphere& Sphere, const bool& bVisibleOnly); /** Populates the array with the list of points within the given box. */ void GetPointsInBox(TArray& SelectedPoints, const FBox& Box, const bool& bVisibleOnly); void GetPointsInBox(TArray64& SelectedPoints, const FBox& Box, const bool& bVisibleOnly); /** * Populates the array with the list of points within the given convex volume. * The volume is assumed to include the LocationOffset of the asset */ void GetPointsInConvexVolume(TArray& SelectedPoints, const FConvexVolume& ConvexVolume, const bool& bVisibleOnly); void GetPointsInConvexVolume(TArray64& SelectedPoints, const FConvexVolume& ConvexVolume, const bool& bVisibleOnly); /** * Returns an array with copies of points from the tree * If ReturnWorldSpace is selected, the points' locations will be converted into absolute value, otherwise they will be relative to the center of the cloud. */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") TArray GetPointsAsCopies(bool bReturnWorldSpace, int32 StartIndex = 0, int32 Count = -1) const; void GetPointsAsCopies(TArray& Points, bool bReturnWorldSpace, int64 StartIndex = 0, int64 Count = -1) const; void GetPointsAsCopies(TArray64& Points, bool bReturnWorldSpace, int64 StartIndex = 0, int64 Count = -1) const; /** * Returns an array with copies of points within the given sphere * If ReturnWorldSpace is selected, the points' locations will be converted into absolute value, otherwise they will be relative to the center of the cloud. */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") TArray GetPointsInSphereAsCopies(FVector Center, float Radius, bool bVisibleOnly, bool bReturnWorldSpace); void GetPointsInSphereAsCopies(TArray& SelectedPoints, const FSphere& Sphere, const bool& bVisibleOnly, bool bReturnWorldSpace) const; void GetPointsInSphereAsCopies(TArray64& SelectedPoints, const FSphere& Sphere, const bool& bVisibleOnly, bool bReturnWorldSpace) const; /** * Returns an array with copies of points within the given box * If ReturnWorldSpace is selected, the points' locations will be converted into absolute value, otherwise they will be relative to the center of the cloud. */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") TArray GetPointsInBoxAsCopies(FVector Center, FVector Extent, bool bVisibleOnly, bool bReturnWorldSpace); void GetPointsInBoxAsCopies(TArray& SelectedPoints, const FBox& Box, const bool& bVisibleOnly, bool bReturnWorldSpace) const; void GetPointsInBoxAsCopies(TArray64& SelectedPoints, const FBox& Box, const bool& bVisibleOnly, bool bReturnWorldSpace) const; /** Performs a raycast test against the point cloud. Returns the pointer if hit or nullptr otherwise. */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud", meta = (Keywords = "raycast")) bool LineTraceSingle(FVector Origin, FVector Direction, float Radius, bool bVisibleOnly, FLidarPointCloudPoint& PointHit); FLidarPointCloudPoint* LineTraceSingle(const FLidarPointCloudRay& Ray, const float& Radius, const bool& bVisibleOnly) { return Octree.RaycastSingle(Ray.ShiftBy(-LocationOffset), Radius, bVisibleOnly); } /** * Performs a raycast test against the point cloud. * Populates OutHits array with the results. * If ReturnWorldSpace is selected, the points' locations will be converted into absolute value, otherwise they will be relative to the center of the cloud. * Returns true it anything has been hit. */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud", meta = (Keywords = "raycast")) bool LineTraceMulti(FVector Origin, FVector Direction, float Radius, bool bVisibleOnly, bool bReturnWorldSpace, TArray& OutHits) { return LineTraceMulti(FLidarPointCloudRay(Origin, Direction), Radius, bVisibleOnly, bReturnWorldSpace, OutHits); } bool LineTraceMulti(const FLidarPointCloudRay& Ray, const float& Radius, bool bVisibleOnly, bool bReturnWorldSpace, TArray& OutHits) { FTransform LocalToWorld(LocationOffset); return Octree.RaycastMulti(Ray.ShiftBy(-LocationOffset), Radius, bVisibleOnly, bReturnWorldSpace ? &LocalToWorld : nullptr, OutHits); } bool LineTraceMulti(const FLidarPointCloudRay& Ray, const float& Radius, bool bVisibleOnly, TArray& OutHits) { return Octree.RaycastMulti(Ray.ShiftBy(-LocationOffset), Radius, bVisibleOnly, OutHits); } /** Sets visibility of points within the given sphere. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void SetVisibilityOfPointsInSphere(bool bNewVisibility, FVector Center, float Radius) { SetVisibilityOfPointsInSphere(bNewVisibility, FSphere(Center, Radius)); } void SetVisibilityOfPointsInSphere(const bool& bNewVisibility, FSphere Sphere) { Sphere.Center -= LocationOffset; Octree.SetVisibilityOfPointsInSphere(bNewVisibility, Sphere); } /** Sets visibility of points within the given box. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void SetVisibilityOfPointsInBox(bool bNewVisibility, FVector Center, FVector Extent) { SetVisibilityOfPointsInBox(bNewVisibility, FBox(Center - Extent, Center + Extent)); } void SetVisibilityOfPointsInBox(const bool& bNewVisibility, const FBox& Box) { Octree.SetVisibilityOfPointsInBox(bNewVisibility, Box.ShiftBy(-LocationOffset)); } /** Sets visibility of the first point hit by the given ray. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void SetVisibilityOfFirstPointByRay(bool bNewVisibility, FVector Origin, FVector Direction, float Radius) { SetVisibilityOfFirstPointByRay(bNewVisibility, FLidarPointCloudRay(Origin, Direction), Radius); } void SetVisibilityOfFirstPointByRay(const bool& bNewVisibility, const FLidarPointCloudRay& Ray, const float& Radius) { Octree.SetVisibilityOfFirstPointByRay(bNewVisibility, Ray.ShiftBy(-LocationOffset), Radius); } /** Sets visibility of points hit by the given ray. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void SetVisibilityOfPointsByRay(bool bNewVisibility, FVector Origin, FVector Direction, float Radius) { SetVisibilityOfPointsByRay(bNewVisibility, FLidarPointCloudRay(Origin, Direction), Radius); } void SetVisibilityOfPointsByRay(const bool& bNewVisibility, const FLidarPointCloudRay& Ray, const float& Radius) { Octree.SetVisibilityOfPointsByRay(bNewVisibility, Ray.ShiftBy(-LocationOffset), Radius); } /** Marks all points hidden */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void HideAll() { Octree.HideAll(); } /** Marks all points visible */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void UnhideAll() { Octree.UnhideAll(); } /** Executes the provided action on each of the points. */ void ExecuteActionOnAllPoints(TFunction Action, const bool& bVisibleOnly) { Octree.ExecuteActionOnAllPoints(MoveTemp(Action), bVisibleOnly); } /** Executes the provided action on each of the points within the given sphere. */ void ExecuteActionOnPointsInSphere(TFunction Action, const FVector& Center, const float& Radius, const bool& bVisibleOnly) { ExecuteActionOnPointsInSphere(MoveTemp(Action), FSphere(Center, Radius), bVisibleOnly); } void ExecuteActionOnPointsInSphere(TFunction Action, FSphere Sphere, const bool& bVisibleOnly) { Sphere.Center -= LocationOffset; Octree.ExecuteActionOnPointsInSphere(MoveTemp(Action), Sphere, bVisibleOnly); } /** Executes the provided action on each of the points within the given box. */ void ExecuteActionOnPointsInBox(TFunction Action, const FVector& Center, const FVector& Extent, const bool& bVisibleOnly) { ExecuteActionOnPointsInBox(MoveTemp(Action), FBox(Center - Extent, Center + Extent), bVisibleOnly); } void ExecuteActionOnPointsInBox(TFunction Action, const FBox& Box, const bool& bVisibleOnly) { Octree.ExecuteActionOnPointsInBox(MoveTemp(Action), Box.ShiftBy(-LocationOffset), bVisibleOnly); } /** Executes the provided action on the first point hit by the given ray. */ void ExecuteActionOnFirstPointByRay(TFunction Action, const FLidarPointCloudRay& Ray, const float& Radius, bool bVisibleOnly) { Octree.ExecuteActionOnFirstPointByRay(MoveTemp(Action), Ray.ShiftBy(-LocationOffset), Radius, bVisibleOnly); } /** Executes the provided action on each of the points hit by the given ray. */ void ExecuteActionOnPointsByRay(TFunction Action, const FLidarPointCloudRay& Ray, const float& Radius, bool bVisibleOnly) { Octree.ExecuteActionOnPointsByRay(MoveTemp(Action), Ray.ShiftBy(-LocationOffset), Radius, bVisibleOnly); } /** Applies the given color to all points */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void ApplyColorToAllPoints(const FColor& NewColor, const bool& bVisibleOnly) { Octree.ApplyColorToAllPoints(NewColor, bVisibleOnly); } /** Applies the given color to all points within the sphere */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void ApplyColorToPointsInSphere(FColor NewColor, FVector Center, float Radius, bool bVisibleOnly) { ApplyColorToPointsInSphere(NewColor, FSphere(Center, Radius), bVisibleOnly); } void ApplyColorToPointsInSphere(const FColor& NewColor, FSphere Sphere, const bool& bVisibleOnly) { Sphere.Center -= LocationOffset; Octree.ApplyColorToPointsInSphere(NewColor, Sphere, bVisibleOnly); } /** Applies the given color to all points within the box */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void ApplyColorToPointsInBox(FColor NewColor, FVector Center, FVector Extent, bool bVisibleOnly) { ApplyColorToPointsInBox(NewColor, FBox(Center - Extent, Center + Extent), bVisibleOnly); } void ApplyColorToPointsInBox(const FColor& NewColor, const FBox& Box, const bool& bVisibleOnly) { Octree.ApplyColorToPointsInBox(NewColor, Box.ShiftBy(-LocationOffset), bVisibleOnly); } /** Applies the given color to the first point hit by the given ray */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void ApplyColorToFirstPointByRay(FColor NewColor, FVector Origin, FVector Direction, float Radius, bool bVisibleOnly) { ApplyColorToFirstPointByRay(NewColor, FLidarPointCloudRay(Origin, Direction), Radius, bVisibleOnly); } void ApplyColorToFirstPointByRay(const FColor& NewColor, const FLidarPointCloudRay& Ray, const float& Radius, bool bVisibleOnly) { Octree.ApplyColorToFirstPointByRay(NewColor, Ray.ShiftBy(-LocationOffset), Radius, bVisibleOnly); } /** Applies the given color to all points hit by the given ray */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void ApplyColorToPointsByRay(FColor NewColor, FVector Origin, FVector Direction, float Radius, bool bVisibleOnly) { ApplyColorToPointsByRay(NewColor, FLidarPointCloudRay(Origin, Direction), Radius, bVisibleOnly); } void ApplyColorToPointsByRay(const FColor& NewColor, const FLidarPointCloudRay& Ray, const float& Radius, bool bVisibleOnly) { Octree.ApplyColorToPointsByRay(NewColor, Ray.ShiftBy(-LocationOffset), Radius, bVisibleOnly); } /** * This should to be called if any manual modification to individual points' visibility has been made. * If not marked dirty, the rendering may work sub-optimally. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void MarkPointVisibilityDirty() { Octree.MarkPointVisibilityDirty(); } #if WITH_EDITOR /** Set of editor helper functions */ void SelectByConvexVolume(FConvexVolume ConvexVolume, bool bAdditive, bool bApplyLocationOffset, bool bVisibleOnly); void SelectBySphere(FSphere Sphere, bool bAdditive, bool bApplyLocationOffset, bool bVisibleOnly); void HideSelected(); void DeleteSelected(); void InvertSelection(); int64 NumSelectedPoints() const; bool HasSelectedPoints() const; void GetSelectedPointsAsCopies(TArray64& SelectedPoints, FTransform Transform) const; void CalculateNormalsForSelection(); void ClearSelection(); void BuildStaticMeshBuffersForSelection(float CellSize, LidarPointCloudMeshing::FMeshBuffers* OutMeshBuffers, const FTransform& Transform); #endif UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void SetSourcePath(const FString& NewSourcePath); UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void SetOptimizedForDynamicData(bool bNewOptimizedForDynamicData); /** * Re-initializes the asset with new bounds. * Warning: Will erase all currently held data! */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void Initialize(const FBox& NewBounds) { LocationOffset = OriginalCoordinates = NewBounds.GetCenter(); Octree.Initialize((FVector3f)NewBounds.GetExtent()); } UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void SetOptimalCollisionError(); /** Builds collision mesh for the cloud, using current collision settings */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void BuildCollision() { BuildCollision(nullptr); } void BuildCollision(TFunction CompletionCallback); UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (Latent, WorldContext = "WorldContextObject", LatentInfo = "LatentInfo")) void BuildCollisionWithCallback(UObject* WorldContextObject, FLatentActionInfo LatentInfo, bool& bSuccess); /** Removes collision mesh from the cloud. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void RemoveCollision(); /** Constructs and returns the MeshBuffers struct from the data */ void BuildStaticMeshBuffers(float CellSize, LidarPointCloudMeshing::FMeshBuffers* OutMeshBuffers, const FTransform& Transform); /** Returns true, if the cloud is fully and persistently loaded. */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud") bool IsFullyLoaded() const { return Octree.IsFullyLoaded(); } /** Persistently loads all nodes. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void LoadAllNodes() { Octree.LoadAllNodes(true); } /** Applies given offset to this point cloud. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void SetLocationOffset(FVector Offset); /** Centers this cloud */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void CenterPoints() { SetLocationOffset(FVector::ZeroVector); } /** Restores original coordinates */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void RestoreOriginalCoordinates() { SetLocationOffset(OriginalCoordinates); } /** Returns true, if the cloud has been centered. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") bool IsCentered() const { return LocationOffset.IsNearlyZero(0.1f); } /** Re-imports the cloud from it's original source file, overwriting any current point information. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (Latent, WorldContext = "WorldContextObject", LatentInfo = "LatentInfo", ExpandEnumAsExecs = "AsyncMode")) void Reimport(UObject* WorldContextObject, bool bUseAsync, FLatentActionInfo LatentInfo, ELidarPointCloudAsyncMode& AsyncMode, float& Progress); void Reimport(const FLidarPointCloudAsyncParameters& AsyncParameters); /** * Exports this Point Cloud to the given filename. * Consult supported export formats. * Returns true if successful */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") bool Export(const FString& Filename); /** * Inserts the given point into the Octree structure. * If bRefreshPointsBounds is set to false, make sure you call RefreshBounds() manually or cloud centering may not work correctly. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void InsertPoint(const FLidarPointCloudPoint& Point, ELidarPointCloudDuplicateHandling DuplicateHandling, bool bRefreshPointsBounds, const FVector& Translation); /** * Inserts group of points into the Octree structure, multi-threaded. * If bRefreshPointsBounds is set to false, make sure you call RefreshBounds() manually or cloud centering may not work correctly. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void InsertPoints(const TArray& Points, ELidarPointCloudDuplicateHandling DuplicateHandling, bool bRefreshPointsBounds, const FVector& Translation) { InsertPoints(Points.GetData(), Points.Num(), DuplicateHandling, bRefreshPointsBounds, Translation); } /** * Inserts group of points into the Octree structure, multi-threaded. * If bRefreshPointsBounds is set to false, make sure you call RefreshBounds() manually or cloud centering may not work correctly. * Can be optionally passed a cancellation pointer - if it ever becomes non-null with value of true, process will be canceled. * May also provide progress callback, called approximately every 1% of progress. * Returns false if canceled. */ bool InsertPoints(FLidarPointCloudPoint* InPoints, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, bool bRefreshPointsBounds, const FVector& Translation, FThreadSafeBool* bCanceled = nullptr, TFunction ProgressCallback = TFunction()); bool InsertPoints(const FLidarPointCloudPoint* InPoints, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, bool bRefreshPointsBounds, const FVector& Translation, FThreadSafeBool* bCanceled = nullptr, TFunction ProgressCallback = TFunction()); bool InsertPoints(FLidarPointCloudPoint** InPoints, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, bool bRefreshPointsBounds, const FVector& Translation, FThreadSafeBool* bCanceled = nullptr, TFunction ProgressCallback = TFunction()); bool InsertPoints_NoLock(FLidarPointCloudPoint* InPoints, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, bool bRefreshPointsBounds, const FVector& Translation, FThreadSafeBool* bCanceled = nullptr, TFunction ProgressCallback = TFunction()); bool InsertPoints_NoLock(const FLidarPointCloudPoint* InPoints, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, bool bRefreshPointsBounds, const FVector& Translation, FThreadSafeBool* bCanceled = nullptr, TFunction ProgressCallback = TFunction()); bool InsertPoints_NoLock(FLidarPointCloudPoint** InPoints, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, bool bRefreshPointsBounds, const FVector& Translation, FThreadSafeBool* bCanceled = nullptr, TFunction ProgressCallback = TFunction()); /** Attempts to remove the given point. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void RemovePoint(FLidarPointCloudPoint Point) { FScopeLock Lock(&Octree.DataLock); Octree.RemovePoint(Point); } void RemovePoint_NoLock(FLidarPointCloudPoint Point) { Octree.RemovePoint(Point); } void RemovePoint(const FLidarPointCloudPoint* Point) { FScopeLock Lock(&Octree.DataLock); RemovePoint_NoLock(Point); } void RemovePoint_NoLock(const FLidarPointCloudPoint* Point) { Octree.RemovePoint(Point); } /** Removes points in bulk */ void RemovePoints(TArray& Points) { FScopeLock Lock(&Octree.DataLock); RemovePoints_NoLock(Points); } void RemovePoints(TArray64& Points) { FScopeLock Lock(&Octree.DataLock); RemovePoints_NoLock(Points); } void RemovePoints_NoLock(TArray& Points) { Octree.RemovePoints(Points); } void RemovePoints_NoLock(TArray64& Points) { Octree.RemovePoints(Points); } /** Removes all points within the given sphere */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void RemovePointsInSphere(FVector Center, float Radius, bool bVisibleOnly) { RemovePointsInSphere(FSphere(Center, Radius), bVisibleOnly); } void RemovePointsInSphere(FSphere Sphere, const bool& bVisibleOnly) { Sphere.Center -= LocationOffset; Octree.RemovePointsInSphere(Sphere, bVisibleOnly); } /** Removes all points within the given box */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void RemovePointsInBox(FVector Center, FVector Extent, bool bVisibleOnly) { RemovePointsInBox(FBox(Center - Extent, Center + Extent), bVisibleOnly); } void RemovePointsInBox(const FBox& Box, const bool& bVisibleOnly) { Octree.RemovePointsInBox(Box.ShiftBy(-LocationOffset), bVisibleOnly); } /** Removes the first point hit by the given ray */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void RemoveFirstPointByRay(FVector Origin, FVector Direction, float Radius, bool bVisibleOnly) { RemoveFirstPointByRay(FLidarPointCloudRay(Origin, Direction), Radius, bVisibleOnly); } void RemoveFirstPointByRay(const FLidarPointCloudRay& Ray, const float& Radius, bool bVisibleOnly) { Octree.RemoveFirstPointByRay(Ray.ShiftBy(-LocationOffset), Radius, bVisibleOnly); } /** Removes all points hit by the given ray */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void RemovePointsByRay(FVector Origin, FVector Direction, float Radius, bool bVisibleOnly) { RemovePointsByRay(FLidarPointCloudRay(Origin, Direction), Radius, bVisibleOnly); } void RemovePointsByRay(const FLidarPointCloudRay& Ray, const float& Radius, const bool& bVisibleOnly) { Octree.RemovePointsByRay(Ray.ShiftBy(-LocationOffset), Radius, bVisibleOnly); } /** Removes all hidden points */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void RemoveHiddenPoints() { Octree.RemoveHiddenPoints(); } /** Reinitializes the cloud with the new set of data. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") bool SetData(const TArray& Points) { return SetData(Points.GetData(), Points.Num()); } bool SetData(TArray& Points) { return SetData(Points.GetData(), Points.Num()); } bool SetData(const TArray64& Points) { return SetData(Points.GetData(), Points.Num()); } bool SetData(TArray64& Points) { return SetData(Points.GetData(), Points.Num()); } bool SetData(const FLidarPointCloudPoint* Points, const int64& Count, TFunction ProgressCallback = TFunction()); bool SetData(FLidarPointCloudPoint** Points, const int64& Count, TFunction ProgressCallback = TFunction()); /** Merges this point cloud with the ones provided */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void Merge(TArray PointCloudsToMerge) { Merge(PointCloudsToMerge, nullptr); } void Merge(TArray PointCloudsToMerge, TFunction ProgressCallback); /** Merges this point cloud with the one provided */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") void MergeSingle(ULidarPointCloud* PointCloudToMerge) { Merge(TArray({ PointCloudToMerge })); } /** Calculates Normals for this point cloud */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (Latent, LatentInfo = "LatentInfo")) void CalculateNormals(FLatentActionInfo LatentInfo); /** * Calculates Normals for the provided points * If a nullptr is passed as Points, the calculation will be executed on the whole cloud. */ void CalculateNormals(TArray64* Points, TFunction CompletionCallback); //~ Begin Interface_CollisionDataProvider Interface virtual bool GetPhysicsTriMeshData(FTriMeshCollisionData* CollisionData, bool InUseAllTriData) override; virtual bool GetTriMeshSizeEstimates(struct FTriMeshCollisionDataEstimates& OutTriMeshEstimates, bool bInUseAllTriData) const override; virtual bool ContainsPhysicsTriMeshData(bool InUseAllTriData) const override { return HasCollisionData(); } virtual bool WantsNegXTriMesh() override { return false; } //~ End Interface_CollisionDataProvider Interface UBodySetup* GetBodySetup(); //~ Begin Deprecated UE_DEPRECATED(4.27, "Use GetPointsInConvexVolume instead.") void GetPointsInFrustum(TArray& SelectedPoints, const FConvexVolume& Frustum, const bool& bVisibleOnly); UE_DEPRECATED(4.27, "Use GetPointsInConvexVolume instead.") void GetPointsInFrustum(TArray64& SelectedPoints, const FConvexVolume& Frustum, const bool& bVisibleOnly); //~ End Deprecated public: /** Aligns provided clouds based on the relative offset between their Original Coordinates. Retains overall centering of the group. */ static void AlignClouds(TArray PointCloudsToAlign); /** * Returns new Point Cloud object imported using the settings provided. * Use nullptr as ImportSettings parameter to use default set of settings instead. */ static ULidarPointCloud* CreateFromFile(const FString& Filename, TSharedPtr ImportSettings = nullptr, UObject* InParent = (UObject*)GetTransientPackage(), FName InName = NAME_None, EObjectFlags Flags = RF_NoFlags) { return CreateFromFile(Filename, FLidarPointCloudAsyncParameters(GetDefault()->bUseAsyncImport), ImportSettings, InParent, InName, Flags); } static ULidarPointCloud* CreateFromFile(const FString& Filename, const FLidarPointCloudAsyncParameters& AsyncParameters, TSharedPtr ImportSettings = nullptr, UObject* InParent = (UObject*)GetTransientPackage(), FName InName = NAME_None, EObjectFlags Flags = RF_NoFlags); /* * Returns new Point Cloud object created from the data provided. * Warning: If using Async, make sure the data does not get invalidated during processing! */ template static ULidarPointCloud* CreateFromData(T Points, const int64& Count, const FLidarPointCloudAsyncParameters& AsyncParameters); static ULidarPointCloud* CreateFromData(const TArray& Points, const bool& bUseAsync); static ULidarPointCloud* CreateFromData(const TArray64& Points, const bool& bUseAsync); static ULidarPointCloud* CreateFromData(const TArray& Points, const FLidarPointCloudAsyncParameters& AsyncParameters); static ULidarPointCloud* CreateFromData(const TArray64& Points, const FLidarPointCloudAsyncParameters& AsyncParameters); static ULidarPointCloud* CreateFromData(TArray& Points, const bool& bUseAsync); static ULidarPointCloud* CreateFromData(TArray64& Points, const bool& bUseAsync); static ULidarPointCloud* CreateFromData(TArray& Points, const FLidarPointCloudAsyncParameters& AsyncParameters); static ULidarPointCloud* CreateFromData(TArray64& Points, const FLidarPointCloudAsyncParameters& AsyncParameters); /** Returns bounds fitting the given list of points */ static FBox CalculateBoundsFromPoints(const FLidarPointCloudPoint* Points, const int64& Count); static FBox CalculateBoundsFromPoints(FLidarPointCloudPoint** Points, const int64& Count); private: /** Once async physics cook is done, create needed state */ void FinishPhysicsAsyncCook(TSharedRef Notification) { FinishPhysicsAsyncCook(true, Notification); } void FinishPhysicsAsyncCook(bool bSuccess, TSharedRef Notification); void InitializeCollisionRendering(); void ReleaseCollisionRendering(bool bDestroyAfterRelease); template void GetPoints_Internal(TArray& Points, int64 StartIndex = 0, int64 Count = -1); template void GetPointsInSphere_Internal(TArray& SelectedPoints, FSphere Sphere, const bool& bVisibleOnly); template void GetPointsInBox_Internal(TArray& SelectedPoints, const FBox& Box, const bool& bVisibleOnly); template void GetPointsInConvexVolume_Internal(TArray& SelectedPoints, const FConvexVolume& ConvexVolume, const bool& bVisibleOnly); template void GetPointsAsCopies_Internal(TArray& Points, bool bReturnWorldSpace, int64 StartIndex = 0, int64 Count = -1) const; template void GetPointsInSphereAsCopies_Internal(TArray& SelectedPoints, FSphere Sphere, const bool& bVisibleOnly, bool bReturnWorldSpace) const; template void GetPointsInBoxAsCopies_Internal(TArray& SelectedPoints, const FBox& Box, const bool& bVisibleOnly, bool bReturnWorldSpace) const; template bool InsertPoints_Internal(T InPoints, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, bool bRefreshPointsBounds, const FVector& Translation, FThreadSafeBool* bCanceled = nullptr, TFunction ProgressCallback = TFunction()); template bool InsertPoints_NoLock_Internal(T InPoints, const int64& Count, ELidarPointCloudDuplicateHandling DuplicateHandling, bool bRefreshPointsBounds, const FVector& Translation, FThreadSafeBool* bCanceled = nullptr, TFunction ProgressCallback = TFunction()); template bool SetData_Internal(T Points, const int64& Count, TFunction ProgressCallback = TFunction()); }; USTRUCT(BlueprintType) struct FLidarPointCloudTraceHit { GENERATED_BODY() public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Collision") TObjectPtr Actor = nullptr; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Collision") TObjectPtr Component = nullptr; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Collision") TArray Points; FLidarPointCloudTraceHit() {} FLidarPointCloudTraceHit(ALidarPointCloudActor* Actor, ULidarPointCloudComponent* Component) : Actor(Actor) , Component(Component) { } }; /** * Blueprint library for the Point Cloud assets */ UCLASS(BlueprintType) class LIDARPOINTCLOUDRUNTIME_API ULidarPointCloudBlueprintLibrary : public UBlueprintFunctionLibrary { GENERATED_BODY() public: /** Returns new, empty Point Cloud object. */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud", meta = (DisplayName = "Create Empty Lidar Point Cloud")) static ULidarPointCloud* CreatePointCloudEmpty() { return NewObject(); } /** * Returns new Point Cloud object imported using default settings. * If using Async, the process runs in the background without blocking the game thread. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (Latent, WorldContext = "WorldContextObject", LatentInfo = "LatentInfo", ExpandEnumAsExecs = "AsyncMode", DisplayName = "Create Lidar Point Cloud From File")) static void CreatePointCloudFromFile(UObject* WorldContextObject, const FString& Filename, bool bUseAsync, FLatentActionInfo LatentInfo, ELidarPointCloudAsyncMode& AsyncMode, float& Progress, ULidarPointCloud*& PointCloud); static void CreatePointCloudFromFile(UObject* WorldContextObject, const FString& Filename, bool bUseAsync, FLatentActionInfo LatentInfo, TSharedPtr ImportSettings, ELidarPointCloudAsyncMode& AsyncMode, float& Progress, ULidarPointCloud*& PointCloud); /* * Returns new Point Cloud object created from the data provided. * Warning: If using Async, make sure the data does not get invalidated during processing! */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (Latent, WorldContext = "WorldContextObject", LatentInfo = "LatentInfo", ExpandEnumAsExecs = "AsyncMode", DisplayName = "Create Lidar Point Cloud From Data")) static void CreatePointCloudFromData(UObject* WorldContextObject, const TArray& Points, bool bUseAsync, FLatentActionInfo LatentInfo, ELidarPointCloudAsyncMode& AsyncMode, float& Progress, ULidarPointCloud*& PointCloud); /** * Exports the Point Cloud to the given filename. * Consult supported export formats. * Returns true if successful */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") static bool ExportPointCloudToFile(ULidarPointCloud* PointCloud, const FString& Filename) { return PointCloud && PointCloud->Export(Filename); } /** Aligns provided clouds based on the relative offset between their Original Coordinates. Retains overall centering of the group. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") static void AlignClouds(TArray PointCloudsToAlign) { ULidarPointCloud::AlignClouds(PointCloudsToAlign); } /** Returns true if there are any points within the given sphere. */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static bool ArePointsInSphere(UObject* WorldContextObject, FVector Center, float Radius, bool bVisibleOnly); /** Returns true if there are any points within the given box. */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static bool ArePointsInBox(UObject* WorldContextObject, FVector Center, FVector Extent, bool bVisibleOnly); /** Returns true if there are any points hit by the given ray. */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static bool ArePointsByRay(UObject* WorldContextObject, FVector Origin, FVector Direction, float Radius, bool bVisibleOnly); /** Returns an array with copies of points within the given sphere */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static void GetPointsInSphereAsCopies(UObject* WorldContextObject, TArray& SelectedPoints, FVector Center, float Radius, bool bVisibleOnly); /** Returns an array with copies of points within the given box */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static void GetPointsInBoxAsCopies(UObject* WorldContextObject, TArray& SelectedPoints, FVector Center, FVector Extent, const bool& bVisibleOnly); /** Does a collision trace along the given line and returns the first blocking hit encountered. */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject", DisplayName = "LineTraceForLidarPointCloud", Keywords = "raycast")) static bool LineTraceSingle(UObject* WorldContextObject, FVector Origin, FVector Direction, float Radius, bool bVisibleOnly, FLidarPointCloudTraceHit& Hit); /** Does a collision trace along the given line and returns all hits encountered up to and including the first blocking hit. */ UFUNCTION(BlueprintPure, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject", DisplayName = "LineTraceMultiForLidarPointCloud", Keywords = "raycast")) static bool LineTraceMulti(UObject* WorldContextObject, FVector Origin, FVector Direction, float Radius, bool bVisibleOnly, TArray& Hits); /** Sets visibility of points within the given sphere. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static void SetVisibilityOfPointsInSphere(UObject* WorldContextObject, bool bNewVisibility, FVector Center, float Radius); /** Sets visibility of points within the given box. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static void SetVisibilityOfPointsInBox(UObject* WorldContextObject, bool bNewVisibility, FVector Center, FVector Extent); /** Sets visibility of the first point hit by the given ray. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static void SetVisibilityOfFirstPointByRay(UObject* WorldContextObject, bool bNewVisibility, FVector Origin, FVector Direction, float Radius); /** Sets visibility of points hit by the given ray. */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static void SetVisibilityOfPointsByRay(UObject* WorldContextObject, bool bNewVisibility, FVector Origin, FVector Direction, float Radius); /** Applies the given color to all points within the sphere */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static void ApplyColorToPointsInSphere(UObject* WorldContextObject, FColor NewColor, FVector Center, float Radius, bool bVisibleOnly); /** Applies the given color to all points within the box */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static void ApplyColorToPointsInBox(UObject* WorldContextObject, FColor NewColor, FVector Center, FVector Extent, bool bVisibleOnly); /** Applies the given color to the first point hit by the given ray */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static void ApplyColorToFirstPointByRay(UObject* WorldContextObject, FColor NewColor, FVector Origin, FVector Direction, float Radius, bool bVisibleOnly); /** Applies the given color to all points hit by the given ray */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static void ApplyColorToPointsByRay(UObject* WorldContextObject, FColor NewColor, FVector Origin, FVector Direction, float Radius, bool bVisibleOnly); /** Removes all points within the given sphere */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static void RemovePointsInSphere(UObject* WorldContextObject, FVector Center, float Radius, bool bVisibleOnly); /** Removes all points within the given box */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static void RemovePointsInBox(UObject* WorldContextObject, FVector Center, FVector Extent, bool bVisibleOnly); /** Removes the first point hit by the given ray */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static void RemoveFirstPointByRay(UObject* WorldContextObject, FVector Origin, FVector Direction, float Radius, bool bVisibleOnly); /** Removes all points hit by the given ray */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud", meta = (WorldContext = "WorldContextObject")) static void RemovePointsByRay(UObject* WorldContextObject, FVector Origin, FVector Direction, float Radius, bool bVisibleOnly); /** Sets the given normal using provided vector */ UFUNCTION(BlueprintCallable, Category = "Lidar Point Cloud") static void NormalFromVector(UPARAM(ref) FLidarPointCloudNormal& Normal, FVector Vector) { Normal.SetFromVector((FVector3f)Vector); } /** Converts a Lidar Point Cloud Normal to a Vector */ UFUNCTION(BlueprintPure, meta = (DisplayName = "Normal to Vector", CompactNodeTitle = "->", BlueprintAutocast), Category = "Lidar Point Cloud") static FVector Conv_LidarPointCloudNormalToVector(const FLidarPointCloudNormal& Normal) { return (FVector)Normal.ToVector(); } /** Converts a Vector to a Lidar Point Cloud Normal */ UFUNCTION(BlueprintPure, meta = (DisplayName = "Vector to Normal", CompactNodeTitle = "->", BlueprintAutocast), Category = "Lidar Point Cloud") static FLidarPointCloudNormal Conv_VectorToLidarPointCloudNormal(const FVector& Vector) { return FLidarPointCloudNormal((FVector3f)Vector); } }; UCLASS(hidecategories = (Collision, Brush, Attachment, Physics, Volume, BrushBuilder), MinimalAPI) class ALidarClippingVolume : public AVolume { GENERATED_BODY() public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Clipping Volume") bool bEnabled; /** Affects how this volume affects points */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Clipping Volume") ELidarClippingVolumeMode Mode; /** * Determines the processing order of the nodes, in case they overlap. * Higher values take priority over lower ones. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Clipping Volume") int32 Priority; ALidarClippingVolume(); };