Files
UnrealEngine/Engine/Plugins/Experimental/MeshModelingToolsetExp/Source/MeshModelingToolsExp/Public/RevolveSplineTool.h
2025-05-18 13:04:45 +08:00

193 lines
6.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Properties/RevolveProperties.h"
#include "Spline/BaseMeshFromSplinesTool.h"
#include "RevolveSplineTool.generated.h"
#define UE_API MESHMODELINGTOOLSEXP_API
class UConstructionPlaneMechanic;
class URevolveSplineTool;
//~ TODO: Might want to have some shared enum for sampling splines in a util folder,
//~ but hesitant to prescribe it until other tools want it.
UENUM()
enum class ERevolveSplineSampleMode : uint8
{
// Place points only at the spline control points
ControlPointsOnly,
// Place points along the spline such that the resulting polyline has no more than
// some maximum deviation from the curve.
PolyLineMaxError,
// Place points along spline that are an equal spacing apart, and so that the spacing
// is as close as possible to some max spacing.
UniformSpacingAlongCurve,
};
UCLASS(MinimalAPI)
class URevolveSplineToolProperties : public URevolveProperties
{
GENERATED_BODY()
public:
/** Determines how points to revolve are actually picked from the spline. */
UPROPERTY(EditAnywhere, Category = Spline)
ERevolveSplineSampleMode SampleMode = ERevolveSplineSampleMode::ControlPointsOnly;
/** How far to allow the triangulation boundary can deviate from the spline curve before we add more vertices. */
UPROPERTY(EditAnywhere, Category = Spline, meta = (ClampMin = 0.001, EditConditionHides,
EditCondition = "SampleMode == ERevolveSplineSampleMode::PolyLineMaxError"))
double ErrorTolerance = 1.0;
/** The maximal distance that the spacing should be allowed to be. */
UPROPERTY(EditAnywhere, Category = Spline, meta = (ClampMin = 0.01, EditConditionHides,
EditCondition = "SampleMode == ERevolveSplineSampleMode::UniformSpacingAlongCurve"))
double MaxSampleDistance = 50.0;
/** Determines how end caps are created. This is not relevant if the end caps are not visible or if the path is not closed. */
UPROPERTY(EditAnywhere, Category = Revolve, AdvancedDisplay, meta = (DisplayAfter = "QuadSplitMode",
EditCondition = "HeightOffsetPerDegree != 0 || RevolveDegrees != 360"))
ERevolvePropertiesCapFillMode CapFillMode = ERevolvePropertiesCapFillMode::Delaunay;
/** Connect the ends of an open path to the axis to add caps to the top and bottom of the revolved result.
* This is not relevant for paths that are already closed. */
UPROPERTY(EditAnywhere, Category = Revolve)
bool bClosePathToAxis = true;
/** Sets the revolution axis origin. */
UPROPERTY(EditAnywhere, Category = RevolutionAxis, meta = (DisplayName = "Origin",
Delta = 5, LinearDeltaSensitivity = 1))
FVector AxisOrigin = FVector(0, 0, 0);
/** Sets the revolution axis pitch and yaw. */
UPROPERTY(EditAnywhere, Category = RevolutionAxis, meta = (DisplayName = "Orientation",
UIMin = -180, UIMax = 180, ClampMin = -180000, ClampMax = 180000))
FVector2D AxisOrientation;
/**
* If true, the revolution axis is re-fit to the input spline on each tool start. If false, the previous
* revolution axis is kept.
*/
UPROPERTY(EditAnywhere, Category = RevolutionAxis, AdvancedDisplay)
bool bResetAxisOnStart = true;
protected:
virtual ERevolvePropertiesCapFillMode GetCapFillMode() const override
{
return CapFillMode;
}
};
enum class ERevolveSplineToolAction
{
ResetAxis
};
UCLASS(MinimalAPI)
class URevolveSplineToolActionPropertySet : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
TWeakObjectPtr<URevolveSplineTool> ParentTool;
void Initialize(URevolveSplineTool* ParentToolIn) { ParentTool = ParentToolIn; }
UE_API void PostAction(ERevolveSplineToolAction Action);
/** Fit the axis to the current curve(by aligning it to the startand end points) */
UFUNCTION(CallInEditor, Category = Actions, meta = (DisplayPriority = 1))
void ResetAxis() { PostAction(ERevolveSplineToolAction::ResetAxis); }
};
//~ We might someday decide to merge this tool as a separate path in the DrawAndRevolveTool...
/**
* Revolves a selected spline to create a new mesh.
*/
UCLASS(MinimalAPI)
class URevolveSplineTool : public UBaseMeshFromSplinesTool
{
GENERATED_BODY()
public:
UE_API virtual void RequestAction(ERevolveSplineToolAction ActionType);
// UInteractiveTool
UE_API virtual void Setup() override;
UE_API virtual void Shutdown(EToolShutdownType ShutdownType) override;
UE_API virtual void Render(IToolsContextRenderAPI* RenderAPI) override;
UE_API virtual void OnPropertyModified(UObject* PropertySet, FProperty* Property) override;
UE_API virtual void OnTick(float DeltaTime) override;
// IDynamicMeshOperatorFactory
UE_API virtual TUniquePtr<UE::Geometry::FDynamicMeshOperator> MakeNewOperator() override;
UE_API virtual FString GeneratedAssetBaseName() const override;
UE_API virtual FText TransactionName() const override;
protected:
// Update the profile curve and fit plane from spline
UE_API virtual void OnSplineUpdate() override;
// Keep the result mesh in the same space as set by the operator result
virtual FTransform3d HandleOperatorTransform(const FDynamicMeshOpResult& OpResult) override
{
return OpResult.Transform;
}
private:
UPROPERTY()
TObjectPtr<URevolveSplineToolProperties> Settings = nullptr;
UPROPERTY()
TObjectPtr<URevolveSplineToolActionPropertySet> ToolActions = nullptr;
UPROPERTY()
TObjectPtr<UConstructionPlaneMechanic> PlaneMechanic = nullptr;
// The actual points to be resolved, sampled from the spline
TArray<FVector3d> ProfileCurve;
bool bProfileCurveIsClosed;
// Axis direction in vector form (since the user modifiable values are a pitch and yaw)
FVector3d RevolutionAxisDirection;
// This duplicates Settings->AxisOrigin, but kept for cleanliness since we do need RevolutionAxisDirection
FVector3d RevolutionAxisOrigin;
UE_API void UpdateRevolutionAxis();
UE_API void ResetAxis();
FVector3d SplineFitPlaneOrigin;
FVector3d SplineFitPlaneNormal;
};
UCLASS(MinimalAPI, Transient)
class URevolveSplineToolBuilder : public UBaseMeshFromSplinesToolBuilder
{
GENERATED_BODY()
public:
/** @return new Tool instance initialized with selected spline source(s) */
UE_API virtual UInteractiveTool* BuildTool(const FToolBuilderState& SceneState) const override;
virtual UE::Geometry::FIndex2i GetSupportedSplineCountRange() const override
{
return UE::Geometry::FIndex2i(1, 1);
}
};
#undef UE_API