diff --git a/Alice b/Alice index 13abc135..84c8f9a1 160000 --- a/Alice +++ b/Alice @@ -1 +1 @@ -Subproject commit 13abc135303391dd72c084e44791148a97d3bfa1 +Subproject commit 84c8f9a1025b40e2c9fca884cadec05b1a321b28 diff --git a/CMakeLists.txt b/CMakeLists.txt index 143295dd..d9181c56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,10 @@ set(CMAKE_USE_MAKE_RULES_OVERRIDE set(CMAKE_USE_MAKE_RULES_OVERRIDE_CXX "${CMAKE_SOURCE_DIR}/cmake/cxx_flag_overrides.cmake") +if(WIN32) + add_compile_definitions(NOMINMAX WIN32_LEAN_AND_MEAN) +endif() + #----------------------------------------------------------------------------- # 检测操作系统 #----------------------------------------------------------------------------- diff --git a/Designer/Data/CommandsConfig.xml b/Designer/Data/CommandsConfig.xml index 37ce57f6..93806a6d 100644 --- a/Designer/Data/CommandsConfig.xml +++ b/Designer/Data/CommandsConfig.xml @@ -15,6 +15,13 @@ + + + - + + + + + + + + + + + + + + + + + + + + + - - - + + + + diff --git a/Designer/Data/FunctionAreaConfig.xml b/Designer/Data/FunctionAreaConfig.xml index d47fc087..ff978902 100644 --- a/Designer/Data/FunctionAreaConfig.xml +++ b/Designer/Data/FunctionAreaConfig.xml @@ -10,6 +10,53 @@ workbench="workbench.part" defaultTab="tab_part_home"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -461,6 +799,14 @@ + + + + + + + + @@ -1098,6 +1444,14 @@ + + + + + + + + @@ -1272,6 +1626,10 @@ + + + + diff --git a/Designer/Interaction/SolidDesignerInteraction/CMakeLists.txt b/Designer/Interaction/SolidDesignerInteraction/CMakeLists.txt index c4a85b89..fb804dab 100644 --- a/Designer/Interaction/SolidDesignerInteraction/CMakeLists.txt +++ b/Designer/Interaction/SolidDesignerInteraction/CMakeLists.txt @@ -21,8 +21,77 @@ link_directories(${ALICE_LIB_DIR}) # 头文件搜索路径 #----------------------------------------------------------------------------- include_directories(${CMAKE_SOURCE_DIR}) +include_directories(${PROJECT_SOURCE_DIR}/Alice) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Foundation/AliceBasicTool/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Foundation/AliceFoundation/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Math/AliceMaths/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Geom/Interface/AliceKernelInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Geom/Interface/AliceKernelInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/AliceCommonOperation/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceCommandInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceCommandInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceOperationSystemInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceOperationSystemInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceCoreApplicationInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceCoreApplicationInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceHighlightInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceHighlightInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceSelectionInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceSelectionInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AlicePickInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AlicePickInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceSnapInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceSnapInterface/Public) + +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceModelInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceModelInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceModelInterface/Public/Feature) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceSketchModelInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceSketchModelInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/AliceSketchRuntime) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/AliceSketchRuntime/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceConstraintSystemInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceConstraintSystemInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureDefinitionInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureDefinitionInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureReferenceInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureReferenceInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureEditInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureEditInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/AliceFeatureEdit/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/AliceFeatureEdit) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceObjectRepresentationModelInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceObjectRepresentationModelInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceViewPrimitiveInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceViewPrimitiveInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceViewModelInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceViewModelInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceTransactionSystemInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceTransactionSystemInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/AliceFeatureDefinition/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/AliceFeatureReference) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/AliceFeatureReference/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/AliceFeatureRuntime) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/AliceFeatureRuntime/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/AliceObjectRepresentationModel/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/AliceFeatureObjectModel/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureObjectModelInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureObjectModelInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureParameterInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureParameterInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureResultInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureResultInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Runtime/AliceSceneRuntime/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Runtime/Interface/AliceSceneRuntimeInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Runtime/Interface/AliceSceneRuntimeInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/UI/QFrameWork/AliceUiFrameWork/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/UI/QFrameWork/AliceUiFrameWork) +include_directories(${PROJECT_SOURCE_DIR}/Alice/UI/QFrameWork/AliceNavigationBar/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/View/AliceUiViewInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureHistoryInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Designer/UI/SolidDesignerCommand) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Runtime/Interface/AliceRenderSystemInterface/Public) #============================================================================= #指定工程为动态库程序 @@ -101,7 +170,31 @@ endif() target_link_libraries(SolidDesignerInteraction PRIVATE AliceBasicTool -) - - -message("*--*--*--*--*--*--*--*--*--*--*--**--*--*--End SolidDesignerInteraction*--*--*--*--*--*--*--*--*--*--*--*--*--*") \ No newline at end of file + AliceFoundation + AliceMaths + AliceOperationSystemInterface + AliceCoreApplicationInterface + AliceViewModelInterface + AliceObjectRepresentationModelInterface + AliceObjectRepresentationModel + AliceModelInterface + AliceConstraintSystemInterface + AliceSketchModelInterface + AliceSketchRuntime + AliceSelectionInterface + AlicePickInterface + AliceHighlightInterface + AliceFeatureDefinitionInterface + AliceFeatureReferenceInterface + AliceFeatureEditInterface + AliceFeatureEdit + AliceFeatureDefinition + AliceFeatureReference + AliceFeatureRuntime + AliceNavigationBar + AliceUiFrameWork + AliceCommonOperation +) + + +message("*--*--*--*--*--*--*--*--*--*--*--**--*--*--End SolidDesignerInteraction*--*--*--*--*--*--*--*--*--*--*--*--*--*") diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidActiveSketchPlaneContext.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidActiveSketchPlaneContext.cpp new file mode 100644 index 00000000..4b70ad06 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidActiveSketchPlaneContext.cpp @@ -0,0 +1,32 @@ +#include "SolidActiveSketchPlaneContext.h" + +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidExtrudeCreateOperation.h" + +using namespace sdr; +using namespace alice; + +bool SolidActiveSketchPlaneContext::IsAvailable() const noexcept +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (!pSession || !pSession->GetActiveDocument()) + { + return false; + } + + const SolidExtrudeCreateOperation* const pOperation = SolidExtrudeCreateOperation::FindActive(pSession); + if (!pOperation) + { + return false; + } + + return pOperation->GetSectionInput().SketchPlaneReferenceId.IsValid(); +} + +bool SolidActiveSketchPlaneContext::HasSelectedSketchPlane() const noexcept +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + const SolidExtrudeCreateOperation* const pOperation = SolidExtrudeCreateOperation::FindActive(pSession); + return pOperation != nullptr && pOperation->GetSectionInput().SketchPlaneReferenceId.IsValid(); +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidActiveSketchPlaneContext.h b/Designer/Interaction/SolidDesignerInteraction/SolidActiveSketchPlaneContext.h new file mode 100644 index 00000000..ba3445b4 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidActiveSketchPlaneContext.h @@ -0,0 +1,12 @@ +#pragma once +#include "SolidDesignerInteraction.h" + +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidActiveSketchPlaneContext final + { + public: + bool IsAvailable() const noexcept; + bool HasSelectedSketchPlane() const noexcept; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidAuthoringOperationBase.h b/Designer/Interaction/SolidDesignerInteraction/SolidAuthoringOperationBase.h new file mode 100644 index 00000000..44f4e7a5 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidAuthoringOperationBase.h @@ -0,0 +1,167 @@ +#pragma once + +#include "SolidDesignerInteraction.h" + +#include "AliceOperationBase.h" +#include "AliceIDocument.h" +#include "AliceIUiView.h" +#include "AliceIViewPort.h" +#include "AliceIViewPortCanvas.h" +#include "AliceObjectId.h" +#include "AliceIRepresentationRecord.h" +#include "AliceDocumentViewDisplayRefreshService.h" +#include "AliceUiDocumentRefreshCoordinator.h" +#include "SolidFeatureAuthoringUiContext.h" + +#include +#include + +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidAuthoringOperationBase : public alice::OperationBase + { + public: + + protected: + std::shared_ptr GetPrimaryOpenView(alice::IDocument* pDocument) const + { + alice::IMainWindow* const pMainWindow = ResolveSolidAuthoringMainWindow(); + return pMainWindow && pDocument ? pMainWindow->GetPrimaryOpenView(pDocument) : std::shared_ptr{}; + } + + std::vector> GetOpenViews(alice::IDocument* pDocument) const + { + alice::IMainWindow* const pMainWindow = ResolveSolidAuthoringMainWindow(); + return pMainWindow && pDocument ? pMainWindow->GetOpenViews(pDocument) : std::vector>{}; + } + + bool FlushPendingCommittedDisplay(alice::IDocument* pDocument) const + { + if (pDocument == nullptr) + { + return false; + } + + const auto views = GetOpenViews(pDocument); + if (views.empty()) + { + return false; + } + + std::shared_ptr pUiDocument; + for (const auto& pView : views) + { + if (pView) + { + pUiDocument = pView->GetOwnerDocument(); + if (pUiDocument) + { + break; + } + } + } + if (!pUiDocument) + { + return false; + } + + const auto pCoordinator = alice::UiDocumentRefreshCoordinator::GetOrCreate(pUiDocument); + return pCoordinator ? pCoordinator->FlushPendingDocumentDelta(views) : false; + } + + bool RefreshViewForModelViewChange(alice::IDocument* pDocument) const + { + if (pDocument == nullptr) + { + return false; + } + + const auto views = GetOpenViews(pDocument); + if (views.empty()) + { + return false; + } + + const auto pUiDocument = views.front() ? views.front()->GetOwnerDocument() : std::shared_ptr{}; + const auto pCoordinator = alice::UiDocumentRefreshCoordinator::GetOrCreate(pUiDocument); + return pCoordinator ? pCoordinator->RefreshViewsForModelViewChange(views) : false; + } + + bool PublishPreviewDisplayRecord(alice::IDocument* pDocument, + const std::shared_ptr& pRecord) const + { + if (pDocument == nullptr || !pRecord) + { + return false; + } + + const auto views = GetOpenViews(pDocument); + if (views.empty()) + { + return false; + } + + alice::DocumentViewDisplayRefreshService refreshService; + return refreshService.SetTransientViewRecord(views, pRecord); + } + + bool ClearPreviewDisplayRecord(alice::IDocument* pDocument, alice::ObjectId idObject) const + { + if (pDocument == nullptr || !idObject.IsValid()) + { + return false; + } + + const auto views = GetOpenViews(pDocument); + if (views.empty()) + { + return false; + } + + alice::DocumentViewDisplayRefreshService refreshService; + return refreshService.ClearTransientViewRecord(views, idObject); + } + + bool ClearAllPreviewDisplayRecords(alice::IDocument* pDocument) const + { + if (pDocument == nullptr) + { + return false; + } + + const auto views = GetOpenViews(pDocument); + if (views.empty()) + { + return false; + } + + alice::DocumentViewDisplayRefreshService refreshService; + return refreshService.ClearAllTransientViewRecords(views); + } + + bool RequestViewRepaint(alice::IDocument* pDocument) const + { + bool repainted = false; + for (const auto& pView : GetOpenViews(pDocument)) + { + if (!pView) + { + continue; + } + alice::IViewPort* const pViewPort = pView->GetViewPort(); + if (pViewPort == nullptr) + { + continue; + } + const auto pCanvas = pViewPort->GetCanvas(); + if (!pCanvas) + { + continue; + } + pCanvas->RequestRepaint(); + repainted = true; + } + return repainted; + } + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidDefaultPickBehavior.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidDefaultPickBehavior.cpp new file mode 100644 index 00000000..9636fa4c --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidDefaultPickBehavior.cpp @@ -0,0 +1,102 @@ +#include "SolidDefaultPickBehavior.h" +#include "AliceIRenderViewPortInput.h" + +using namespace sdr; +using namespace alice; + +SolidDefaultPickBehavior::SolidDefaultPickBehavior(SolidPickIntent intent, std::string viewKind) + : m_intent(intent) + , m_viewKind(std::move(viewKind)) +{ + +} + +SolidPickIntent SolidDefaultPickBehavior::GetIntent() const noexcept +{ + return m_intent; +} + +const std::string& SolidDefaultPickBehavior::GetViewKind() const noexcept +{ + return m_viewKind; +} + +bool SolidDefaultPickBehavior::ShouldAppendSelection(std::uint32_t modifiers) const noexcept +{ + return (modifiers & static_cast(RenderKeyModifier::Ctrl)) != 0u; +} + +bool SolidDefaultPickBehavior::AcceptSelectionItem(const SelectionItem& item) const +{ + return AcceptCommandSelectionInput(item.ToCommandSelectionInput()); +} + +bool SolidDefaultPickBehavior::AcceptCommandSelectionInput(const CommandSelectionInput& input) const +{ + if (!input.Handle.TargetObjectId.IsValid()) + return false; + + const std::string primarySemanticRole = input.GetPrimarySemanticRole(); + if (primarySemanticRole.empty()) + return m_intent == SolidPickIntent::DefaultModeling; + + switch (m_intent) + { + case SolidPickIntent::SketchPlaneInput: + return alice::MatchesAnySemanticRoleKind(primarySemanticRole, GetSketchSelectionSemanticRoleKinds()) || alice::MatchesAnySemanticRoleKind(primarySemanticRole, GetSketchPlaneSemanticRoleKinds()); + case SolidPickIntent::OrientationReferenceInput: + return alice::MatchesAnySemanticRoleKind(primarySemanticRole, GetOrientationReferenceSemanticRoleKinds()); + case SolidPickIntent::DefaultModeling: + default: + return alice::MatchesAnySemanticRoleKind(primarySemanticRole, DefaultModelingRoleKinds_()); + } +} +const std::vector& SolidDefaultPickBehavior::GetSketchSelectionSemanticRoleKinds() const +{ + return SketchRoleKinds_(); +} + +const std::vector& SolidDefaultPickBehavior::GetSketchPlaneSemanticRoleKinds() const +{ + return SketchPlaneRoleKinds_(); +} + +const std::vector& SolidDefaultPickBehavior::GetOrientationReferenceSemanticRoleKinds() const +{ + return OrientationReferenceRoleKinds_(); +} + +const std::vector& SolidDefaultPickBehavior::DefaultModelingRoleKinds_() +{ + static const std::vector v = { SemanticRoleKind::DatumPlane, SemanticRoleKind::DatumAxis, SemanticRoleKind::DatumPoint, SemanticRoleKind::DatumCsys, + SemanticRoleKind::ModelPlanarFace, SemanticRoleKind::ModelFace, SemanticRoleKind::ModelEdge, SemanticRoleKind::ModelVertex, + SemanticRoleKind::ModelBody, SemanticRoleKind::ModelCurve, SemanticRoleKind::ModelPoint, SemanticRoleKind::SketchRegion, + SemanticRoleKind::SketchCurve, SemanticRoleKind::SketchPoint, SemanticRoleKind::FeatureResult, SemanticRoleKind::FeatureBody, + SemanticRoleKind::FeatureFace, SemanticRoleKind::FeatureEdge, SemanticRoleKind::FeatureVertex, SemanticRoleKind::Component, + SemanticRoleKind::ComponentInstance, SemanticRoleKind::Occurrence }; + return v; +} + +const std::vector& SolidDefaultPickBehavior::SketchRoleKinds_() +{ + static const std::vector v = { SemanticRoleKind::SketchRegion, SemanticRoleKind::SketchProfile, + SemanticRoleKind::SketchLoop, SemanticRoleKind::SketchChain, SemanticRoleKind::SketchCurve, SemanticRoleKind::SketchPoint, + SemanticRoleKind::Sketch, SemanticRoleKind::SketchFeature }; + return v; +} + +const std::vector& SolidDefaultPickBehavior::SketchPlaneRoleKinds_() +{ + static const std::vector v = { SemanticRoleKind::DatumPlane, SemanticRoleKind::ModelPlanarFace, + SemanticRoleKind::ModelFace, SemanticRoleKind::FeatureFace, SemanticRoleKind::SketchRegion, SemanticRoleKind::SketchProfile }; + return v; +} + +const std::vector& SolidDefaultPickBehavior::OrientationReferenceRoleKinds_() +{ + static const std::vector v = { SemanticRoleKind::DatumPlane, SemanticRoleKind::DatumAxis, + SemanticRoleKind::DatumPoint, SemanticRoleKind::DatumCsys, SemanticRoleKind::ModelPlanarFace, SemanticRoleKind::ModelFace, + SemanticRoleKind::ModelEdge, SemanticRoleKind::ModelVertex, SemanticRoleKind::FeatureFace, SemanticRoleKind::FeatureEdge, + SemanticRoleKind::FeatureVertex, SemanticRoleKind::SketchRegion, SemanticRoleKind::SketchCurve, SemanticRoleKind::SketchPoint }; + return v; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidDefaultPickBehavior.h b/Designer/Interaction/SolidDesignerInteraction/SolidDefaultPickBehavior.h new file mode 100644 index 00000000..d4094f0e --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidDefaultPickBehavior.h @@ -0,0 +1,36 @@ +#pragma once +#include "SolidDesignerInteraction.h" + +#include "AliceISelectionManager.h" +#include "AliceSemanticRoleKind.h" + +#include +#include +#include + +namespace sdr +{ + enum class SolidPickIntent { DefaultModeling, SketchPlaneInput, OrientationReferenceInput }; + + class SOLID_DESIGNER_INTERACTION_EXPORT SolidDefaultPickBehavior + { + public: + explicit SolidDefaultPickBehavior(SolidPickIntent intent = SolidPickIntent::DefaultModeling, std::string viewKind = {}); + SolidPickIntent GetIntent() const noexcept; + const std::string& GetViewKind() const noexcept; + bool ShouldAppendSelection(std::uint32_t modifiers) const noexcept; + bool AcceptSelectionItem(const alice::SelectionItem& item) const; + bool AcceptCommandSelectionInput(const alice::CommandSelectionInput& input) const; + const std::vector& GetSketchSelectionSemanticRoleKinds() const; + const std::vector& GetSketchPlaneSemanticRoleKinds() const; + const std::vector& GetOrientationReferenceSemanticRoleKinds() const; + private: + static const std::vector& DefaultModelingRoleKinds_(); + static const std::vector& SketchRoleKinds_(); + static const std::vector& SketchPlaneRoleKinds_(); + static const std::vector& OrientationReferenceRoleKinds_(); + private: + SolidPickIntent m_intent{ SolidPickIntent::DefaultModeling }; + std::string m_viewKind; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidDefaultPickOperation.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidDefaultPickOperation.cpp new file mode 100644 index 00000000..2bc4b138 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidDefaultPickOperation.cpp @@ -0,0 +1,306 @@ +#include "SolidDefaultPickOperation.h" +#include "AliceOperationKeyBehavior.h" +#include "SolidOperationInputAdapter.h" + +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "AliceISelectionManager.h" +#include "AliceIPickingManager.h" +#include "AliceIHighlightManager.h" +#include "AliceOperationModifierQuery.h" + +#include +#include +#include +#include "AliceVector3d.h" + +using namespace sdr; +using namespace alice; + +namespace +{ + static bool HasModifier_(std::uint32_t modifiers, RenderKeyModifier flag) noexcept + { + return (modifiers & static_cast(flag)) != 0u; + } + + static bool AllowsByFilter_(const PickHit& hit, const SolidSemanticPickFilter& pickFilter) + { + PickTargetOptions options{}; + pickFilter.ConfigurePickTargets(options); + if (!options.Allows(hit.Kind) || !pickFilter.AllowHit(hit)) + { + return false; + } + + RepresentationNodeReference node{}; + node.TargetObjectId = hit.TargetObjectId; + node.RepresentationNodeToken = hit.RepresentationNodeToken; + node.RepresentationNodeSemanticRole = hit.RepresentationNodeSemanticRole; + node.RepresentationNodePathToken = hit.RepresentationNodePathToken; + node.SubElementToken = hit.SubElementToken; + node.ModelElementStableIdentity = hit.ModelElementStableIdentity; + node.PersistentEntityId = hit.PersistentEntityId; + node.TopoSemanticRef = hit.TopoSemanticRef; + node.RuntimeInstanceId = hit.RuntimeInstanceId; + node.PrimitiveId = hit.PrimitiveId; + node.DisplayInstanceToken = hit.DisplayInstanceToken; + return pickFilter.AllowRepresentationNode(node); + } + + static bool TryResolveCyclingCandidate_(IPickingManager* pPickingManager, + const SolidSemanticPickFilter& pickFilter, + std::size_t candidateIndex, + PickHit& outHit) + { + if (pPickingManager == nullptr) + { + return false; + } + + std::vector candidates = pPickingManager->GetCandidateHits(); + std::vector filtered; + filtered.reserve(candidates.size()); + for (const PickHit& hit : candidates) + { + if (AllowsByFilter_(hit, pickFilter)) + { + filtered.push_back(hit); + } + } + if (filtered.empty()) + { + return false; + } + + const std::size_t safeIndex = candidateIndex % filtered.size(); + outHit = filtered[safeIndex]; + return true; + } +} + +SolidDefaultPickOperation::SolidDefaultPickOperation(std::string viewKind) + : m_viewKind(std::move(viewKind)) + , m_behavior(SolidPickIntent::DefaultModeling, m_viewKind) + , m_pickFilter(SolidPickIntent::DefaultModeling) +{ +} + +SolidDefaultPickOperation::~SolidDefaultPickOperation() = default; + +void SolidDefaultPickOperation::InitOperation(IUiView* pCurrentView) +{ + PickOperationBase::InitOperation(pCurrentView); + m_bFinished = false; + m_dragAnchor = {}; + m_isLeftDragging = false; + m_cycleCandidateIndex = 0u; + ClearCapturedPickCandidates(); + ClearLastPickHit(); + ClearPreselectionFeedback(); + ClearSnapFeedback(); +} + +void SolidDefaultPickOperation::OnCancel() +{ + ClearCapturedPickCandidates(); + ClearLastPickHit(); + ClearPreselectionFeedback(); + ClearSnapFeedback(); +} + +bool SolidDefaultPickOperation::OnLButtonDown(IUiView* pCurrentView, const Vector3d& pos) +{ + m_dragAnchor = pos; + m_isLeftDragging = false; + m_cycleCandidateIndex = 0u; + return RefreshPickCandidates(pCurrentView, pos, m_pickFilter) && UpdatePreselection(m_pickFilter); +} + +bool SolidDefaultPickOperation::OnMovePoint(IUiView* pCurrentView, const Vector3d& pos) +{ + std::int32_t screenX = 0; + std::int32_t screenY = 0; + std::uint32_t buttons = 0u; + std::uint32_t modifiers = 0u; + (void)sdr::detail::TryGetCurrentScreenPoint(screenX, screenY, &buttons, &modifiers); + + const bool isLeftPressed = (buttons & static_cast(RenderMouseButton::Left)) != 0u; + if (isLeftPressed) + { + m_isLeftDragging = IsDragGesture_(m_dragAnchor, pos); + if (m_isLeftDragging) + { + ClearPreselectionFeedback(); + m_cycleCandidateIndex = 0u; + return RefreshPickCandidates(pCurrentView, + m_dragAnchor, + pos, + PickBoxStyle::Directional, + m_pickFilter); + } + } + + m_isLeftDragging = false; + m_cycleCandidateIndex = 0u; + if (!RefreshPickCandidates(pCurrentView, pos, m_pickFilter)) + { + ClearPreselectionFeedback(); + return false; + } + return UpdateCurrentPreselectionFromCandidates_(); +} + +bool SolidDefaultPickOperation::OnLButtonUp(IUiView* pCurrentView, const Vector3d& pos) +{ + std::int32_t screenX = 0; + std::int32_t screenY = 0; + std::uint32_t buttons = 0u; + std::uint32_t modifiers = 0u; + (void)sdr::detail::TryGetCurrentScreenPoint(screenX, screenY, &buttons, &modifiers); + + const bool appendSelection = HasModifier_(modifiers, RenderKeyModifier::Shift); + const bool toggleSelection = HasModifier_(modifiers, RenderKeyModifier::Ctrl); + + bool handled = false; + if (m_isLeftDragging && IsDragGesture_(m_dragAnchor, pos)) + { + handled = CommitBoxSelection_(pCurrentView, pos); + } + else + { + if (RefreshPickCandidates(pCurrentView, pos, m_pickFilter)) + { + handled = CommitSelection(m_pickFilter, appendSelection, toggleSelection); + } + } + + m_isLeftDragging = false; + return handled; +} + +bool SolidDefaultPickOperation::IsFinished() const noexcept +{ + return m_bFinished; +} + +bool SolidDefaultPickOperation::HandlePointerMove_(IUiView* pCurrentView, const Vector3d& pos) +{ + return OnMovePoint(pCurrentView, pos); +} + +bool SolidDefaultPickOperation::HandlePointerCommit_(IUiView* pCurrentView, const Vector3d& pos) +{ + return OnLButtonUp(pCurrentView, pos); +} + +bool SolidDefaultPickOperation::ShouldAppendSelection_() const noexcept +{ + std::int32_t x = 0; + std::int32_t y = 0; + std::uint32_t buttons = 0u; + std::uint32_t modifiers = 0u; + if (!sdr::detail::TryGetCurrentScreenPoint(x, y, &buttons, &modifiers)) + { + return false; + } + return HasModifier_(modifiers, RenderKeyModifier::Shift); +} + +void SolidDefaultPickOperation::ClearInvalidPreselection_() const +{ + if (ISelectionManager* const pSelectionManager = ResolveSelectionManager()) + { + if (const auto preselection = pSelectionManager->GetPreselectionInput(); preselection.has_value()) + { + if (!m_behavior.AcceptCommandSelectionInput(preselection.value())) + { + pSelectionManager->ClearPreselection(); + } + } + } +} + +bool SolidDefaultPickOperation::UpdateCurrentPreselectionFromCandidates_() const +{ + IPickingManager* const pPickingManager = ResolvePickingManager(); + PickHit hit; + if (!TryResolveCyclingCandidate_(pPickingManager, m_pickFilter, 0u, hit)) + { + ClearPreselectionFeedback(); + return false; + } + + if (!ApplyPreselection(hit)) + { + return false; + } + ClearInvalidPreselection_(); + return true; +} + +bool SolidDefaultPickOperation::CommitBoxSelection_(IUiView* pCurrentView, const Vector3d& endPos) +{ + std::int32_t x = 0; + std::int32_t y = 0; + std::uint32_t buttons = 0u; + std::uint32_t modifiers = 0u; + (void)sdr::detail::TryGetCurrentScreenPoint(x, y, &buttons, &modifiers); + + const bool appendSelection = HasModifier_(modifiers, RenderKeyModifier::Shift); + const bool toggleSelection = HasModifier_(modifiers, RenderKeyModifier::Ctrl); + if (!RefreshPickCandidates(pCurrentView, m_dragAnchor, endPos, PickBoxStyle::Directional, m_pickFilter)) + { + return false; + } + return CommitSelectionFromCandidateHits(m_pickFilter, appendSelection, toggleSelection, false); +} + +bool SolidDefaultPickOperation::IsDragGesture_(const Vector3d& beginPos, const Vector3d& endPos) noexcept +{ + const double dx = endPos.X() - beginPos.X(); + const double dy = endPos.Y() - beginPos.Y(); + return std::sqrt(dx * dx + dy * dy) >= 6.0; +} + +bool SolidDefaultPickOperation::OnKeyDown(IUiView* pCurrentView, std::int32_t keyCode) +{ + const std::uint32_t modifiers = alice::QueryCurrentKeyboardModifiers(); + if (SolidOperationKeyBehavior::IsEscape(keyCode)) + { + ClearCommittedSelection(); + ClearCommittedSelectionHighlight(); + ClearPreselectionFeedback(); + ClearSnapFeedback(); + ClearCapturedPickCandidates(); + ClearLastPickHit(); + return true; + } + + if (static_cast(keyCode) == InputKeyCode::Tab) + { + IPickingManager* const pPickingManager = ResolvePickingManager(); + PickHit cycledHit; + ++m_cycleCandidateIndex; + if (TryResolveCyclingCandidate_(pPickingManager, m_pickFilter, m_cycleCandidateIndex, cycledHit)) + { + return ApplyPreselection(cycledHit); + } + return false; + } + + if (SolidOperationKeyBehavior::IsUndo(keyCode, modifiers)) + { + return SolidOperationKeyBehavior::ExecuteUndo(); + } + if (SolidOperationKeyBehavior::IsRedo(keyCode, modifiers)) + { + return SolidOperationKeyBehavior::ExecuteRedo(); + } + return false; +} + +bool SolidDefaultPickOperation::OnKeyUp(IUiView*, std::int32_t) +{ + return false; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidDefaultPickOperation.h b/Designer/Interaction/SolidDesignerInteraction/SolidDefaultPickOperation.h new file mode 100644 index 00000000..0fe0ebd5 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidDefaultPickOperation.h @@ -0,0 +1,54 @@ +#pragma once +#include "SolidDesignerInteraction.h" + +#include "AlicePickOperationBase.h" +#include "SolidDefaultPickBehavior.h" +#include "SolidPickFilters.h" + +#include +#include +#include "AliceVector3d.h" + +namespace sdr +{ + /// \brief Long-lived default editing operation for modeling views. + /// + /// when no explicit feature command is active, + /// the current model view keeps a stable selection/picking operation alive so viewport hover/click + /// continues to drive preselection and committed selection. + class SOLID_DESIGNER_INTERACTION_EXPORT SolidDefaultPickOperation final : public alice::PickOperationBase + { + public: + explicit SolidDefaultPickOperation(std::string viewKind = {}); + ~SolidDefaultPickOperation() override; + + void InitOperation(alice::IUiView* pCurrentView) override; + void OnCancel() override; + bool OnLButtonDown(alice::IUiView* pCurrentView, const alice::Vector3d& pos) override; + bool OnMovePoint(alice::IUiView* pCurrentView, const alice::Vector3d& pos) override; + bool OnLButtonUp(alice::IUiView* pCurrentView, const alice::Vector3d& pos) override; + bool OnKeyDown(alice::IUiView* pCurrentView, std::int32_t keyCode) override; + bool OnKeyUp(alice::IUiView* pCurrentView, std::int32_t keyCode) override; + bool IsFinished() const noexcept override; + + private: + bool HandlePointerMove_(alice::IUiView* pCurrentView, const alice::Vector3d& pos); + bool HandlePointerCommit_(alice::IUiView* pCurrentView, const alice::Vector3d& pos); + bool ShouldAppendSelection_() const noexcept; + void ClearInvalidPreselection_() const; + + private: + bool UpdateCurrentPreselectionFromCandidates_() const; + bool CommitBoxSelection_(alice::IUiView* pCurrentView, const alice::Vector3d& endPos); + static bool IsDragGesture_(const alice::Vector3d& beginPos, const alice::Vector3d& endPos) noexcept; + + private: + std::string m_viewKind; + SolidDefaultPickBehavior m_behavior; + SolidSemanticPickFilter m_pickFilter; + alice::Vector3d m_dragAnchor{}; + bool m_isLeftDragging = false; + std::size_t m_cycleCandidateIndex = 0u; + bool m_bFinished = false; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeCommitDataBuilder.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeCommitDataBuilder.cpp new file mode 100644 index 00000000..ff40f65f --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeCommitDataBuilder.cpp @@ -0,0 +1,53 @@ +#include "SolidExtrudeCommitDataBuilder.h" +#include "AliceFeatureLifecycleModels.h" +#include "AliceIFeatureDefinition.h" +#include "AliceIFeatureReferenceSet.h" +#include "AliceExtrudeDefinitionAssembler.h" +#include "AliceExtrudeReferenceSetAssembler.h" + +using namespace sdr; +using namespace alice; + +SolidExtrudeCommitData SolidExtrudeCommitDataBuilder::Build(const SolidExtrudeDefinitionBuildInputs& definitionInputs, + bool reuseExistingSketchForDefinition, + const ObjectId& definitionSourceSketchFeatureId, + bool reuseExistingSketchForReferenceSet, + const ObjectId& referenceSourceSketchFeatureId) +{ + SolidExtrudeCommitData data; + + SolidExtrudeDefinitionBuildInputs definitionBuildInputs = definitionInputs; + definitionBuildInputs.ReuseExistingSketch = reuseExistingSketchForDefinition; + definitionBuildInputs.SourceSketchFeatureId = definitionSourceSketchFeatureId; + data.Definition = alice::ExtrudeDefinitionAssembler::BuildExtrudeDefinition(definitionBuildInputs); + + SolidExtrudeDefinitionBuildInputs referenceBuildInputs = definitionInputs; + referenceBuildInputs.WorkingExtrudeDefinitionData = nullptr; + referenceBuildInputs.WorkingSketchDefinition = nullptr; + referenceBuildInputs.ReuseExistingSketch = reuseExistingSketchForReferenceSet; + referenceBuildInputs.SourceSketchFeatureId = referenceSourceSketchFeatureId; + data.ReferenceSet = alice::ExtrudeReferenceSetAssembler::BuildExtrudeReferenceSet(referenceBuildInputs); + return data; +} + +FeatureCreateRequestModel SolidExtrudeCommitDataBuilder::BuildCreateRequest(const SolidExtrudeCommitData& data, + FeatureLifecycleApplyMode applyMode, + FeatureDomain targetDomain, + FeatureId targetFeatureId, + bool allowIncompleteCommit) +{ + FeatureCreateRequestModel request; + request.SetTargetDomain(targetDomain); + request.SetApplyMode(applyMode); + if (data.Definition) + { + request.SetDefinitionCandidate(data.Definition->Clone()); + } + request.SetReferenceSetCandidate(data.ReferenceSet); + request.SetAllowIncompleteCommit(allowIncompleteCommit); + if (targetFeatureId.IsValid()) + { + request.SetTargetFeatureId(targetFeatureId); + } + return request; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeCommitDataBuilder.h b/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeCommitDataBuilder.h new file mode 100644 index 00000000..46348425 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeCommitDataBuilder.h @@ -0,0 +1,40 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "AliceObjectId.h" +#include "AliceFeaturePrimitives.h" +#include "AliceFeatureAuthoringInputs.h" + +namespace alice +{ + class IFeatureDefinition; + class IFeatureReferenceSet; + class FeatureCreateRequestModel; +} + +namespace sdr +{ + using SolidExtrudeDefinitionBuildInputs = alice::ExtrudeDefinitionBuildInputs; + + struct SOLID_DESIGNER_INTERACTION_EXPORT SolidExtrudeCommitData final + { + std::shared_ptr Definition; + std::shared_ptr ReferenceSet; + [[nodiscard]] bool IsComplete() const noexcept { return Definition != nullptr && ReferenceSet != nullptr; } + }; + + class SOLID_DESIGNER_INTERACTION_EXPORT SolidExtrudeCommitDataBuilder final + { + public: + static SolidExtrudeCommitData Build(const SolidExtrudeDefinitionBuildInputs& definitionInputs, + bool reuseExistingSketchForDefinition, + const alice::ObjectId& definitionSourceSketchFeatureId, + bool reuseExistingSketchForReferenceSet, + const alice::ObjectId& referenceSourceSketchFeatureId); + + static alice::FeatureCreateRequestModel BuildCreateRequest(const SolidExtrudeCommitData& data, + alice::FeatureLifecycleApplyMode applyMode, + alice::FeatureDomain targetDomain, + alice::FeatureId targetFeatureId = {}, + bool allowIncompleteCommit = false); + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeCreateOperation.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeCreateOperation.cpp new file mode 100644 index 00000000..9384b812 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeCreateOperation.cpp @@ -0,0 +1,1099 @@ +#include "SolidExtrudeCreateOperation.h" + +#include "SolidSectionPlacementOperation.h" +#include "SolidSectionEditOperation.h" +#include "SolidSectionPickFilters.h" +#include "SolidExtrudePreviewCoordinator.h" +#include "SolidHostedSketchDisplayCoordinator.h" +#include "SolidHostedSketchCommitCoordinator.h" +#include "SolidFeatureAuthoringTransactionScope.h" +#include "SolidFeatureAuthoringUiContext.h" +#include "AlicePickReferenceOperation.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "AliceIDocument.h" +#include "AliceISelectionManager.h" +#include "AliceIOperationManager.h" +#include "AliceIDocumentFeatureManager.h" +#include "AliceIFeatureEditSessionFactory.h" +#include "AliceFeatureEditService.h" +#include "AliceFeatureLifecycleModels.h" +#include "AliceIFeatureDefinitionFactory.h" +#include "AliceIFeatureReferenceFactory.h" +#include "AliceFeatureObject.h" +#include "AlicePartFeatureObjects.h" +#include "AliceIPartFeatureFamilies.h" +#include "AliceISketchFeature.h" +#include "AliceSketchObjectModel.h" +#include "AliceIExtrudeFeatureEditSession.h" +#include "AliceISketchEditSession.h" +#include "AliceISketchInteractionController.h" +#include "AliceIFeatureSchema.h" +#include "AliceIFeatureElementTree.h" +#include "AliceIFeatureTypeDescriptor.h" + +#include "AliceIUiView.h" +#include "AliceIViewPort.h" +#include "AliceIViewPortCanvas.h" +#include "AliceIModelView.h" +#include "AliceIViewDefinition.h" +#include "UiManager/AliceModelViewNavigationService.h" +#include "AliceFeatureDefinitionPathAccess.h" +#include "AliceVector3d.h" + +#include +#include +#include "SolidDesignerCommands.h" + +using namespace sdr; +using namespace alice; + + +namespace +{ + constexpr FeatElemId kDatumPlaneRolePath = 910u; + constexpr FeatElemId kDatumPlaneOriginXPath = 911u; + constexpr FeatElemId kDatumPlaneOriginYPath = 912u; + constexpr FeatElemId kDatumPlaneOriginZPath = 913u; + constexpr FeatElemId kDatumPlaneNormalXPath = 914u; + constexpr FeatElemId kDatumPlaneNormalYPath = 915u; + constexpr FeatElemId kDatumPlaneNormalZPath = 916u; + constexpr FeatElemId kDatumPlaneUAxisXPath = 917u; + constexpr FeatElemId kDatumPlaneUAxisYPath = 918u; + constexpr FeatElemId kDatumPlaneUAxisZPath = 919u; + + static alice::Vector3d NormalizeOrFallback_(alice::Vector3d value, const alice::Vector3d& fallback) + { + if (value.Normalize() <= 1.0e-12) + { + return fallback; + } + return value; + } + + static bool PopulatePlacementContextFromView_(const std::shared_ptr& pView, + SolidSketchPlacementContext& ioContext) + { + if (!pView) + { + return false; + } + + alice::IViewPort* const pViewPort = pView->GetViewPort(); + const auto pCanvas = pViewPort ? pViewPort->GetCanvas() : std::shared_ptr{}; + const auto pModelView = pView->GetModelView(); + const auto pDefinition = pModelView ? pModelView->GetDefinition() : std::shared_ptr{}; + + if (pCanvas) + { + ioContext.ViewportPixelWidth = std::max(1, pCanvas->GetWidth()); + ioContext.ViewportPixelHeight = std::max(1, pCanvas->GetHeight()); + ioContext.ScreenOriginX = ioContext.ViewportPixelWidth * 0.5; + ioContext.ScreenOriginY = ioContext.ViewportPixelHeight * 0.5; + } + + if (pDefinition) + { + ioContext.PerspectiveProjection = pDefinition->GetProjectionMode() == alice::ProjectionMode::Perspective; + ioContext.CameraFovYRadians = pDefinition->GetFovYRadians(); + ioContext.CameraOrthoScale = pDefinition->GetOrthoScale(); + ioContext.CameraEyeX = pDefinition->GetEye().X(); + ioContext.CameraEyeY = pDefinition->GetEye().Y(); + ioContext.CameraEyeZ = pDefinition->GetEye().Z(); + ioContext.CameraTargetX = pDefinition->GetTarget().X(); + ioContext.CameraTargetY = pDefinition->GetTarget().Y(); + ioContext.CameraTargetZ = pDefinition->GetTarget().Z(); + ioContext.CameraUpX = pDefinition->GetUp().X(); + ioContext.CameraUpY = pDefinition->GetUp().Y(); + ioContext.CameraUpZ = pDefinition->GetUp().Z(); + if (!ioContext.PerspectiveProjection && ioContext.ViewportPixelHeight > 1.0) + { + // OCCT orthographic camera scale is the full viewport size for aspect == 1. + // Therefore the model-space size represented by one vertical screen pixel is + // Scale / viewportHeight instead of 2 * Scale / viewportHeight. + ioContext.ScreenToModelScale = std::max(1.0e-6, ioContext.CameraOrthoScale) / ioContext.ViewportPixelHeight; + } + } + + return true; + } + + static bool ResolveDatumPlaneFrame_(alice::IDocument* pDocument, + const alice::ObjectId& planeId, + alice::Vector3d& outOrigin, + alice::Vector3d& outXAxis, + alice::Vector3d& outYAxis, + alice::Vector3d& outNormal) + { + alice::IDocumentFeatureManager* const pFeatureManager = pDocument ? pDocument->GetDocumentFeatureManagerFw() : nullptr; + alice::IFeature* const pFeature = pFeatureManager ? pFeatureManager->FindFeatureById(planeId) : nullptr; + if (!pFeature || std::string_view(pFeature->GetStableTypeCode()) != "datum.plane") + { + return false; + } + + const alice::IFeatureDefinition* const pDefinition = pFeature->GetDefinition(); + const alice::IFeatureElementTree* const pTree = pDefinition ? pDefinition->GetElementTree() : nullptr; + if (!pTree) + { + return false; + } + + outOrigin = alice::Vector3d(alice::feature::paths::ReadDoubleOrDefault(pTree, { kDatumPlaneOriginXPath }, 0.0), + alice::feature::paths::ReadDoubleOrDefault(pTree, { kDatumPlaneOriginYPath }, 0.0), + alice::feature::paths::ReadDoubleOrDefault(pTree, { kDatumPlaneOriginZPath }, 0.0)); + outNormal = NormalizeOrFallback_(alice::Vector3d(alice::feature::paths::ReadDoubleOrDefault(pTree, { kDatumPlaneNormalXPath }, 0.0), + alice::feature::paths::ReadDoubleOrDefault(pTree, { kDatumPlaneNormalYPath }, 0.0), + alice::feature::paths::ReadDoubleOrDefault(pTree, { kDatumPlaneNormalZPath }, 1.0)), + alice::Vector3d::UnitZ); + outXAxis = NormalizeOrFallback_(alice::Vector3d(alice::feature::paths::ReadDoubleOrDefault(pTree, { kDatumPlaneUAxisXPath }, 1.0), + alice::feature::paths::ReadDoubleOrDefault(pTree, { kDatumPlaneUAxisYPath }, 0.0), + alice::feature::paths::ReadDoubleOrDefault(pTree, { kDatumPlaneUAxisZPath }, 0.0)), + alice::Vector3d::UnitX); + outYAxis = outNormal.Cross(outXAxis); + if (outYAxis.IsZero()) + { + outYAxis = std::abs(outNormal.Dot(alice::Vector3d::UnitY)) < 0.95 ? outNormal.Cross(alice::Vector3d::UnitY) + : outNormal.Cross(alice::Vector3d::UnitX); + } + outYAxis = NormalizeOrFallback_(outYAxis, alice::Vector3d::UnitY); + outXAxis = NormalizeOrFallback_(outYAxis.Cross(outNormal), outXAxis); + return true; + } + + static void ApplyPlaneFrameToPlacementContext_(const alice::Vector3d& origin, + const alice::Vector3d& xAxis, + const alice::Vector3d& yAxis, + const alice::Vector3d& normal, + SolidSketchPlacementContext& ioContext) + { + ioContext.PlaneAnchorX = origin.X(); + ioContext.PlaneAnchorY = origin.Y(); + ioContext.PlaneAnchorZ = origin.Z(); + ioContext.HasPlaneAnchor = true; + ioContext.PlaneXAxisX = xAxis.X(); + ioContext.PlaneXAxisY = xAxis.Y(); + ioContext.PlaneXAxisZ = xAxis.Z(); + ioContext.PlaneYAxisX = yAxis.X(); + ioContext.PlaneYAxisY = yAxis.Y(); + ioContext.PlaneYAxisZ = yAxis.Z(); + ioContext.PlaneNormalX = normal.X(); + ioContext.PlaneNormalY = normal.Y(); + ioContext.PlaneNormalZ = normal.Z(); + ioContext.HasPlaneFrame = true; + } + + static bool ConfigureSketchAuthoringView_(alice::IDocument* pDocument, + const std::shared_ptr& pView, + const alice::ObjectId& planeId, + SolidSketchPlacementContext& ioContext) + { + if (!pView) + { + return false; + } + + const auto pModelView = pView->GetModelView(); + if (pModelView) + { + pModelView->SetWorkPlaneId(planeId); + } + + alice::ModelViewNavigationService navigationService; + (void)navigationService.LookNormalToWorkPlane(pView); + (void)PopulatePlacementContextFromView_(pView, ioContext); + + alice::Vector3d origin; + alice::Vector3d xAxis; + alice::Vector3d yAxis; + alice::Vector3d normal; + if (ResolveDatumPlaneFrame_(pDocument, planeId, origin, xAxis, yAxis, normal)) + { + ApplyPlaneFrameToPlacementContext_(origin, xAxis, yAxis, normal, ioContext); + ioContext.CameraTargetX = origin.X(); + ioContext.CameraTargetY = origin.Y(); + ioContext.CameraTargetZ = origin.Z(); + return true; + } + return false; + } + + static bool ComputePlacementFrameFromContext_(const SolidSketchPlacementContext& context, + alice::Vector3d& outOrigin, + alice::Vector3d& outXAxis, + alice::Vector3d& outYAxis) + { + outOrigin = context.HasPlaneAnchor + ? alice::Vector3d(context.PlaneAnchorX, context.PlaneAnchorY, context.PlaneAnchorZ) + : alice::Vector3d(context.CameraTargetX, context.CameraTargetY, context.CameraTargetZ); + if (context.HasPlaneFrame) + { + outXAxis = NormalizeOrFallback_(alice::Vector3d(context.PlaneXAxisX, context.PlaneXAxisY, context.PlaneXAxisZ), alice::Vector3d::UnitX); + outYAxis = NormalizeOrFallback_(alice::Vector3d(context.PlaneYAxisX, context.PlaneYAxisY, context.PlaneYAxisZ), alice::Vector3d::UnitY); + return true; + } + + const alice::Vector3d eye(context.CameraEyeX, context.CameraEyeY, context.CameraEyeZ); + const alice::Vector3d target(context.CameraTargetX, context.CameraTargetY, context.CameraTargetZ); + alice::Vector3d up(context.CameraUpX, context.CameraUpY, context.CameraUpZ); + up = NormalizeOrFallback_(up, alice::Vector3d::UnitY); + const alice::Vector3d forward = NormalizeOrFallback_(target - eye, alice::Vector3d::NegaUnitZ); + outXAxis = NormalizeOrFallback_(forward.Cross(up), alice::Vector3d::UnitX); + outYAxis = NormalizeOrFallback_(outXAxis.Cross(forward), up); + return true; + } +} + + +SolidExtrudeCreateOperation::SolidExtrudeCreateOperation(CommandParameter params) + : m_params(std::move(params)) +{ +} + +SolidExtrudeCreateOperation::~SolidExtrudeCreateOperation() = default; + +void SolidExtrudeCreateOperation::InitOperation(IUiView* pCurrentView) +{ + SolidAuthoringOperationBase::InitOperation(pCurrentView); + ResolveContext_(); + PrimeInputsFromParameters_(); + InitializeSketchPlacementContextFromActiveView_(); + (void)EnsureSketchEditSession_(); + (void)EnsureExtrudeDefinitionEditSession_(); + (void)EnterDashboardUi_(); + + ObjectId planeId; + std::string selectionKey; + std::string semanticRole; + if (TryResolveSketchPlaneFromSelection_(planeId, selectionKey, semanticRole)) + { + (void)StartSectionPlacement_(planeId, selectionKey, semanticRole); + return; + } + (void)BeginDefineInternalSketchPlacement(); +} + +void SolidExtrudeCreateOperation::OnCancel() +{ + (void)CancelWorkflow(); +} + +bool SolidExtrudeCreateOperation::CanConsumeCommand() +{ + return true; +} + +bool SolidExtrudeCreateOperation::ConsumeCommand(IUiView* pCurrentView, const std::string& commandId, const CommandParameter& params) +{ + (void)pCurrentView; + (void)params; + return RouteWorkflowCommand_(commandId); +} + +void SolidExtrudeCreateOperation::OnChildOperationFinished(const OperationResult& childResult) +{ + if (const auto* const pPlacement = dynamic_cast(childResult.Payload.get())) + { + if (childResult.FinishStatus == OperationFinishStatus::Successful && pPlacement->Accepted) + { + m_sectionInput = pPlacement->SectionInput; + m_sketchPlacementContext = pPlacement->PlacementContext; + m_sketchPlacementContext.SketchPlaneId = m_sectionInput.SketchPlaneReferenceId; + m_sketchPlacementContext.PlacementReferenceId = m_sectionInput.PlacementReferenceId; + m_sketchEditState.SetSketchPlaneReferenceId(m_sectionInput.SketchPlaneReferenceId); + m_sketchEditState.SetPlacementReferenceId(m_sectionInput.PlacementReferenceId); + + const auto pView = GetPrimaryOpenView(m_pDocument); + (void)ConfigureSketchAuthoringView_(m_pDocument, + pView, + m_sectionInput.SketchPlaneReferenceId, + m_sketchPlacementContext); + SyncSketchEditSessionFromState_(); + RebuildHostedSketchDisplay_(); + (void)EditSectionSketch(); + return; + } + if (!pPlacement->ErrorText.empty()) + { + m_strLastErrorText = pPlacement->ErrorText; + } + return; + } + + if (const auto* const pSection = dynamic_cast(childResult.Payload.get())) + { + if (childResult.FinishStatus == OperationFinishStatus::Successful && pSection->Accepted) + { + m_sketchEditState.SetSketch(pSection->Sketch); + RefreshSectionInputFromSketch_(); + SyncSketchEditSessionFromState_(); + (void)EnterDashboardUi_(); + if (BuildOrRefreshPreview_()) + { + ClearHostedSketchDisplay_(); + m_stage = ExtrudeWorkflowStage::PreviewingDashboard; + } + else + { + RebuildHostedSketchDisplay_(); + m_stage = ExtrudeWorkflowStage::AwaitSectionSource; + } + return; + } + + if (!pSection->ErrorText.empty()) + { + m_strLastErrorText = pSection->ErrorText; + } + + if (m_pSectionSketchBeforeEditing) + { + m_sketchEditState.SetSketch(m_pSectionSketchBeforeEditing); + m_sectionInput = m_sectionInputBeforeEditing; + SyncSketchEditSessionFromState_(); + } + + if (m_bHadAcceptedSectionBeforeEditing) + { + (void)EnterDashboardUi_(); + if (BuildOrRefreshPreview_()) + { + ClearHostedSketchDisplay_(); + m_stage = ExtrudeWorkflowStage::PreviewingDashboard; + } + else + { + RebuildHostedSketchDisplay_(); + m_stage = ExtrudeWorkflowStage::AwaitSectionSource; + } + } + else + { + ClearHostedSketchDisplay_(); + (void)EnterDashboardUi_(); + m_stage = ExtrudeWorkflowStage::AwaitSectionSource; + } + return; + } + + if (const auto* const pPick = dynamic_cast(childResult.Payload.get())) + { + if (childResult.FinishStatus == OperationFinishStatus::Successful && pPick->ReferenceId.IsValid()) + { + m_bUseExistingSketchSection = true; + m_idSectionSourceSketchFeature = pPick->ReferenceId; + (void)BuildOrRefreshPreview_(); + (void)EnterDashboardUi_(); + m_stage = ExtrudeWorkflowStage::PreviewingDashboard; + return; + } + } +} + +bool SolidExtrudeCreateOperation::IsFinished() const noexcept +{ + return m_bFinished || OperationBase::IsFinished(); +} + +bool SolidExtrudeCreateOperation::CanDefineInternalSketchPlacement() const noexcept +{ + return !IsFinished(); +} + +bool SolidExtrudeCreateOperation::CanReuseExistingSketchSection() const noexcept +{ + return !IsFinished(); +} + +bool SolidExtrudeCreateOperation::CanEditSectionSketch() const noexcept +{ + return !IsFinished() && m_sectionInput.SketchPlaneReferenceId.IsValid(); +} + +bool SolidExtrudeCreateOperation::CanFlipSectionOrientation() const noexcept +{ + return CanEditSectionSketch(); +} + +bool SolidExtrudeCreateOperation::CanRestoreSectionOrientation() const noexcept +{ + return m_sketchPlacementContext.FlipHorizontal; +} + +bool SolidExtrudeCreateOperation::IsEditingSketch() const noexcept +{ + return m_stage == ExtrudeWorkflowStage::EditingSection; +} + +bool SolidExtrudeCreateOperation::IsPreviewingDashboard() const noexcept +{ + return m_stage == ExtrudeWorkflowStage::PreviewingDashboard; +} + +const SolidSketchSectionInput& SolidExtrudeCreateOperation::GetSectionInput() const noexcept +{ + return m_sectionInput; +} + +const SolidExtrudeDashboardInput& SolidExtrudeCreateOperation::GetDashboardInput() const noexcept +{ + return m_dashboardInput; +} + +const SolidSketchEditState& SolidExtrudeCreateOperation::GetSketchEditState() const noexcept +{ + return m_sketchEditState; +} + +const SolidSketchHighlightState& SolidExtrudeCreateOperation::GetSketchHighlightState() const noexcept +{ + return m_sketchHighlightState; +} + +const std::string& SolidExtrudeCreateOperation::GetLastErrorText() const noexcept +{ + return m_strLastErrorText; +} + +bool SolidExtrudeCreateOperation::BeginDefineInternalSketchPlacement() +{ + m_bUseExistingSketchSection = false; + m_idSectionSourceSketchFeature = {}; + return StartSectionPlacement_(); +} + +bool SolidExtrudeCreateOperation::BeginReuseExistingSketchSelection() +{ + return StartExistingSketchSelection_(); +} + +bool SolidExtrudeCreateOperation::EditSectionSketch() +{ + return StartSectionEdit_(); +} + +bool SolidExtrudeCreateOperation::UpdateDashboard(const SolidExtrudeDashboardInput& input) +{ + m_dashboardInput = input; + return BuildOrRefreshPreview_(); +} + +bool SolidExtrudeCreateOperation::ConfirmFeature() +{ + if (!CanConfirmFeature()) + { + m_strLastErrorText = "Extrude dashboard OK is only valid while the workflow is in dashboard preview state."; + return false; + } + + m_stage = ExtrudeWorkflowStage::Committing; + return CommitFeatureCreation_(); +} + +bool SolidExtrudeCreateOperation::CancelWorkflow() +{ + if (!CanCancelWorkflow()) + { + return false; + } + + DiscardPreview_(); + ClearHostedSketchDisplay_(); + (void)ExitCreationUiToHome_(); + m_stage = ExtrudeWorkflowStage::Cancelled; + m_bFinished = true; + MarkCancelled(OperationFinishReason::Esc); + return true; +} + +bool SolidExtrudeCreateOperation::CanConfirmFeature() const noexcept +{ + return !m_bFinished && m_stage == ExtrudeWorkflowStage::PreviewingDashboard; +} + +bool SolidExtrudeCreateOperation::CanCancelWorkflow() const noexcept +{ + return !m_bFinished && + m_stage != ExtrudeWorkflowStage::Finished && + m_stage != ExtrudeWorkflowStage::Cancelled; +} + +bool SolidExtrudeCreateOperation::FlipSectionOrientation() +{ + m_sketchPlacementContext.FlipHorizontal = !m_sketchPlacementContext.FlipHorizontal; + RebuildHostedSketchDisplay_(); + return BuildOrRefreshPreview_(); +} + +bool SolidExtrudeCreateOperation::RestoreSectionOrientation() +{ + m_sketchPlacementContext.FlipHorizontal = false; + RebuildHostedSketchDisplay_(); + return BuildOrRefreshPreview_(); +} + +SolidExtrudeCreateOperation* SolidExtrudeCreateOperation::FindActive(ISession* pSession) noexcept +{ + IOperationManager* const pOperationManager = pSession ? pSession->GetOperationManagerFw() : nullptr; + if (!pOperationManager) return nullptr; + const std::size_t depth = pOperationManager->ActiveDepth(); + for (std::size_t i = depth; i > 0; --i) + { + if (auto* const pOp = dynamic_cast(pOperationManager->GetOperationAt(i - 1u))) return pOp; + } + return nullptr; +} + +bool SolidExtrudeCreateOperation::RouteWorkflowCommand_(const std::string& commandId) +{ + using namespace Cmd; + + if (commandId == SKETCH_DEFINEINTERNAL) + { + return BeginDefineInternalSketchPlacement(); + } + if (commandId == SKETCH_REUSE) + { + return BeginReuseExistingSketchSelection(); + } + if (commandId == SKETCH_EDIT) + { + return EditSectionSketch(); + } + if (commandId == SKETCH_SECTION_FLIPSECTIONORIENTATION) + { + return FlipSectionOrientation(); + } + if (commandId == SKETCH_SECTION_RESTORESECTIONORIENTATION) + { + return RestoreSectionOrientation(); + } + if (commandId == FEATURE_EXTRUDE_OK) + { + return ConfirmFeature(); + } + if (commandId == FEATURE_EXTRUDE_CANCEL) + { + return CancelWorkflow(); + } + + return false; +} + +bool SolidExtrudeCreateOperation::ResolveContext_() +{ + m_pSession = CoreAppUtil::GetCurrentSession(); + m_pDocument = m_pSession ? m_pSession->GetActiveDocument() : nullptr; + return m_pDocument != nullptr; +} + +void SolidExtrudeCreateOperation::PrimeInputsFromParameters_() +{ + const auto rawFeatureId = m_params.Get("featureId", 0ull); + if (rawFeatureId != 0ull) + { + m_idEditedExtrudeFeature = ObjectId::FromPermanentValue(rawFeatureId); + m_bEditingExistingFeature = m_idEditedExtrudeFeature.IsValid(); + } +} + +void SolidExtrudeCreateOperation::InitializeSketchPlacementContextFromActiveView_() +{ + m_sketchPlacementContext = SolidSketchPlacementContext{}; + + const auto pView = GetPrimaryOpenView(m_pDocument); + if (!PopulatePlacementContextFromView_(pView, m_sketchPlacementContext)) + { + m_sketchPlacementContext.ScreenOriginX = 640.0; + m_sketchPlacementContext.ScreenOriginY = 360.0; + m_sketchPlacementContext.ScreenToModelScale = 0.01; + m_sketchPlacementContext.CameraEyeZ = 10.0; + m_sketchPlacementContext.CameraTargetZ = 0.0; + m_sketchPlacementContext.CameraUpY = 1.0; + } +} + +bool SolidExtrudeCreateOperation::TryResolveSketchPlaneFromSelection_(ObjectId& outPlaneId, std::string& outKey, std::string& outRole) const +{ + ISelectionManager* const pSelectionManager = m_pSession ? m_pSession->GetSelectionManagerFw() : nullptr; + if (!pSelectionManager) return false; + if (auto pre = pSelectionManager->GetPreselectionInput(); pre.has_value()) + { + outPlaneId = pre->Handle.TargetObjectId; + outKey = pre->GetPrimarySelectionToken(); + outRole = pre->GetPrimarySemanticRole(); + return outPlaneId.IsValid(); + } + const auto selections = pSelectionManager->GetSelectionInputs(); + if (!selections.empty()) + { + outPlaneId = selections.front().Handle.TargetObjectId; + outKey = selections.front().GetPrimarySelectionToken(); + outRole = selections.front().GetPrimarySemanticRole(); + return outPlaneId.IsValid(); + } + return false; +} + +bool SolidExtrudeCreateOperation::EnsureSketchEditSession_() +{ + if (m_pSketchEditSession) + return true; + + IFeatureEditSessionFactory* const pFactory = IFeatureEditSessionFactory::Get(); + if (!pFactory) + return false; + + if (m_bEditingExistingFeature && m_pEditedInternalSketchFeature) + { + m_pSketchEditSession = pFactory->BeginSketchEdit(*m_pDocument, *m_pEditedInternalSketchFeature); + if (m_pSketchEditSession) + { + (void)m_pSketchEditSession->RestoreWorkingSketchFromWorkingDefinition(); + if (const std::shared_ptr pSketch = m_pSketchEditSession->GetWorkingSketch()) + { + m_sketchEditState.SetSketch(pSketch); + RefreshSectionInputFromSketch_(); + } + } + return m_pSketchEditSession != nullptr; + } + if (!m_pTransientSketchFeature) + { + IFeatureDefinitionFactory* const pDefFactory = IFeatureDefinitionFactory::Get(); + IFeatureReferenceFactory* const pRefFactory = IFeatureReferenceFactory::Get(); + if (!pDefFactory || !pRefFactory) + return false; + + auto pTree = pDefFactory->CreateElementTree(); + const SchemaVersion version = SchemaVersion::FromComponents(1u,0u,0u,0u); + auto pSchema = pDefFactory->CreateSchema("schema.sketch.internal", version, TypeId{}); + auto pTypeDescriptor = pDefFactory->CreateTypeDescriptor("sketch.internal", "Internal Sketch", FeatureDomain::Sketch, TypeId{}, TypeId{}); + auto pDefinition = pDefFactory->CreateDefinition("sketch.internal", TypeId{}, version, std::move(pSchema), std::move(pTree), std::move(pTypeDescriptor)); + m_pTransientSketchFeature = std::make_shared(FeatureDomain::Sketch); + m_pTransientSketchFeature->SetFeatureId(FeatureId::FromTransientValue(1001)); + m_pTransientSketchFeature->SetStableTypeCode("sketch.internal"); + m_pTransientSketchFeature->SetDefinition(std::move(pDefinition)); + m_pTransientSketchFeature->SetReferenceSet(pRefFactory->CreateReferenceSet()); + } + + m_pSketchEditSession = pFactory->BeginSketchEdit(*m_pTransientSketchFeature); + + if (m_pSketchEditSession) + SyncSketchEditSessionFromState_(); + return m_pSketchEditSession != nullptr; +} + +bool SolidExtrudeCreateOperation::EnsureExtrudeDefinitionEditSession_() +{ + if (m_pExtrudeEditSession) + return true; + + IFeatureEditSessionFactory* const pFactory = IFeatureEditSessionFactory::Get(); + if (!pFactory) + return false; + + if (m_bEditingExistingFeature && m_pEditedExtrudeFeature) + { + if (auto* const pExtrude = dynamic_cast(m_pEditedExtrudeFeature.get())) + { + m_pExtrudeEditSession = pFactory->BeginExtrudeEdit(*m_pDocument, *pExtrude); + return m_pExtrudeEditSession != nullptr; + } + return false; + } + if (!m_pTransientExtrudeFeature) + { + IFeatureDefinitionFactory* const pDefFactory = IFeatureDefinitionFactory::Get(); + IFeatureReferenceFactory* const pRefFactory = IFeatureReferenceFactory::Get(); + if (!pDefFactory || !pRefFactory) + return false; + + auto pTree = pDefFactory->CreateElementTree(); + const SchemaVersion version = SchemaVersion::FromComponents(1u,0u,0u,0u); + auto pSchema = pDefFactory->CreateSchema("schema.part.extrude", version, TypeId{}); + auto pTypeDescriptor = pDefFactory->CreateTypeDescriptor("part.extrude", "Extrude", FeatureDomain::Part, TypeId{}, TypeId{}); + auto pDefinition = pDefFactory->CreateDefinition("part.extrude", TypeId{}, version, std::move(pSchema), std::move(pTree), std::move(pTypeDescriptor)); + m_pTransientExtrudeFeature = std::make_shared(); + m_pTransientExtrudeFeature->SetFeatureId(FeatureId::FromTransientValue(2001)); + m_pTransientExtrudeFeature->SetStableTypeCode("part.extrude"); + m_pTransientExtrudeFeature->SetDefinition(std::move(pDefinition)); + m_pTransientExtrudeFeature->SetReferenceSet(pRefFactory->CreateReferenceSet()); + } + m_pExtrudeEditSession = m_pTransientExtrudeFeature->EditDefinition(); + return m_pExtrudeEditSession != nullptr; +} + +void SolidExtrudeCreateOperation::SyncSketchEditSessionFromState_() +{ + if (!m_pSketchEditSession) + return; + + m_sketchEditState.SetSketchPlaneReferenceId(m_sectionInput.SketchPlaneReferenceId); + m_sketchEditState.SetPlacementReferenceId(m_sectionInput.PlacementReferenceId); + + (void)m_pSketchEditSession->SetWorkingSketch(m_sketchEditState.GetSketch()); + (void)m_pSketchEditSession->SetPlacementReferences(m_sectionInput.SketchPlaneReferenceId, m_sectionInput.PlacementReferenceId); + + alice::Vector3d frameOrigin; + alice::Vector3d frameXAxis; + alice::Vector3d frameYAxis; + if (ComputePlacementFrameFromContext_(m_sketchPlacementContext, frameOrigin, frameXAxis, frameYAxis)) + { + (void)m_pSketchEditSession->SetKernelPlacementFrame(frameOrigin, frameXAxis, frameYAxis); + } + else + { + (void)m_pSketchEditSession->ClearKernelPlacementFrame(); + } + + RefreshSectionInputFromSketch_(); + (void)m_pSketchEditSession->SetSectionAnalysis(m_sectionInput.ClosedProfileCount, + m_sectionInput.OpenChainCount, + m_sectionInput.HasSelfIntersection, + m_sectionInput.HasDanglingGeometry, + m_sectionInput.HasZeroAreaProfile); + (void)m_pSketchEditSession->SyncKernelCurveBindings(); + (void)m_pSketchEditSession->SyncWorkingDefinitionFromSketch(); +} + +bool SolidExtrudeCreateOperation::SyncExtrudeDefinitionEditSessionFromState_() +{ + if (!EnsureExtrudeDefinitionEditSession_() || !m_pExtrudeEditSession) + return false; + + (void)m_pExtrudeEditSession->SetFeatureName(m_dashboardInput.FeatureName); + (void)m_pExtrudeEditSession->SetOperation(m_dashboardInput.RemoveMaterial ? ExtrudeMaterialOperation::Remove : ExtrudeMaterialOperation::Add); + if (m_bUseExistingSketchSection) + (void)m_pExtrudeEditSession->ReuseSketchFeature(m_idSectionSourceSketchFeature); + else + (void)m_pExtrudeEditSession->UseInternalSection(); + + ExtrudeSideLimit side1; + side1.Type = m_dashboardInput.Side1ExtentType; + side1.Distance = m_dashboardInput.Depth; + (void)m_pExtrudeEditSession->SetSide1Limit(side1); + ExtrudeSideLimit side2; side2.Type = m_dashboardInput.Symmetric ? std::string("Blind") : m_dashboardInput.Side2ExtentType; + side2.Distance = m_dashboardInput.Symmetric ? m_dashboardInput.Depth : 0.0; + (void)m_pExtrudeEditSession->SetSide2Limit(side2); + ExtrudeDirectionData direction; direction.ReverseDirection = m_dashboardInput.ReverseDirection; + direction.Symmetric = m_dashboardInput.Symmetric; + (void)m_pExtrudeEditSession->SetDirection(direction); + ExtrudeDraftData draft; + draft.Enabled = m_dashboardInput.AddTaper; + draft.Angle = m_dashboardInput.TaperAngle; + (void)m_pExtrudeEditSession->SetDraft(draft); + return true; +} + +void SolidExtrudeCreateOperation::RefreshSectionInputFromSketch_() +{ + const SolidSketchSectionAnalysis analysis = m_sketchEditState.AnalyzeSection(); + m_sectionInput.ClosedProfileCount = analysis.ClosedProfileCount; + m_sectionInput.OpenChainCount = analysis.OpenChainCount; + m_sectionInput.HasSelfIntersection = analysis.HasSelfIntersection; + m_sectionInput.HasDanglingGeometry = analysis.HasDanglingGeometry; + m_sectionInput.HasZeroAreaProfile = analysis.HasZeroAreaProfile; +} + +SolidExtrudeDefinitionBuildInputs SolidExtrudeCreateOperation::BuildDefinitionBuildInputs_() const +{ + SolidExtrudeDefinitionBuildInputs inputs; + inputs.SectionInput = &m_sectionInput; + inputs.Sketch = m_sketchEditState.GetSketch().get(); + inputs.SketchPlacementContext = &m_sketchPlacementContext; + inputs.WorkingExtrudeDefinitionData = nullptr; + if (m_pExtrudeEditSession) + { + inputs.WorkingExtrudeDefinitionDataStorage = {}; + alice::ExtrudeStructuredDefinitionData structured{}; + if (m_pExtrudeEditSession->ReadWorkingStructuredDefinitionData(structured)) + { + inputs.WorkingExtrudeDefinitionDataStorage = structured.Definition; + inputs.WorkingExtrudeDefinitionData = &inputs.WorkingExtrudeDefinitionDataStorage; + if (!inputs.Sketch && structured.InternalSketch) + { + inputs.Sketch = structured.InternalSketch.get(); + } + inputs.StructuredSectionSnapshotStorage = structured.SectionSnapshot; + inputs.StructuredSectionSnapshot = &inputs.StructuredSectionSnapshotStorage; + } + else if (m_pExtrudeEditSession->ReadWorkingDefinitionData(inputs.WorkingExtrudeDefinitionDataStorage)) + { + inputs.WorkingExtrudeDefinitionData = &inputs.WorkingExtrudeDefinitionDataStorage; + } + } + inputs.Depth = m_dashboardInput.Depth; + inputs.RemoveMaterial = m_dashboardInput.RemoveMaterial; + inputs.ReverseDirection = m_dashboardInput.ReverseDirection; + inputs.Symmetric = m_dashboardInput.Symmetric; + inputs.Side1ExtentType = m_dashboardInput.Side1ExtentType; + inputs.Side2ExtentType = m_dashboardInput.Side2ExtentType; + inputs.AddTaper = m_dashboardInput.AddTaper; + inputs.TaperAngle = m_dashboardInput.TaperAngle; + inputs.FeatureName = m_dashboardInput.FeatureName; + inputs.SectionOrientationFlipped = m_sketchPlacementContext.FlipHorizontal; + return inputs; +} + +bool SolidExtrudeCreateOperation::EnterSketchEditingUi_() +{ + (void)ActivateSolidAuthoringWorkbench(kExtrudeAuthoringUiProfile.SketchWorkbenchId, m_pDocument); + return ApplySolidAuthoringUiContext(kExtrudeAuthoringUiProfile.SketchUiContextId); +} + +bool SolidExtrudeCreateOperation::EnterDashboardUi_() +{ + (void)ActivateSolidAuthoringWorkbench(kExtrudeAuthoringUiProfile.ModelingWorkbenchId, m_pDocument); + return ApplySolidAuthoringUiContext(kExtrudeAuthoringUiProfile.DashboardUiContextId); +} + +bool SolidExtrudeCreateOperation::ExitCreationUiToHome_() +{ + const bool workbenchOk = ActivateSolidAuthoringWorkbench(kExtrudeAuthoringUiProfile.RestoreUiContextId, m_pDocument); + const bool uiContextOk = ApplySolidAuthoringUiContext(kExtrudeAuthoringUiProfile.RestoreUiContextId); + return workbenchOk || uiContextOk; +} + +bool SolidExtrudeCreateOperation::RestoreDefaultModelingInteraction_() +{ + return ExitCreationUiToHome_(); +} + +bool SolidExtrudeCreateOperation::StartSectionPlacement_(ObjectId preselectedPlaneId, std::string preselectedPlaneKey, std::string preselectedPlaneRole) +{ + m_stage = ExtrudeWorkflowStage::DefiningSectionPlacement; + return StartChildOperation(std::make_unique(preselectedPlaneId, std::move(preselectedPlaneKey), std::move(preselectedPlaneRole))); +} + +bool SolidExtrudeCreateOperation::StartExistingSketchSelection_() +{ + m_stage = ExtrudeWorkflowStage::PickingExistingSketch; + PickReferenceInputData input; + input.PromptText = "Select existing sketch."; + input.AllowPreselection = true; + return StartChildOperation(std::make_unique(input, std::make_shared())); +} + +bool SolidExtrudeCreateOperation::StartSectionEdit_() +{ + if (!EnsureSketchEditSession_()) + return false; + + m_pSectionSketchBeforeEditing.reset(); + if (const std::shared_ptr currentSketch = m_sketchEditState.GetSketch()) + { + m_pSectionSketchBeforeEditing = alice::Sketch::CloneFrom(*currentSketch); + } + m_sectionInputBeforeEditing = m_sectionInput; + m_bHadAcceptedSectionBeforeEditing = m_sectionInput.ClosedProfileCount > 0 + && m_sectionInput.OpenChainCount == 0 + && !m_sectionInput.HasDanglingGeometry + && !m_sectionInput.HasSelfIntersection + && !m_sectionInput.HasZeroAreaProfile; + + m_stage = ExtrudeWorkflowStage::EditingSection; + (void)EnterSketchEditingUi_(); + RebuildHostedSketchDisplay_(); + return StartChildOperation(std::make_unique(m_pDocument, + &m_sketchEditState, + m_pSketchEditSession.get(), + m_sketchPlacementContext, + &m_strLastErrorText, + [this]() { SyncSketchEditSessionFromState_(); RebuildHostedSketchDisplay_(); }, + [this]() { RebuildHostedSketchDisplay_(); }, + []() {}, + []() {})); +} + +bool SolidExtrudeCreateOperation::BuildOrRefreshPreview_() +{ + if (!m_pDocument) + return false; + + RefreshSectionInputFromSketch_(); + if (!SyncExtrudeDefinitionEditSessionFromState_()) + { + m_strLastErrorText = "Extrude working definition session could not be synchronized before preview evaluation."; + return false; + } + + SolidExtrudeSectionSourceState state; + state.EditingExistingFeature = m_bEditingExistingFeature; + state.UseExistingSketchSection = m_bUseExistingSketchSection; + state.SelectedSourceSketchFeatureId = m_idSectionSourceSketchFeature; + state.CommittedInternalSketchFeatureId = m_idCommittedInternalSketchFeature; + const SolidExtrudeSectionSourcePlan plan = SolidExtrudeSectionSourceCoordinator::ResolveForPreview(state); + if (plan.IsReuseExistingSketch() && !plan.HasResolvedSourceSketch()) + { + m_strLastErrorText = "Extrude preview requires a valid reused sketch feature before the dashboard can evaluate."; + return false; + } + + SolidExtrudeDefinitionBuildInputs inputs = BuildDefinitionBuildInputs_(); + SolidExtrudeCommitData data = SolidExtrudeCommitDataBuilder::Build(inputs, + plan.IsReuseExistingSketch(), + plan.SourceSketchFeatureId, + plan.IsReuseExistingSketch(), + plan.SourceSketchFeatureId); + if (!data.IsComplete()) + { + m_strLastErrorText = "Extrude definition/reference data could not be built for preview."; + return false; + } + if (!SolidExtrudePreviewCoordinator::RebuildPreview(*m_pDocument, data, m_idPreviewFeature, m_pPreviewSeedFeature, m_pPreviewDisplayRecord, m_strLastErrorText)) + return false; + + if (m_pPreviewDisplayRecord) + (void)PublishPreviewDisplayRecord(m_pDocument, m_pPreviewDisplayRecord); + return true; +} + +bool SolidExtrudeCreateOperation::CommitFeatureCreation_() +{ + IDocumentFeatureManager* const pFeatureManager = m_pDocument ? m_pDocument->GetDocumentFeatureManagerFw() : nullptr; + if (!pFeatureManager) + { + m_strLastErrorText = "Document feature manager is not available for feature commit."; + return false; + } + + SolidFeatureAuthoringTransactionScope txScope(m_pDocument, m_bEditingExistingFeature ? "Redefine Extrude Feature" : "Create Extrude Feature"); + if (!txScope.IsActive()) + { + m_strLastErrorText = txScope.GetLastError(); + return false; + } + + SolidExtrudeSectionSourceState state; state.EditingExistingFeature = m_bEditingExistingFeature; state.UseExistingSketchSection = m_bUseExistingSketchSection; state.SelectedSourceSketchFeatureId = m_idSectionSourceSketchFeature; state.CommittedInternalSketchFeatureId = m_idCommittedInternalSketchFeature; + SolidExtrudeSectionSourcePlan plan = SolidExtrudeSectionSourceCoordinator::ResolveForCommit(state); + if (!plan.IsReuseExistingSketch() && plan.RequiresInternalSketchCommit) + { + SolidExtrudeDefinitionBuildInputs sketchInputs = BuildDefinitionBuildInputs_(); + std::shared_ptr pSketch = SolidHostedSketchCommitCoordinator::CommitInternalSketch(*m_pDocument, sketchInputs, &m_strLastErrorText); + if (!pSketch) + return false; + + plan.SourceSketchFeatureId = pSketch->GetFeatureId(); + m_idCommittedInternalSketchFeature = plan.SourceSketchFeatureId; + } + if (!SyncExtrudeDefinitionEditSessionFromState_()) + return false; + + SolidExtrudeDefinitionBuildInputs inputs = BuildDefinitionBuildInputs_(); + SolidExtrudeCommitData data = SolidExtrudeCommitDataBuilder::Build(inputs, + plan.IsReuseExistingSketch(), + plan.SourceSketchFeatureId, + plan.IsReuseExistingSketch(), + plan.SourceSketchFeatureId); + + if (!data.IsComplete()) + { + m_strLastErrorText = "Extrude commit data could not be built."; + return false; + } + + std::shared_ptr errorSet; + std::shared_ptr incompleteState; + if (m_bEditingExistingFeature && m_pEditedExtrudeFeature) + { + if (!pFeatureManager->CommitFeatureRedefine(*m_pEditedExtrudeFeature, data.Definition ? data.Definition->Clone() : nullptr, data.ReferenceSet, errorSet, incompleteState)) + { + m_strLastErrorText = "Extrude feature redefine commit failed."; + return false; + } + m_idCommittedExtrudeFeature = m_pEditedExtrudeFeature->GetFeatureId(); + } + else + { + FeatureCreateRequestModel request = SolidExtrudeCommitDataBuilder::BuildCreateRequest(data, FeatureLifecycleApplyMode::Commit, FeatureDomain::Part, m_idPreviewFeature); + std::shared_ptr pCreatedFeature = pFeatureManager->CreateFeature(request, errorSet, incompleteState); + if (!pCreatedFeature) + { + m_strLastErrorText = "Extrude feature commit failed."; + return false; + } + + m_idCommittedExtrudeFeature = pCreatedFeature->GetFeatureId(); + } + if (!txScope.Commit(&m_strLastErrorText)) + return false; + + DiscardPreview_(); + ClearHostedSketchDisplay_(); + (void)FlushPendingCommittedDisplay(m_pDocument); + PublishCommittedFeatureSelection_(); + m_stage = ExtrudeWorkflowStage::Finished; + m_bFinished = true; + MarkSuccessful(OperationFinishReason::Enter); + (void)ExitCreationUiToHome_(); + return true; +} + +void SolidExtrudeCreateOperation::RebuildHostedSketchDisplay_() +{ + if (!m_pTransientSketchFeature) + { + (void)EnsureSketchEditSession_(); + } + + if (!m_pTransientSketchFeature) + return; + + + // 关键修复: + // 当前 sketch 曲线先写进了 SketchEditSession 的 working definition + // 但 builder 读的是 transient sketch feature 自己的 definition + // 不把 working definition 回写/克隆过来,正式曲线永远显示为空 + if (m_pSketchEditSession) + { + if (const IFeatureDefinition* const pWorkingDefinition = m_pSketchEditSession->GetWorkingDefinition()) + { + m_pTransientSketchFeature->SetDefinition(pWorkingDefinition->Clone()); + } + } + + const alice::ISketchInteractionController* pInteractionController = nullptr; + if (alice::ISession* const pSession = alice::CoreAppUtil::GetCurrentSession()) + { + if (const auto* const pSectionOp = sdr::SolidSectionEditOperation::FindActive(pSession)) + { + pInteractionController = pSectionOp->GetSketchInteractionController(); + } + } + m_pHostedSketchDisplayRecord = SolidHostedSketchDisplayCoordinator::BuildDisplayRecord(*m_pTransientSketchFeature, m_sketchPlacementContext, m_sketchEditState, pInteractionController); + + if (m_pHostedSketchDisplayRecord) + { + (void)PublishPreviewDisplayRecord(m_pDocument, m_pHostedSketchDisplayRecord); + (void)RequestViewRepaint(m_pDocument); + } +} + +void SolidExtrudeCreateOperation::ClearHostedSketchDisplay_() +{ + if (m_pHostedSketchDisplayRecord && m_pHostedSketchDisplayRecord->GetObjectId().IsValid()) + { + (void)ClearPreviewDisplayRecord(m_pDocument, m_pHostedSketchDisplayRecord->GetObjectId()); + } + m_pHostedSketchDisplayRecord.reset(); + (void)RequestViewRepaint(m_pDocument); +} + +void SolidExtrudeCreateOperation::DiscardPreview_() +{ + SolidExtrudePreviewCoordinator::DiscardPreview(m_pDocument, m_idPreviewFeature, m_pPreviewSeedFeature, m_pPreviewDisplayRecord); + if (m_idPreviewFeature.IsValid()) + { + (void)ClearPreviewDisplayRecord(m_pDocument, m_idPreviewFeature); + } +} + +void SolidExtrudeCreateOperation::PublishCommittedFeatureSelection_() +{ + ISelectionManager* const pSelectionManager = m_pSession ? m_pSession->GetSelectionManagerFw() : nullptr; + if (!pSelectionManager || !m_idCommittedExtrudeFeature.IsValid()) + return; + + pSelectionManager->Clear(); +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeCreateOperation.h b/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeCreateOperation.h new file mode 100644 index 00000000..873efe68 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeCreateOperation.h @@ -0,0 +1,168 @@ +#pragma once +#include "SolidDesignerInteraction.h" + +#include "SolidAuthoringOperationBase.h" +#include "AliceCommandParameter.h" +#include "AliceObjectId.h" +#include "AliceFeaturePrimitives.h" +#include "AliceFeatureAuthoringInputs.h" +#include "AliceIRepresentationRecord.h" +#include "SolidSketchEditState.h" +#include "SolidExtrudeCommitDataBuilder.h" +#include "SolidExtrudeSectionSourceCoordinator.h" +#include "SolidSketchPlacementContext.h" +#include "SolidSketchSectionTypes.h" + +namespace alice +{ + class ISession; + class IDocument; + class IFeature; + class IExtrudeFeature; + class IExtrudeFeatureEditSession; + class ISketchEditSession; + class FeatureObject; + class ExtrudeFeatureObject; +} + +namespace sdr +{ + enum class ExtrudeWorkflowStage : std::uint8_t + { + AwaitSectionSource = 0, + DefiningSectionPlacement, + PickingExistingSketch, + EditingSection, + PreviewingDashboard, + Committing, + Finished, + Cancelled, + Failed + }; + + struct SOLID_DESIGNER_INTERACTION_EXPORT SolidExtrudeDashboardInput + { + double Depth{ 10.0 }; + bool RemoveMaterial{ false }; + bool ReverseDirection{ false }; + bool Symmetric{ false }; + bool PreviewOnly{ false }; + std::string Side1ExtentType{ "Blind" }; + std::string Side2ExtentType{ "None" }; + bool AddTaper{ false }; + double TaperAngle{ 0.0 }; + std::string FeatureName{ "EXTRUDE_1" }; + }; + + struct SOLID_DESIGNER_INTERACTION_EXPORT SolidSketchHighlightState + { + std::string EntityKey; + std::optional SnapPoint; + }; + + class SOLID_DESIGNER_INTERACTION_EXPORT SolidExtrudeCreateOperation final : public SolidAuthoringOperationBase + { + public: + explicit SolidExtrudeCreateOperation(alice::CommandParameter params = {}); + ~SolidExtrudeCreateOperation() override; + + void InitOperation(alice::IUiView* pCurrentView) override; + void OnCancel() override; + void OnChildOperationFinished(const alice::OperationResult& childResult) override; + bool CanConsumeCommand() override; + bool ConsumeCommand(alice::IUiView* pCurrentView, const std::string& commandId, const alice::CommandParameter& params) override; + bool IsFinished() const noexcept override; + + bool BeginDefineInternalSketchPlacement(); + bool BeginReuseExistingSketchSelection(); + bool EditSectionSketch(); + bool UpdateDashboard(const SolidExtrudeDashboardInput& input); + bool ConfirmFeature(); + bool CancelWorkflow(); + bool CanConfirmFeature() const noexcept; + bool CanCancelWorkflow() const noexcept; + bool FlipSectionOrientation(); + bool RestoreSectionOrientation(); + + bool CanDefineInternalSketchPlacement() const noexcept; + bool CanReuseExistingSketchSection() const noexcept; + bool CanEditSectionSketch() const noexcept; + bool CanFlipSectionOrientation() const noexcept; + bool CanRestoreSectionOrientation() const noexcept; + bool IsEditingSketch() const noexcept; + bool IsPreviewingDashboard() const noexcept; + + const SolidSketchSectionInput& GetSectionInput() const noexcept; + const SolidExtrudeDashboardInput& GetDashboardInput() const noexcept; + const SolidSketchEditState& GetSketchEditState() const noexcept; + const SolidSketchHighlightState& GetSketchHighlightState() const noexcept; + const std::string& GetLastErrorText() const noexcept; + + static SolidExtrudeCreateOperation* FindActive(alice::ISession* pSession) noexcept; + + private: + bool ResolveContext_(); + bool RouteWorkflowCommand_(const std::string& commandId); + void PrimeInputsFromParameters_(); + void InitializeSketchPlacementContextFromActiveView_(); + bool TryResolveSketchPlaneFromSelection_(alice::ObjectId& outPlaneId, std::string& outKey, std::string& outRole) const; + bool EnsureSketchEditSession_(); + bool EnsureExtrudeDefinitionEditSession_(); + void SyncSketchEditSessionFromState_(); + bool SyncExtrudeDefinitionEditSessionFromState_(); + void RefreshSectionInputFromSketch_(); + SolidExtrudeDefinitionBuildInputs BuildDefinitionBuildInputs_() const; + bool EnterSketchEditingUi_(); + bool EnterDashboardUi_(); + bool ExitCreationUiToHome_(); + bool RestoreDefaultModelingInteraction_(); + bool StartSectionPlacement_(alice::ObjectId preselectedPlaneId = {}, std::string preselectedPlaneKey = {}, std::string preselectedPlaneRole = {}); + bool StartExistingSketchSelection_(); + bool StartSectionEdit_(); + bool BuildOrRefreshPreview_(); + bool CommitFeatureCreation_(); + void RebuildHostedSketchDisplay_(); + void ClearHostedSketchDisplay_(); + void DiscardPreview_(); + void PublishCommittedFeatureSelection_(); + + private: + alice::CommandParameter m_params; + alice::ISession* m_pSession = nullptr; + alice::IDocument* m_pDocument = nullptr; + ExtrudeWorkflowStage m_stage = ExtrudeWorkflowStage::AwaitSectionSource; + bool m_bUseExistingSketchSection = false; + bool m_bEditingExistingFeature = false; + bool m_bFinished = false; + + alice::ObjectId m_idSectionSourceSketchFeature; + alice::FeatureId m_idPreviewFeature; + alice::FeatureId m_idCommittedExtrudeFeature; + alice::ObjectId m_idCommittedInternalSketchFeature; + alice::ObjectId m_idEditedExtrudeFeature; + alice::ObjectId m_idEditedInternalSketchFeature; + + std::shared_ptr m_pPreviewSeedFeature; + std::shared_ptr m_pEditedExtrudeFeature; + std::shared_ptr m_pEditedInternalSketchFeature; + std::shared_ptr m_pTransientSketchFeature; + std::shared_ptr m_pTransientExtrudeFeature; + + std::unique_ptr m_pExtrudeEditSession; + std::unique_ptr m_pSketchEditSession; + + SolidExtrudeDashboardInput m_dashboardInput; + SolidSketchSectionInput m_sectionInput; + SolidSketchEditState m_sketchEditState; + std::shared_ptr m_pSectionSketchBeforeEditing; + SolidSketchSectionInput m_sectionInputBeforeEditing; + bool m_bHadAcceptedSectionBeforeEditing = false; + SolidSketchPlacementContext m_sketchPlacementContext; + SolidSketchHighlightState m_sketchHighlightState; + + std::shared_ptr m_pPreviewDisplayRecord; + std::shared_ptr m_pCommittedDisplayRecord; + std::shared_ptr m_pHostedSketchDisplayRecord; + std::string m_strLastErrorText; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidExtrudePreviewCoordinator.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidExtrudePreviewCoordinator.cpp new file mode 100644 index 00000000..88a690f7 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidExtrudePreviewCoordinator.cpp @@ -0,0 +1,120 @@ +#include "SolidExtrudePreviewCoordinator.h" +#include "SolidExtrudeCommitDataBuilder.h" +#include "AliceIDocument.h" +#include "AliceIDocumentFeatureManager.h" +#include "AliceFeatureLifecycleModels.h" +#include "AliceIRepresentationRecord.h" +#include "AliceRepresentationProjectionService.h" +#include "AliceIFeature.h" + +#include + +using namespace sdr; +using namespace alice; + +namespace +{ + static std::string BuildFeatureErrorText_(const char* pFallback, + const std::shared_ptr& errorSet, + const std::shared_ptr& incompleteState) + { + std::ostringstream stream; + stream << (pFallback ? pFallback : "Feature evaluation failed."); + + if (errorSet && errorSet->GetErrorCount() > 0u) + { + const IElementError* const pPrimaryError = errorSet->GetError(0u); + if (pPrimaryError && pPrimaryError->GetMessage() && pPrimaryError->GetMessage()[0] != '\0') + { + stream << " Details: " << pPrimaryError->GetMessage(); + } + if (pPrimaryError && pPrimaryError->GetSuggestedFix() && pPrimaryError->GetSuggestedFix()[0] != '\0') + { + stream << " Fix: " << pPrimaryError->GetSuggestedFix(); + } + } + + if (incompleteState) + { + const char* const pSectionState = incompleteState->GetUnresolvedSectionState(); + if (pSectionState && pSectionState[0] != '\0') + { + stream << " State: " << pSectionState; + } + } + return stream.str(); + } +} + +bool SolidExtrudePreviewCoordinator::RebuildPreview(IDocument& document, + const SolidExtrudeCommitData& commitData, + FeatureId& ioPreviewFeatureId, + std::shared_ptr& ioPreviewSeedFeature, + std::shared_ptr& ioPreviewDisplayRecord, + std::string& ioErrorText) +{ + IDocumentFeatureManager* const pFeatureManager = document.GetDocumentFeatureManagerFw(); + if (!pFeatureManager) + { + ioErrorText = "Document feature manager is not available for preview evaluation."; + return false; + } + + std::shared_ptr errorSet; + std::shared_ptr incompleteState; + + if (!ioPreviewSeedFeature) + { + FeatureCreateRequestModel request = SolidExtrudeCommitDataBuilder::BuildCreateRequest(commitData, + FeatureLifecycleApplyMode::PreviewOnly, + FeatureDomain::Part); + ioPreviewSeedFeature = pFeatureManager->CreateFeature(request, errorSet, incompleteState); + if (!ioPreviewSeedFeature) + { + ioErrorText = BuildFeatureErrorText_("Extrude preview creation failed.", errorSet, incompleteState); + return false; + } + ioPreviewFeatureId = ioPreviewSeedFeature->GetFeatureId(); + } + else if (!pFeatureManager->PreviewFeatureRedefine(*ioPreviewSeedFeature, commitData.Definition.get(), commitData.ReferenceSet, errorSet, incompleteState)) + { + ioErrorText = BuildFeatureErrorText_("Extrude preview update failed.", errorSet, incompleteState); + return false; + } + + const IFeature* const pPreviewFeature = pFeatureManager->FindPreviewFeature(ioPreviewFeatureId); + if (!pPreviewFeature) + { + ioErrorText = "Preview feature object is not available after preview evaluation."; + return false; + } + + rep::RepresentationProjectionService projectionService; + ioPreviewDisplayRecord = projectionService.ProjectDocumentObjectToRecord(*const_cast(pPreviewFeature)); + if (!ioPreviewDisplayRecord) + { + ioErrorText = "Preview display-model record could not be built from the preview feature."; + return false; + } + return true; +} + +void SolidExtrudePreviewCoordinator::DiscardPreview(IDocument* pDocument, + FeatureId& ioPreviewFeatureId, + std::shared_ptr& ioPreviewSeedFeature, + std::shared_ptr& ioPreviewDisplayRecord) +{ + if (pDocument) + { + if (IDocumentFeatureManager* const pFeatureManager = pDocument->GetDocumentFeatureManagerFw()) + { + if (ioPreviewFeatureId.IsValid()) + { + pFeatureManager->DiscardFeaturePreview(ioPreviewFeatureId); + } + } + } + ioPreviewFeatureId = {}; + ioPreviewSeedFeature.reset(); + ioPreviewDisplayRecord.reset(); +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidExtrudePreviewCoordinator.h b/Designer/Interaction/SolidDesignerInteraction/SolidExtrudePreviewCoordinator.h new file mode 100644 index 00000000..43433b3b --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidExtrudePreviewCoordinator.h @@ -0,0 +1,32 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "AliceFeaturePrimitives.h" + +namespace alice +{ + class IDocument; + class IFeature; + class IFeatureDefinition; + class IFeatureReferenceSet; + namespace rep { class IRepresentationRecord; } +} + +namespace sdr +{ + struct SolidExtrudeCommitData; + class SOLID_DESIGNER_INTERACTION_EXPORT SolidExtrudePreviewCoordinator final + { + public: + static bool RebuildPreview(alice::IDocument& document, + const SolidExtrudeCommitData& commitData, + alice::FeatureId& ioPreviewFeatureId, + std::shared_ptr& ioPreviewSeedFeature, + std::shared_ptr& ioPreviewDisplayRecord, + std::string& ioErrorText); + + static void DiscardPreview(alice::IDocument* pDocument, + alice::FeatureId& ioPreviewFeatureId, + std::shared_ptr& ioPreviewSeedFeature, + std::shared_ptr& ioPreviewDisplayRecord); + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeSectionSourceCoordinator.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeSectionSourceCoordinator.cpp new file mode 100644 index 00000000..981cea95 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeSectionSourceCoordinator.cpp @@ -0,0 +1,23 @@ +#include "SolidExtrudeSectionSourceCoordinator.h" + +using namespace sdr; +using namespace alice; + +SolidExtrudeSectionSourcePlan SolidExtrudeSectionSourceCoordinator::ResolveForPreview(const SolidExtrudeSectionSourceState& state) noexcept +{ + SolidExtrudeSectionSourcePlan plan; + plan.UseExistingSketchSection = state.UseExistingSketchSection; + if (state.UseExistingSketchSection) + { + plan.SourceSketchFeatureId = state.SelectedSourceSketchFeatureId; + return plan; + } + plan.SourceSketchFeatureId = state.CommittedInternalSketchFeatureId; + plan.RequiresInternalSketchCommit = !plan.SourceSketchFeatureId.IsValid(); + return plan; +} + +SolidExtrudeSectionSourcePlan SolidExtrudeSectionSourceCoordinator::ResolveForCommit(const SolidExtrudeSectionSourceState& state) noexcept +{ + return ResolveForPreview(state); +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeSectionSourceCoordinator.h b/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeSectionSourceCoordinator.h new file mode 100644 index 00000000..c35add0d --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidExtrudeSectionSourceCoordinator.h @@ -0,0 +1,31 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "AliceObjectId.h" + +namespace sdr +{ + struct SOLID_DESIGNER_INTERACTION_EXPORT SolidExtrudeSectionSourcePlan + { + bool UseExistingSketchSection = false; + bool RequiresInternalSketchCommit = false; + alice::ObjectId SourceSketchFeatureId{}; + + bool IsReuseExistingSketch() const noexcept { return UseExistingSketchSection; } + bool HasResolvedSourceSketch() const noexcept { return SourceSketchFeatureId.IsValid(); } + }; + + struct SOLID_DESIGNER_INTERACTION_EXPORT SolidExtrudeSectionSourceState + { + bool EditingExistingFeature = false; + bool UseExistingSketchSection = false; + alice::ObjectId SelectedSourceSketchFeatureId{}; + alice::ObjectId CommittedInternalSketchFeatureId{}; + }; + + class SOLID_DESIGNER_INTERACTION_EXPORT SolidExtrudeSectionSourceCoordinator final + { + public: + static SolidExtrudeSectionSourcePlan ResolveForPreview(const SolidExtrudeSectionSourceState& state) noexcept; + static SolidExtrudeSectionSourcePlan ResolveForCommit(const SolidExtrudeSectionSourceState& state) noexcept; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidFeatureAuthoringTransactionScope.h b/Designer/Interaction/SolidDesignerInteraction/SolidFeatureAuthoringTransactionScope.h new file mode 100644 index 00000000..1930a04e --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidFeatureAuthoringTransactionScope.h @@ -0,0 +1,88 @@ +#pragma once + +#include "AliceIDocument.h" +#include "AliceITransactionManager.h" +#include "AliceTransactionTypes.h" + +#include +#include + +namespace sdr +{ + class SolidFeatureAuthoringTransactionScope final + { + public: + SolidFeatureAuthoringTransactionScope(alice::IDocument* pInDocument, + std::string_view InDescription, + alice::TransactionPolicy InPolicy = alice::TransactionPolicy::UndoRedo) + : m_pDocument(pInDocument) + , m_pTransactionManager(pInDocument ? pInDocument->GetTransactionManagerFw() : nullptr) + , m_strDescription(InDescription) + { + if (!m_pDocument) + { + m_strLastError = "Document is null; transaction cannot be started."; + return; + } + if (!m_pTransactionManager) + { + m_strLastError = "Transaction manager is not available on the active document."; + return; + } + if (m_pTransactionManager->HasActiveTransaction()) + { + m_strLastError = "Another user transaction is already active; nested feature authoring transactions are not allowed."; + return; + } + if (!m_pTransactionManager->BeginUserTransaction(InDescription, InPolicy)) + { + m_strLastError = "Failed to begin the feature authoring transaction."; + return; + } + m_bActive = true; + } + + ~SolidFeatureAuthoringTransactionScope() + { + if (m_bActive && m_pTransactionManager) + { + (void)m_pTransactionManager->RollbackUserTransaction(); + } + } + + bool IsActive() const noexcept { return m_bActive; } + const std::string& GetLastError() const noexcept { return m_strLastError; } + + bool Commit(std::string* pOutError = nullptr) + { + if (!m_bActive) + { + if (pOutError) + { + *pOutError = m_strLastError.empty() + ? std::string("Feature authoring transaction '") + m_strDescription + "' is not active." + : m_strLastError; + } + return false; + } + if (!m_pTransactionManager || !m_pTransactionManager->CommitUserTransaction()) + { + m_strLastError = std::string("Failed to commit feature authoring transaction '") + m_strDescription + "'."; + if (pOutError) + { + *pOutError = m_strLastError; + } + return false; + } + m_bActive = false; + return true; + } + + private: + alice::IDocument* m_pDocument = nullptr; + alice::ITransactionManager* m_pTransactionManager = nullptr; + std::string m_strDescription; + std::string m_strLastError; + bool m_bActive = false; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidFeatureAuthoringUiContext.h b/Designer/Interaction/SolidDesignerInteraction/SolidFeatureAuthoringUiContext.h new file mode 100644 index 00000000..21853a1f --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidFeatureAuthoringUiContext.h @@ -0,0 +1,67 @@ +#pragma once + +#include "AliceIDocument.h" +#include "AliceIMainWindow.h" +#include "AliceIUiApplication.h" +#include "AliceIUiApplicationFactory.h" +#include "AliceIWorkBenchManager.h" + +#include + +namespace sdr +{ + struct SolidFeatureAuthoringUiProfile final + { + std::string_view ModelingWorkbenchId{ "workbench.part" }; + std::string_view SketchWorkbenchId{ "workbench.sketch" }; + std::string_view DashboardUiContextId{}; + std::string_view SketchUiContextId{}; + std::string_view RestoreUiContextId{ "workbench.part" }; + }; + + inline constexpr SolidFeatureAuthoringUiProfile kExtrudeAuthoringUiProfile{ "workbench.part", "workbench.sketch", "feature.extrude.create", "feature.extrude.sketch", "workbench.part" }; + inline constexpr SolidFeatureAuthoringUiProfile kRevolveAuthoringUiProfile{ "workbench.part", "workbench.sketch", "feature.revolve.create", "feature.revolve.sketch", "workbench.part" }; + inline constexpr SolidFeatureAuthoringUiProfile kSweepAuthoringUiProfile{ "workbench.part", "workbench.sketch", "feature.sweep.create", "feature.sweep.sketch", "workbench.part" }; + inline constexpr SolidFeatureAuthoringUiProfile kHoleAuthoringUiProfile{ "workbench.part", "workbench.part", "feature.hole.create", "", "workbench.part" }; + + inline alice::IMainWindow* ResolveSolidAuthoringMainWindow() + { + alice::IUiApplicationFactory* const pFactory = alice::IUiApplicationFactory::Get(); + if (!pFactory) + { + return nullptr; + } + alice::IUiApplication* const pUiApp = pFactory->GetUiApplication(); + if (!pUiApp) + { + return nullptr; + } + return pUiApp->GetMainWindowFw(); + } + + inline bool ActivateSolidAuthoringWorkbench(std::string_view InWorkbenchId, alice::IDocument* pInDocument) + { + alice::IMainWindow* const pMainWindow = ResolveSolidAuthoringMainWindow(); + if (!pMainWindow) + { + return false; + } + alice::IWorkBenchManager* const pWorkbenchManager = pMainWindow->GetWorkbenchManager(); + if (!pWorkbenchManager) + { + return false; + } + return pWorkbenchManager->ActivateWorkBench(std::string(InWorkbenchId), pInDocument); + } + + inline bool ApplySolidAuthoringUiContext(std::string_view InUiContextId) + { + alice::IMainWindow* const pMainWindow = ResolveSolidAuthoringMainWindow(); + if (!pMainWindow) + { + return false; + } + pMainWindow->ApplyWorkbenchForCommandUi(std::string(InUiContextId)); + return true; + } +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidHoleAuthoringPayloadBuilder.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidHoleAuthoringPayloadBuilder.cpp new file mode 100644 index 00000000..a08eebac --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidHoleAuthoringPayloadBuilder.cpp @@ -0,0 +1,43 @@ +#include "SolidHoleAuthoringPayloadBuilder.h" + +#include "AliceFeatureLifecycleModels.h" +#include "AliceDiagnosticMacro.h" +#include "AliceIFeatureDefinition.h" +#include "AliceIFeatureReferenceSet.h" + +using namespace sdr; +using namespace alice; + +bool SolidHoleAuthoringPayload::IsComplete() const noexcept +{ + return Definition != nullptr && ReferenceSet != nullptr; +} + +SolidHoleAuthoringPayload SolidHoleAuthoringPayloadBuilder::Build(std::shared_ptr definition, + std::shared_ptr referenceSet) +{ + SolidHoleAuthoringPayload payload; + payload.Definition = std::move(definition); + payload.ReferenceSet = std::move(referenceSet); + return payload; +} + +FeatureCreateRequestModel SolidHoleAuthoringPayloadBuilder::BuildCreateRequest(const SolidHoleAuthoringPayload& payload, + FeatureLifecycleApplyMode applyMode, + FeatureDomain targetDomain, + FeatureId targetFeatureId, + bool allowIncompleteCommit) +{ + FeatureCreateRequestModel request; + DIAG_RETURN_IF_FALSE(payload.Definition, request, "payload.Definition cannot be null", "hananiah", "2025.11.02"); + request.SetTargetDomain(targetDomain); + request.SetApplyMode(applyMode); + request.SetDefinitionCandidate(payload.Definition->Clone()); + request.SetReferenceSetCandidate(payload.ReferenceSet); + request.SetAllowIncompleteCommit(allowIncompleteCommit); + if (targetFeatureId.IsValid()) + { + request.SetTargetFeatureId(targetFeatureId); + } + return request; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidHoleAuthoringPayloadBuilder.h b/Designer/Interaction/SolidDesignerInteraction/SolidHoleAuthoringPayloadBuilder.h new file mode 100644 index 00000000..bfd4aaa2 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidHoleAuthoringPayloadBuilder.h @@ -0,0 +1,37 @@ +#pragma once +#include "SolidDesignerInteraction.h" + +#include "AliceFeaturePrimitives.h" + +#include + +namespace alice +{ + class IFeatureDefinition; + class IFeatureReferenceSet; + class FeatureCreateRequestModel; +} + +namespace sdr +{ + struct SOLID_DESIGNER_INTERACTION_EXPORT SolidHoleAuthoringPayload final + { + std::shared_ptr Definition; + std::shared_ptr ReferenceSet; + + [[nodiscard]] bool IsComplete() const noexcept; + }; + + class SOLID_DESIGNER_INTERACTION_EXPORT SolidHoleAuthoringPayloadBuilder final + { + public: + static SolidHoleAuthoringPayload Build(std::shared_ptr definition, + std::shared_ptr referenceSet); + + static alice::FeatureCreateRequestModel BuildCreateRequest(const SolidHoleAuthoringPayload& payload, + alice::FeatureLifecycleApplyMode applyMode, + alice::FeatureDomain targetDomain, + alice::FeatureId targetFeatureId = {}, + bool allowIncompleteCommit = false); + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidHostedSketchCommitCoordinator.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidHostedSketchCommitCoordinator.cpp new file mode 100644 index 00000000..559febe4 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidHostedSketchCommitCoordinator.cpp @@ -0,0 +1,82 @@ +#include "SolidHostedSketchCommitCoordinator.h" + +#include "AliceFeatureLifecycleModels.h" +#include "AliceIDocument.h" +#include "AliceIDocumentFeatureManager.h" +#include "AliceIFeature.h" +#include "AliceIFeatureDefinition.h" +#include "AliceIFeatureElementTree.h" +#include "AliceIFeatureReferenceSet.h" +#include "AliceISketchDefinitionTreeCodecHelper.h" +#include "AliceISketch.h" +#include "AliceSketchSectionInputBuilder.h" +#include "AliceExtrudeReferenceSetAssembler.h" + +using namespace sdr; +using namespace alice; + +std::shared_ptr SolidHostedSketchCommitCoordinator::CommitInternalSketch(IDocument& document, + const SolidExtrudeDefinitionBuildInputs& inputs, + std::string* outError) +{ + IDocumentFeatureManager* const featureManager = document.GetDocumentFeatureManagerFw(); + if (!featureManager) + { + if (outError) *outError = "Document feature manager is not available for internal sketch commit."; + return nullptr; + } + + auto definition = alice::SketchSectionInputBuilder::BuildInternalSketchDefinition(inputs); + auto referenceSet = alice::ExtrudeReferenceSetAssembler::BuildInternalSketchReferenceSet(); + if (!definition || !referenceSet) + { + if (outError) *outError = "Internal sketch definition could not be constructed."; + return nullptr; + } + + std::shared_ptr errorSet; + std::shared_ptr incompleteState; + FeatureCreateRequestModel request; + request.SetTargetDomain(FeatureDomain::Sketch); + request.SetApplyMode(FeatureLifecycleApplyMode::Commit); + request.SetDefinitionCandidate(definition->Clone()); + request.SetReferenceSetCandidate(referenceSet); + return featureManager->CreateFeature(request, errorSet, incompleteState); +} + +bool SolidHostedSketchCommitCoordinator::RestoreSketchFeature(IFeature& feature, + SolidSketchEditState& ioSketchState, + SolidSketchSectionInput& ioSectionInput, + std::string* outError) +{ + const IFeatureDefinition* const definition = feature.GetDefinition(); + const IFeatureElementTree* const tree = definition ? definition->GetElementTree() : nullptr; + if (!tree) + { + if (outError) *outError = "Internal sketch feature definition is missing an element tree."; + return false; + } + + SketchStructuredSectionSnapshot recordData; + std::shared_ptr restoredSketch; + ISketchDefinitionTreeCodecHelper* pCodecHelper = ISketchDefinitionTreeCodecHelper::Get(); + if (!pCodecHelper || !pCodecHelper->ReadStructuredSketchDefinition(*tree, restoredSketch, recordData)) + { + if (outError) *outError = "Internal sketch feature does not contain a structured semantic sketch payload."; + return false; + } + + ioSketchState.SetSketch(restoredSketch); + ioSectionInput.SketchPlaneReferenceId = recordData.SketchPlaneReferenceId; + ioSectionInput.PlacementReferenceId = recordData.PlacementReferenceId; + ioSectionInput.SketchPlaneGraphicToken = recordData.SketchPlaneGraphicToken; + ioSectionInput.SketchPlaneGraphicRole = recordData.SketchPlaneGraphicRole; + ioSectionInput.PlacementReferenceGraphicToken = recordData.PlacementReferenceGraphicToken; + ioSectionInput.PlacementReferenceGraphicRole = recordData.PlacementReferenceGraphicRole; + ioSectionInput.ClosedProfileCount = recordData.ClosedProfileCount; + ioSectionInput.OpenChainCount = recordData.OpenChainCount; + ioSectionInput.HasSelfIntersection = recordData.HasSelfIntersection; + ioSectionInput.HasDanglingGeometry = recordData.HasDanglingGeometry; + ioSectionInput.HasZeroAreaProfile = recordData.HasZeroAreaProfile; + return true; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidHostedSketchCommitCoordinator.h b/Designer/Interaction/SolidDesignerInteraction/SolidHostedSketchCommitCoordinator.h new file mode 100644 index 00000000..67f57c89 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidHostedSketchCommitCoordinator.h @@ -0,0 +1,28 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "AliceFeatureAuthoringInputs.h" +#include "SolidSketchEditState.h" +#include "SolidSketchSectionTypes.h" + +namespace alice +{ + class IDocument; + class IFeature; +} + +namespace sdr +{ + using SolidExtrudeDefinitionBuildInputs = alice::ExtrudeDefinitionBuildInputs; + + class SOLID_DESIGNER_INTERACTION_EXPORT SolidHostedSketchCommitCoordinator final + { + public: + static std::shared_ptr CommitInternalSketch(alice::IDocument& document, + const SolidExtrudeDefinitionBuildInputs& inputs, + std::string* outError); + static bool RestoreSketchFeature(alice::IFeature& feature, + SolidSketchEditState& ioSketchState, + SolidSketchSectionInput& ioSectionInput, + std::string* outError); + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidHostedSketchDisplayCoordinator.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidHostedSketchDisplayCoordinator.cpp new file mode 100644 index 00000000..2cee25d5 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidHostedSketchDisplayCoordinator.cpp @@ -0,0 +1,280 @@ +#include "SolidHostedSketchDisplayCoordinator.h" +#include "SolidSketchRepresentationProjection.h" + +#include "AliceConstants.h" +#include "AliceFeatureObject.h" +#include "AliceRepresentationRecord.h" +#include "AliceRepresentationGroupNode.h" +#include "AliceCurveRepresentationNode.h" +#include "AliceVector3d.h" +#include "AliceSemanticRoleId.h" +#include "AliceISketchInteractionController.h" + +#include +#include +#include + +using namespace sdr; +using namespace alice; + +namespace +{ + static alice::Vector3d MakeVec3(double x, double y, double z) + { + return alice::Vector3d(x, y, z); + } + + static alice::Vector3d NormalizeOrFallback(alice::Vector3d value, const alice::Vector3d& fallback) + { + if (value.Normalize() <= 1.0e-12) + { + return fallback; + } + return value; + } + + static bool ResolvePlacementFrame(const SolidSketchPlacementContext& context, + alice::Vector3d& outOrigin, + alice::Vector3d& outXAxis, + alice::Vector3d& outYAxis) + { + outOrigin = context.HasPlaneAnchor + ? MakeVec3(context.PlaneAnchorX, context.PlaneAnchorY, context.PlaneAnchorZ) + : MakeVec3(context.CameraTargetX, context.CameraTargetY, context.CameraTargetZ); + + if (context.HasPlaneFrame) + { + outXAxis = NormalizeOrFallback(MakeVec3(context.PlaneXAxisX, context.PlaneXAxisY, context.PlaneXAxisZ), alice::Vector3d::UnitX); + outYAxis = NormalizeOrFallback(MakeVec3(context.PlaneYAxisX, context.PlaneYAxisY, context.PlaneYAxisZ), alice::Vector3d::UnitY); + return true; + } + + const alice::Vector3d eye = MakeVec3(context.CameraEyeX, context.CameraEyeY, context.CameraEyeZ); + const alice::Vector3d target = MakeVec3(context.CameraTargetX, context.CameraTargetY, context.CameraTargetZ); + alice::Vector3d up = NormalizeOrFallback(MakeVec3(context.CameraUpX, context.CameraUpY, context.CameraUpZ), alice::Vector3d::UnitY); + const alice::Vector3d forward = NormalizeOrFallback(target - eye, alice::Vector3d::NegaUnitZ); + outXAxis = NormalizeOrFallback(forward.Cross(up), alice::Vector3d::UnitX); + outYAxis = NormalizeOrFallback(outXAxis.Cross(forward), up); + return true; + } + + static alice::Vector3d MapSketchPointToWorld_(const SolidSketchPlacementContext& ctx, const alice::SketchPoint2d& point) + { + const alice::Vector3d eye = MakeVec3(ctx.CameraEyeX, ctx.CameraEyeY, ctx.CameraEyeZ); + const alice::Vector3d target = MakeVec3(ctx.CameraTargetX, ctx.CameraTargetY, ctx.CameraTargetZ); + alice::Vector3d up = NormalizeOrFallback(MakeVec3(ctx.CameraUpX, ctx.CameraUpY, ctx.CameraUpZ), alice::Vector3d::UnitY); + const alice::Vector3d forward = NormalizeOrFallback(target - eye, alice::Vector3d::NegaUnitZ); + alice::Vector3d right = NormalizeOrFallback(forward.Cross(up), alice::Vector3d::UnitX); + up = NormalizeOrFallback(right.Cross(forward), up); + + const alice::Vector3d anchor = ctx.HasPlaneAnchor + ? MakeVec3(ctx.PlaneAnchorX, ctx.PlaneAnchorY, ctx.PlaneAnchorZ) + : target; + const alice::Vector3d planeXAxis = ctx.HasPlaneFrame + ? NormalizeOrFallback(MakeVec3(ctx.PlaneXAxisX, ctx.PlaneXAxisY, ctx.PlaneXAxisZ), right) + : right; + const alice::Vector3d planeYAxis = ctx.HasPlaneFrame + ? NormalizeOrFallback(MakeVec3(ctx.PlaneYAxisX, ctx.PlaneYAxisY, ctx.PlaneYAxisZ), up) + : up; + + const double x = ctx.FlipHorizontal ? -point.X() : point.X(); + return anchor + planeXAxis * x + planeYAxis * point.Y(); + } + + static std::vector ScaleCoords(const std::vector& points, int axis) + { + std::vector values; + values.reserve(points.size()); + for (const alice::Vector3d& point : points) + { + const double coord = axis == 0 ? point.X() : (axis == 1 ? point.Y() : point.Z()); + values.push_back(static_cast(std::llround(coord * 1000.0))); + } + return values; + } + + static std::uint64_t HashSketchNodeId_(alice::ObjectId idObject, const std::string& token) + { + const std::uint64_t seed = static_cast(idObject.RawValue()); + const std::uint64_t hash = static_cast(std::hash{}(token)); + return seed ^ (hash + 0x9e3779b97f4a7c15ULL + (seed << 6u) + (seed >> 2u)); + } + + static double ResolveGripHalfSize(const SolidSketchPlacementContext& context, bool highlighted) + { + const double pixels = highlighted ? 6.0 : 4.0; + const double worldPerPixel = std::max(context.ScreenToModelScale, 1.0e-6); + return std::max(worldPerPixel * pixels, worldPerPixel * 2.0); + } + + static std::shared_ptr BuildPolylineNode(alice::ObjectId idObject, + const std::string& name, + const std::string& role, + const std::string& token, + const std::vector& points) + { + if (points.size() < 2u) + { + return {}; + } + + auto pNode = std::make_shared(); + pNode->SetPersistentNodeId(HashSketchNodeId_(idObject, token)); + pNode->SetOwnerObjectId(idObject); + pNode->SetDebugName(name); + pNode->SetSemanticRole(role); + pNode->SetCurveBindingToken(token); + pNode->SetCurveStyleTokenStorage(role); + pNode->SetSampledPolylineXs(ScaleCoords(points, 0)); + pNode->SetSampledPolylineYs(ScaleCoords(points, 1)); + pNode->SetSampledPolylineZs(ScaleCoords(points, 2)); + return pNode; + } +} + +std::shared_ptr SolidHostedSketchDisplayCoordinator::BuildDisplayRecord(const alice::FeatureObject& ownerFeature, + const SolidSketchPlacementContext& placementContext, + const SolidSketchEditState& sketchEditState, + const alice::ISketchInteractionController* pSketchInteractionController) +{ + const alice::ObjectId idObject = ownerFeature.GetFeatureId(); + if (!idObject.IsValid()) + { + return {}; + } + + auto pRecord = std::make_shared(); + pRecord->SetObjectId(idObject); + pRecord->SetDocumentObject(const_cast(&ownerFeature)); + pRecord->SetDocumentObjectTypeName("sketch.internal.preview"); + pRecord->SetDebugLabel("extrude.hosted-sketch.preview"); + + auto pRoot = std::make_shared(); + pRoot->SetPersistentNodeId(HashSketchNodeId_(idObject, "extrude.hosted-sketch.root")); + pRoot->SetOwnerObjectId(idObject); + pRoot->SetDebugName("extrude.hosted-sketch.root"); + pRoot->SetSemanticRole("sketch.root"); + pRoot->SetGroupTag("sketch.preview"); + pRoot->SetIsCadNode(true); + + SolidSketchRepresentationProjection::AppendProjectedSketchCurves(*pRoot, idObject, placementContext, sketchEditState.GetSketch()); + + auto appendPolyline = [&](const std::string& token, const std::string& role, const std::vector& points) + { + if (points.size() < 2u) return; + if (auto pNode = BuildPolylineNode(idObject, token, role, token, points)) + { + pRoot->AppendChild(pNode); + } + }; + + auto appendSampledCurve = [&](const std::string& token, const std::string& role, auto evaluator) + { + std::vector points; + constexpr int kSegments = 48; + points.reserve(static_cast(kSegments) + 1u); + for (int i = 0; i <= kSegments; ++i) + { + const double t = static_cast(i) / static_cast(kSegments); + points.push_back(MapSketchPointToWorld_(placementContext, evaluator(t))); + } + appendPolyline(token, role, points); + }; + + const SolidSketchLineDraft& lineDraft = sketchEditState.GetLineDraft(); + if (lineDraft.Active) + { + const double dx = lineDraft.Current.X() - lineDraft.Start.X(); + const double dy = lineDraft.Current.Y() - lineDraft.Start.Y(); + if ((dx * dx + dy * dy) > 1.0e-18) + { + appendPolyline("draft.line", "sketch.draft.curve", + { MapSketchPointToWorld_(placementContext, lineDraft.Start), + MapSketchPointToWorld_(placementContext, lineDraft.Current) }); + } + } + + const SolidSketchCircleDraft& circleDraft = sketchEditState.GetCircleDraft(); + if (circleDraft.Active) + { + const double dx = circleDraft.Current.X() - circleDraft.Center.X(); + const double dy = circleDraft.Current.Y() - circleDraft.Center.Y(); + const double radius = std::sqrt(dx * dx + dy * dy); + if (radius > 1.0e-9) + { + appendSampledCurve("draft.circle", "sketch.draft.curve", + [&](double t) + { + const double angle = t * 2.0 * alice::kPi; + return alice::SketchPoint2d{ circleDraft.Center.X() + std::cos(angle) * radius, + circleDraft.Center.Y() + std::sin(angle) * radius }; + }); + } + } + + const SolidSketchRectangleDraft& rectangleDraft = sketchEditState.GetRectangleDraft(); + if (rectangleDraft.Active) + { + const alice::SketchPoint2d p0 = rectangleDraft.Corner0; + const alice::SketchPoint2d p1{ rectangleDraft.Corner1.X(), rectangleDraft.Corner0.Y() }; + const alice::SketchPoint2d p2 = rectangleDraft.Corner1; + const alice::SketchPoint2d p3{ rectangleDraft.Corner0.X(), rectangleDraft.Corner1.Y() }; + appendPolyline("draft.rectangle", "sketch.draft.curve", + { MapSketchPointToWorld_(placementContext, p0), + MapSketchPointToWorld_(placementContext, p1), + MapSketchPointToWorld_(placementContext, p2), + MapSketchPointToWorld_(placementContext, p3), + MapSketchPointToWorld_(placementContext, p0) }); + } + + const SolidSketchEllipseDraft& ellipseDraft = sketchEditState.GetEllipseDraft(); + if (ellipseDraft.Active) + { + const double radiusX = std::abs(ellipseDraft.Current.X() - ellipseDraft.Center.X()); + const double radiusY = std::abs(ellipseDraft.Current.Y() - ellipseDraft.Center.Y()); + if (radiusX > 1.0e-9 && radiusY > 1.0e-9) + { + appendSampledCurve("draft.ellipse", "sketch.draft.curve", + [&](double t) + { + const double angle = t * 2.0 * alice::kPi; + return alice::SketchPoint2d{ ellipseDraft.Center.X() + std::cos(angle) * radiusX, + ellipseDraft.Center.Y() + std::sin(angle) * radiusY }; + }); + } + } + + if (pSketchInteractionController != nullptr) + { + alice::Vector3d gripOrigin; + alice::Vector3d gripXAxis; + alice::Vector3d gripYAxis; + const bool hasGripFrame = ResolvePlacementFrame(placementContext, gripOrigin, gripXAxis, gripYAxis); + const alice::SketchGripDisplayPolicy gripPolicy = sketchEditState.HasActiveDraft() + ? alice::SketchGripDisplayPolicy::HighlightOnly + : alice::SketchGripDisplayPolicy::PersistentAndHighlight; + + std::vector gripPoints; + pSketchInteractionController->CollectGripPoints(gripPoints, gripPolicy); + for (std::size_t index = 0; index < gripPoints.size(); ++index) + { + const auto& grip = gripPoints[index]; + const alice::Vector3d center = MapSketchPointToWorld_(placementContext, grip.Point); + const double halfSize = ResolveGripHalfSize(placementContext, grip.Highlighted); + const alice::Vector3d dx = hasGripFrame ? (gripXAxis * halfSize) : alice::Vector3d(halfSize, 0.0, 0.0); + const alice::Vector3d dy = hasGripFrame ? (gripYAxis * halfSize) : alice::Vector3d(0.0, halfSize, 0.0); + const std::string token = grip.Token.empty() ? (std::string("grip.") + std::to_string(index)) : grip.Token; + const std::string role = std::string(alice::ToStableSemanticRoleText(grip.Highlighted ? alice::SemanticRoleId::SketchSnapPoint + : alice::SemanticRoleId::SketchControlPoint)); + appendPolyline(token + ".box", role, + { center - dx - dy, + center + dx - dy, + center + dx + dy, + center - dx + dy, + center - dx - dy }); + } + } + + pRecord->AppendRepresentationRoot(pRoot); + return pRecord; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidHostedSketchDisplayCoordinator.h b/Designer/Interaction/SolidDesignerInteraction/SolidHostedSketchDisplayCoordinator.h new file mode 100644 index 00000000..5d526b34 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidHostedSketchDisplayCoordinator.h @@ -0,0 +1,18 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "SolidSketchPlacementContext.h" +#include "SolidSketchEditState.h" + +namespace alice { class FeatureObject; class ISketchInteractionController; namespace rep { class IRepresentationRecord; } } + +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidHostedSketchDisplayCoordinator final + { + public: + static std::shared_ptr BuildDisplayRecord(const alice::FeatureObject& ownerFeature, + const SolidSketchPlacementContext& placementContext, + const SolidSketchEditState& sketchEditState, + const alice::ISketchInteractionController* pSketchInteractionController = nullptr); + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidOperationInputAdapter.h b/Designer/Interaction/SolidDesignerInteraction/SolidOperationInputAdapter.h new file mode 100644 index 00000000..c1dd0803 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidOperationInputAdapter.h @@ -0,0 +1,33 @@ +#pragma once + +#include "AliceOperationInputSnapshot.h" + +#include +#include + +namespace sdr::detail +{ + inline bool TryGetCurrentScreenPoint(std::int32_t& x, + std::int32_t& y, + std::uint32_t* pButtons = nullptr, + std::uint32_t* pModifiers = nullptr) noexcept + { + const std::optional snapshot = alice::OperationInputSnapshot::GetCurrentPointer(); + if (!snapshot.has_value()) + { + return false; + } + + x = static_cast(snapshot->X); + y = static_cast(snapshot->Y); + if (pButtons != nullptr) + { + *pButtons = snapshot->Buttons; + } + if (pModifiers != nullptr) + { + *pModifiers = snapshot->Modifiers; + } + return true; + } +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidPickFilters.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidPickFilters.cpp new file mode 100644 index 00000000..b10cbaa2 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidPickFilters.cpp @@ -0,0 +1,214 @@ +#include "SolidPickFilters.h" +#include "AliceIPickingManager.h" +#include "AliceSemanticRoleKind.h" +#include + +using namespace sdr; +using namespace alice; + +namespace +{ + static bool ContainsKind_(const std::vector& kinds, PickHitKind kind) + { + return std::find(kinds.begin(), kinds.end(), kind) != kinds.end(); + } +} + +SolidSemanticPickFilter::SolidSemanticPickFilter(SolidPickIntent intent) +{ + Reset(intent); +} + +SolidSemanticPickFilter::SolidSemanticPickFilter(std::vector allowedKinds, std::vector preferredSemanticRoleKinds, bool allowFallbackForUnnamedRoles) +{ + Reset(std::move(allowedKinds), std::move(preferredSemanticRoleKinds), allowFallbackForUnnamedRoles); +} + +void SolidSemanticPickFilter::Reset(SolidPickIntent intent) +{ + Reset(AllowedKindsForIntent_(intent), RoleKindsForIntent_(intent), intent == SolidPickIntent::DefaultModeling); +} + +void SolidSemanticPickFilter::Reset(std::vector allowedKinds, std::vector preferredSemanticRoleKinds, bool allowFallbackForUnnamedRoles) +{ + m_allowedKinds = std::move(allowedKinds); + m_preferredSemanticRoleKinds = std::move(preferredSemanticRoleKinds); + m_allowFallbackForUnnamedRoles = allowFallbackForUnnamedRoles; +} + +void SolidSemanticPickFilter::ConfigurePickTargets(PickTargetOptions& ioOptions) const +{ + ioOptions.AllowedTargets = ToPickTargetFlags_(m_allowedKinds); + ioOptions.AllowHighlightOnlyRepresentationNode = true; +} + +bool SolidSemanticPickFilter::AllowHit(const PickHit& hit) const +{ + if (!m_allowedKinds.empty() && !ContainsKind_(m_allowedKinds, hit.Kind)) + return false; + + const std::string_view role = !hit.RepresentationNodeSemanticRole.empty() ? std::string_view(hit.RepresentationNodeSemanticRole) : (!hit.TopoSemanticRef.empty() ? std::string_view(hit.TopoSemanticRef) : std::string_view(hit.EntityToken)); + if (role.empty()) + return m_allowFallbackForUnnamedRoles && hit.TargetObjectId.IsValid(); + + return MatchesPreferredRoleKinds_(role); + +} + +bool SolidSemanticPickFilter::AllowRepresentationNode(const RepresentationNodeReference& node) const +{ + if (!node.TargetObjectId.IsValid() && node.PersistentEntityId == 0u && node.RepresentationNodeToken.empty()) + return false; + + const std::string_view role = !node.RepresentationNodeSemanticRole.empty() ? std::string_view(node.RepresentationNodeSemanticRole) : (!node.TopoSemanticRef.empty() ? std::string_view(node.TopoSemanticRef) : std::string_view(node.RepresentationNodeToken)); if (role.empty()) return m_allowFallbackForUnnamedRoles; + return MatchesPreferredRoleKinds_(role); +} + +const std::vector& SolidSemanticPickFilter::GetAllowedKinds() const noexcept +{ + return m_allowedKinds; +} + +const std::vector& SolidSemanticPickFilter::GetPreferredSemanticRoleKinds() const noexcept +{ + return m_preferredSemanticRoleKinds; +} + +bool SolidSemanticPickFilter::MatchesPreferredRoleKinds_(std::string_view roleOrToken) const +{ + return alice::MatchesAnySemanticRoleKind(roleOrToken, m_preferredSemanticRoleKinds); +} + +PickTargetFlag SolidSemanticPickFilter::ToPickTargetFlags_(const std::vector& kinds) noexcept +{ + if (kinds.empty()) + return PickTargetFlag::Any; + + PickTargetFlag flags = PickTargetFlag::None; + for (const PickHitKind kind : kinds) + { + switch (kind) + { + case PickHitKind::Object: + flags = flags | PickTargetFlag::Object; + break; + case PickHitKind::Body: + flags = flags | PickTargetFlag::Body; + break; + case PickHitKind::Face: + flags = flags | PickTargetFlag::Face; + break; + case PickHitKind::Edge: + flags = flags | PickTargetFlag::Edge; + break; + case PickHitKind::Vertex: + flags = flags | PickTargetFlag::Vertex; + break; + case PickHitKind::Curve: + flags = flags | PickTargetFlag::Curve; + break; + case PickHitKind::Point: + flags = flags | PickTargetFlag::Point; + break; + case PickHitKind::SketchCurve: + flags = flags | PickTargetFlag::SketchCurve; + break; + case PickHitKind::SketchPoint: + flags = flags | PickTargetFlag::SketchPoint; + break; + case PickHitKind::SketchRegion: + flags = flags | PickTargetFlag::SketchRegion; + break; + case PickHitKind::DatumPlane: + flags = flags | PickTargetFlag::DatumPlane; + break; + case PickHitKind::DatumAxis: + flags = flags | PickTargetFlag::DatumAxis; + break; + case PickHitKind::DatumPoint: + flags = flags | PickTargetFlag::DatumPoint; + break; + case PickHitKind::DatumCsys: + flags = flags | PickTargetFlag::DatumCsys; + break; + case PickHitKind::FeatureResult: + flags = flags | PickTargetFlag::FeatureResult; + break; + case PickHitKind::Component: + flags = flags | PickTargetFlag::Component; + break; + case PickHitKind::Occurrence: + flags = flags | PickTargetFlag::Occurrence; + break; + case PickHitKind::Text: + flags = flags | PickTargetFlag::Text; + break; + case PickHitKind::MeshTriangle: + flags = flags | PickTargetFlag::MeshTriangle; + break; + case PickHitKind::SubElement: + flags = flags | PickTargetFlag::SubElement; + break; + default: + break; +} + } + return flags; +} + +std::vector SolidSemanticPickFilter::AllowedKindsForIntent_(SolidPickIntent intent) +{ + //基准面是否应该填充?, 线框是否可行 + switch (intent) + { + case SolidPickIntent::SketchPlaneInput: + return { PickHitKind::DatumPlane, + PickHitKind::DatumAxis, + PickHitKind::DatumPoint, + PickHitKind::DatumCsys, + PickHitKind::Face, + PickHitKind::Edge, + PickHitKind::Vertex, + PickHitKind::Curve, + PickHitKind::SketchRegion, + PickHitKind::SketchCurve, + PickHitKind::SketchPoint, + PickHitKind::FeatureResult, + PickHitKind::SubElement, + PickHitKind::Object }; + case SolidPickIntent::OrientationReferenceInput: + return { PickHitKind::DatumPlane, PickHitKind::DatumAxis, PickHitKind::DatumPoint, PickHitKind::DatumCsys, + PickHitKind::Face, PickHitKind::Edge, PickHitKind::Vertex, PickHitKind::SketchRegion, PickHitKind::SketchCurve, + PickHitKind::SketchPoint, PickHitKind::FeatureResult, PickHitKind::SubElement, PickHitKind::Object }; + default: + return { PickHitKind::DatumPlane, PickHitKind::DatumAxis, PickHitKind::DatumPoint, PickHitKind::DatumCsys, + PickHitKind::Body, PickHitKind::Face, PickHitKind::Edge, PickHitKind::Vertex, PickHitKind::SketchRegion, + PickHitKind::SketchCurve, PickHitKind::SketchPoint, PickHitKind::FeatureResult, PickHitKind::Component, + PickHitKind::Occurrence, PickHitKind::SubElement, PickHitKind::Object }; } +} + +std::vector SolidSemanticPickFilter::RoleKindsForIntent_(SolidPickIntent intent) +{ + SolidDefaultPickBehavior behavior(intent); + switch (intent) + { + case SolidPickIntent::SketchPlaneInput: + { + auto roles = behavior.GetSketchSelectionSemanticRoleKinds(); + const auto& plane = behavior.GetSketchPlaneSemanticRoleKinds(); + roles.insert(roles.end(), plane.begin(), plane.end()); + return roles; + } + case SolidPickIntent::OrientationReferenceInput: + return behavior.GetOrientationReferenceSemanticRoleKinds(); + default: + return { SemanticRoleKind::DatumPlane, SemanticRoleKind::DatumAxis, SemanticRoleKind::DatumPoint, + SemanticRoleKind::DatumCsys, SemanticRoleKind::ModelPlanarFace, SemanticRoleKind::ModelFace, + SemanticRoleKind::ModelEdge, SemanticRoleKind::ModelVertex, SemanticRoleKind::ModelBody, + SemanticRoleKind::ModelCurve, SemanticRoleKind::ModelPoint, SemanticRoleKind::SketchRegion, + SemanticRoleKind::SketchCurve, SemanticRoleKind::SketchPoint, SemanticRoleKind::FeatureResult, + SemanticRoleKind::FeatureBody, SemanticRoleKind::FeatureFace, SemanticRoleKind::FeatureEdge, + SemanticRoleKind::FeatureVertex, SemanticRoleKind::Component, SemanticRoleKind::ComponentInstance, + SemanticRoleKind::Occurrence }; + } +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidPickFilters.h b/Designer/Interaction/SolidDesignerInteraction/SolidPickFilters.h new file mode 100644 index 00000000..84f60220 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidPickFilters.h @@ -0,0 +1,31 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "AliceIPickFilter.h" +#include "SolidDefaultPickBehavior.h" +#include +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSemanticPickFilter final : public alice::IPickFilter + { + public: + SolidSemanticPickFilter() = default; + explicit SolidSemanticPickFilter(SolidPickIntent intent); + SolidSemanticPickFilter(std::vector allowedKinds, std::vector preferredSemanticRoleKinds, bool allowFallbackForUnnamedRoles = false); + void Reset(SolidPickIntent intent); + void Reset(std::vector allowedKinds, std::vector preferredSemanticRoleKinds, bool allowFallbackForUnnamedRoles = false); + void ConfigurePickTargets(alice::PickTargetOptions& ioOptions) const override; + bool AllowHit(const alice::PickHit& hit) const override; + bool AllowRepresentationNode(const alice::RepresentationNodeReference& node) const override; + const std::vector& GetAllowedKinds() const noexcept; + const std::vector& GetPreferredSemanticRoleKinds() const noexcept; + private: + bool MatchesPreferredRoleKinds_(std::string_view roleOrToken) const; + static alice::PickTargetFlag ToPickTargetFlags_(const std::vector& kinds) noexcept; + static std::vector AllowedKindsForIntent_(SolidPickIntent intent); + static std::vector RoleKindsForIntent_(SolidPickIntent intent); + private: + std::vector m_allowedKinds; + std::vector m_preferredSemanticRoleKinds; + bool m_allowFallbackForUnnamedRoles = false; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidRevolveAuthoringPayloadBuilder.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidRevolveAuthoringPayloadBuilder.cpp new file mode 100644 index 00000000..74a02423 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidRevolveAuthoringPayloadBuilder.cpp @@ -0,0 +1,43 @@ +#include "SolidRevolveAuthoringPayloadBuilder.h" + +#include "AliceFeatureLifecycleModels.h" +#include "AliceIFeatureDefinition.h" +#include "AliceIFeatureReferenceSet.h" + +using namespace sdr; +using namespace alice; + +bool SolidRevolveAuthoringPayload::IsComplete() const noexcept +{ + return Definition != nullptr && ReferenceSet != nullptr; +} + +SolidRevolveAuthoringPayload SolidRevolveAuthoringPayloadBuilder::Build(std::unique_ptr definition, + std::shared_ptr referenceSet) +{ + SolidRevolveAuthoringPayload payload; + payload.Definition = std::move(definition); + payload.ReferenceSet = std::move(referenceSet); + return payload; +} + +FeatureCreateRequestModel SolidRevolveAuthoringPayloadBuilder::BuildCreateRequest(const SolidRevolveAuthoringPayload& payload, + FeatureLifecycleApplyMode applyMode, + FeatureDomain targetDomain, + FeatureId targetFeatureId, + bool allowIncompleteCommit) +{ + FeatureCreateRequestModel request; + request.SetTargetDomain(targetDomain); + request.SetApplyMode(applyMode); + + auto upDefinition = payload.Definition->Clone(); + request.SetDefinitionCandidate(std::move(upDefinition)); + request.SetReferenceSetCandidate(payload.ReferenceSet); + request.SetAllowIncompleteCommit(allowIncompleteCommit); + if (targetFeatureId.IsValid()) + { + request.SetTargetFeatureId(targetFeatureId); + } + return request; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidRevolveAuthoringPayloadBuilder.h b/Designer/Interaction/SolidDesignerInteraction/SolidRevolveAuthoringPayloadBuilder.h new file mode 100644 index 00000000..3c7726dd --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidRevolveAuthoringPayloadBuilder.h @@ -0,0 +1,37 @@ +#pragma once +#include "SolidDesignerInteraction.h" + +#include "AliceFeaturePrimitives.h" +#include "AliceIFeatureDefinition.h" + +#include + +namespace alice +{ + class IFeatureReferenceSet; + class FeatureCreateRequestModel; +} + +namespace sdr +{ + struct SOLID_DESIGNER_INTERACTION_EXPORT SolidRevolveAuthoringPayload final + { + std::unique_ptr Definition; + std::shared_ptr ReferenceSet; + + [[nodiscard]] bool IsComplete() const noexcept; + }; + + class SOLID_DESIGNER_INTERACTION_EXPORT SolidRevolveAuthoringPayloadBuilder final + { + public: + static SolidRevolveAuthoringPayload Build(std::unique_ptr definition, + std::shared_ptr referenceSet); + + static alice::FeatureCreateRequestModel BuildCreateRequest(const SolidRevolveAuthoringPayload& payload, + alice::FeatureLifecycleApplyMode applyMode, + alice::FeatureDomain targetDomain, + alice::FeatureId targetFeatureId = {}, + bool allowIncompleteCommit = false); + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionArcOperation.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidSectionArcOperation.cpp new file mode 100644 index 00000000..3068145e --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionArcOperation.cpp @@ -0,0 +1,116 @@ +#include "SolidSectionArcOperation.h" + +using namespace sdr; +using namespace alice; + +namespace +{ + static bool IsLeftButtonDown_(const PointerEvent& e) + { + return (e.buttons & 1u) != 0u; + } +} + +SolidSectionArcOperation::SolidSectionArcOperation(std::shared_ptr context) noexcept + : SolidSectionCurveOperationBase(std::move(context)) +{ +} + +SolidSectionArcOperation::~SolidSectionArcOperation() = default; + +void SolidSectionArcOperation::OnPointerDown(const PointerEvent& e) +{ + if (!IsLeftButtonDown_(e) || !IsActive_() || !m_spContext || !m_spContext->pSketchEditState) + { + return; + } + + SketchPoint2d point; + if (!TryProjectPointerToSectionPoint(*m_spContext, e, point)) + { + return; + } + + SolidSketchEditState& state = *m_spContext->pSketchEditState; + const SolidSketchArcDraft& draft = state.GetArcDraft(); + if (!draft.Active) + { + state.BeginArc(point); + NotifyDraftChanged_(); + return; + } + + bool changed = false; + if (draft.Step == 1u) + { + changed = state.AdvanceArc(point); + } + else if (draft.Step == 2u) + { + changed = state.CommitArc(point); + if (changed) + { + NotifyGeometryChanged_(); + } + } + (void)changed; + NotifyDraftChanged_(); +} + +void SolidSectionArcOperation::OnPointerMove(const PointerEvent& e) +{ + if (!IsActive_() || !m_spContext || !m_spContext->pSketchEditState) + { + return; + } + + const SolidSketchArcDraft& draft = m_spContext->pSketchEditState->GetArcDraft(); + if (!draft.Active) + { + return; + } + + SketchPoint2d point; + if (!TryProjectPointerToSectionPoint(*m_spContext, e, point)) + { + return; + } + + m_spContext->pSketchEditState->UpdateArc(point); + NotifyDraftChanged_(); +} + +void SolidSectionArcOperation::OnPointerUp(const PointerEvent& e) +{ + (void)e; +} + +void SolidSectionArcOperation::OnCancel() +{ + if (!m_spContext || !m_spContext->pSketchEditState) + { + FinishCancelled_(); + return; + } + + if (m_spContext->pSketchEditState->GetArcDraft().Active) + { + m_spContext->pSketchEditState->CancelDraft(); + ClearFeedback_(); + NotifyDraftChanged_(); + return; + } + + ClearFeedback_(); + FinishCancelled_(); +} + +bool SolidSectionArcOperation::OnKeyDown(const KeyEvent& e) +{ + if (static_cast(e.key) != InputKeyCode::Escape) + { + return false; + } + OnCancel(); + return true; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionArcOperation.h b/Designer/Interaction/SolidDesignerInteraction/SolidSectionArcOperation.h new file mode 100644 index 00000000..6d55a1fc --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionArcOperation.h @@ -0,0 +1,19 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "SolidSectionCurveOperationBase.h" + +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSectionArcOperation final : public SolidSectionCurveOperationBase + { + public: + explicit SolidSectionArcOperation(std::shared_ptr context) noexcept; + ~SolidSectionArcOperation() override; + + void OnPointerDown(const alice::PointerEvent& e) override; + void OnPointerMove(const alice::PointerEvent& e) override; + void OnPointerUp(const alice::PointerEvent& e) override; + void OnCancel() override; + bool OnKeyDown(const alice::KeyEvent& e) override; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionCircleOperation.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidSectionCircleOperation.cpp new file mode 100644 index 00000000..8def0efe --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionCircleOperation.cpp @@ -0,0 +1,107 @@ +#include "SolidSectionCircleOperation.h" + +using namespace sdr; +using namespace alice; + +namespace +{ + static bool IsLeftButtonDown_(const PointerEvent& e) + { + return (e.buttons & 1u) != 0u; + } +} + +SolidSectionCircleOperation::SolidSectionCircleOperation(std::shared_ptr context) noexcept + : SolidSectionCurveOperationBase(std::move(context)) +{ +} + +SolidSectionCircleOperation::~SolidSectionCircleOperation() = default; + +void SolidSectionCircleOperation::OnPointerDown(const PointerEvent& e) +{ + if (!IsLeftButtonDown_(e) || !IsActive_() || !m_spContext || !m_spContext->pSketchEditState) + { + return; + } + + SketchPoint2d point; + if (!TryProjectPointerToSectionPoint(*m_spContext, e, point)) + { + return; + } + + SolidSketchEditState& state = *m_spContext->pSketchEditState; + const SolidSketchCircleDraft& draft = state.GetCircleDraft(); + if (!draft.Active) + { + state.BeginCircle(point); + NotifyDraftChanged_(); + return; + } + + const bool committed = state.CommitCircle(point); + if (committed) + { + NotifyGeometryChanged_(); + } + NotifyDraftChanged_(); +} + +void SolidSectionCircleOperation::OnPointerMove(const PointerEvent& e) +{ + if (!IsActive_() || !m_spContext || !m_spContext->pSketchEditState) + { + return; + } + + const SolidSketchCircleDraft& draft = m_spContext->pSketchEditState->GetCircleDraft(); + if (!draft.Active) + { + return; + } + + SketchPoint2d point; + if (!TryProjectPointerToSectionPoint(*m_spContext, e, point)) + { + return; + } + + m_spContext->pSketchEditState->UpdateCircle(point); + NotifyDraftChanged_(); +} + +void SolidSectionCircleOperation::OnPointerUp(const PointerEvent& e) +{ + (void)e; +} + +void SolidSectionCircleOperation::OnCancel() +{ + if (!m_spContext || !m_spContext->pSketchEditState) + { + FinishCancelled_(); + return; + } + + if (m_spContext->pSketchEditState->GetCircleDraft().Active) + { + m_spContext->pSketchEditState->CancelDraft(); + ClearFeedback_(); + NotifyDraftChanged_(); + return; + } + + ClearFeedback_(); + FinishCancelled_(); +} + +bool SolidSectionCircleOperation::OnKeyDown(const KeyEvent& e) +{ + if (static_cast(e.key) != InputKeyCode::Escape) + { + return false; + } + OnCancel(); + return true; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionCircleOperation.h b/Designer/Interaction/SolidDesignerInteraction/SolidSectionCircleOperation.h new file mode 100644 index 00000000..d0293a62 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionCircleOperation.h @@ -0,0 +1,19 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "SolidSectionCurveOperationBase.h" + +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSectionCircleOperation final : public SolidSectionCurveOperationBase + { + public: + explicit SolidSectionCircleOperation(std::shared_ptr context) noexcept; + ~SolidSectionCircleOperation() override; + + void OnPointerDown(const alice::PointerEvent& e) override; + void OnPointerMove(const alice::PointerEvent& e) override; + void OnPointerUp(const alice::PointerEvent& e) override; + void OnCancel() override; + bool OnKeyDown(const alice::KeyEvent& e) override; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionCurveOperationBase.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidSectionCurveOperationBase.cpp new file mode 100644 index 00000000..219a71e2 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionCurveOperationBase.cpp @@ -0,0 +1,97 @@ +#include "SolidSectionCurveOperationBase.h" + +using namespace sdr; +using namespace alice; + +SolidSectionCurveOperationBase::SolidSectionCurveOperationBase(std::shared_ptr context) noexcept + : m_spContext(std::move(context)) +{ +} + +SolidSectionCurveOperationBase::~SolidSectionCurveOperationBase() = default; + +void SolidSectionCurveOperationBase::InitOperation(IUiView* pCurrentView) +{ + alice::OperationBase::InitOperation(pCurrentView); +} + +void SolidSectionCurveOperationBase::OnCancel() +{ + if (m_spContext && m_spContext->pSketchEditState) + { + m_spContext->pSketchEditState->CancelDraft(); + } + ClearFeedback_(); + NotifyDraftChanged_(); + FinishCancelled_(); +} + +bool SolidSectionCurveOperationBase::OnKeyDown(const KeyEvent& e) +{ + if (static_cast(e.key) != InputKeyCode::Escape) + { + return false; + } + OnCancel(); + return true; +} + +bool SolidSectionCurveOperationBase::IsFinished() const noexcept +{ + return m_bFinished; +} + +void SolidSectionCurveOperationBase::GetOperationResult(OperationResult& outResult) const +{ + if (m_result.IsFinished()) + { + outResult = m_result; + return; + } + alice::OperationBase::GetOperationResult(outResult); +} + +bool SolidSectionCurveOperationBase::IsActive_() const noexcept +{ + return m_spContext && m_spContext->pSketchEditState && (!m_spContext->IsSectionEditingActive || m_spContext->IsSectionEditingActive()); +} + +void SolidSectionCurveOperationBase::ClearFeedback_() const +{ + if (m_spContext && m_spContext->ClearHighlightFeedback) + { + m_spContext->ClearHighlightFeedback(); + } +} + +void SolidSectionCurveOperationBase::NotifyDraftChanged_() const +{ + if (m_spContext && m_spContext->OnDraftChanged) + { + m_spContext->OnDraftChanged(); + } +} + +void SolidSectionCurveOperationBase::NotifyGeometryChanged_() +{ + if (m_spContext && m_spContext->SyncEditSession) + { + m_spContext->SyncEditSession(); + } + if (m_spContext && m_spContext->OnGeometryChanged) + { + m_spContext->OnGeometryChanged(); + } +} + +void SolidSectionCurveOperationBase::FinishSuccessful_() +{ + m_result = OperationResult::Successful(OperationFinishReason::CompletedByParent); + m_bFinished = true; +} + +void SolidSectionCurveOperationBase::FinishCancelled_(OperationFinishReason reason) +{ + m_result = OperationResult::Cancelled(reason); + m_bFinished = true; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionCurveOperationBase.h b/Designer/Interaction/SolidDesignerInteraction/SolidSectionCurveOperationBase.h new file mode 100644 index 00000000..38c7c564 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionCurveOperationBase.h @@ -0,0 +1,35 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "AliceOperationBase.h" +#include "SolidSectionEditSharedContext.h" + +#include + +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSectionCurveOperationBase : public alice::OperationBase + { + public: + explicit SolidSectionCurveOperationBase(std::shared_ptr context) noexcept; + ~SolidSectionCurveOperationBase() override; + + void InitOperation(alice::IUiView* pCurrentView) override; + void OnCancel() override; + bool OnKeyDown(const alice::KeyEvent& e) override; + bool IsFinished() const noexcept override; + void GetOperationResult(alice::OperationResult& outResult) const override; + + protected: + bool IsActive_() const noexcept; + void ClearFeedback_() const; + void NotifyDraftChanged_() const; + void NotifyGeometryChanged_(); + void FinishSuccessful_(); + void FinishCancelled_(alice::OperationFinishReason reason = alice::OperationFinishReason::SystemCancelled); + + protected: + std::shared_ptr m_spContext; + bool m_bFinished{ false }; + alice::OperationResult m_result; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionEditOperation.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidSectionEditOperation.cpp new file mode 100644 index 00000000..83d42931 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionEditOperation.cpp @@ -0,0 +1,466 @@ +#include "SolidSectionEditOperation.h" + +#include "SolidSectionLineOperation.h" +#include "SolidSectionCircleOperation.h" +#include "SolidSectionArcOperation.h" +#include "SolidSectionRectangleOperation.h" +#include "SolidSectionEllipseOperation.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "AliceISnappingManager.h" +#include "AliceIOperationManager.h" +#include "AliceISelectionManager.h" +#include "AliceISketchEditSession.h" +#include "AliceIDocument.h" +#include "AliceISketchInteractionController.h" +#include "AliceSketchInteractionController.h" + +using namespace sdr; +using namespace alice; + +SolidSectionEditOperation::SolidSectionEditOperation(IDocument* pDocument, + SolidSketchEditState* pSketchEditState, + ISketchEditSession* pSketchEditSession, + const SolidSketchPlacementContext& placementContext, + std::string* pLastErrorText, + std::function onGeometryChanged, + std::function onDraftChanged, + std::function onAccepted, + std::function onCancelled) + : m_pDocument(pDocument) + , m_pSketchEditState(pSketchEditState) + , m_pSketchEditSession(pSketchEditSession) + , m_placementContext(placementContext) + , m_pLastErrorText(pLastErrorText) + , m_onGeometryChanged(std::move(onGeometryChanged)) + , m_onDraftChanged(std::move(onDraftChanged)) + , m_onAccepted(std::move(onAccepted)) + , m_onCancelled(std::move(onCancelled)) +{ +} + +SolidSectionEditOperation::~SolidSectionEditOperation() = default; + +void SolidSectionEditOperation::InitOperation(IUiView* pCurrentView) +{ + SolidAuthoringOperationBase::InitOperation(pCurrentView); + m_inputProjector.SetPlacementContext(m_placementContext); + m_pSketchInteractionController = std::make_unique(); + if (m_pSketchInteractionController) + { + m_pSketchInteractionController->BindDocument(m_pDocument); + m_pSketchInteractionController->SetSketchPlaneReferenceId(m_placementContext.SketchPlaneId); + if (m_pSketchEditState) + { + m_pSketchInteractionController->SetSketch(m_pSketchEditState->GetSketch()); + } + } + m_spSharedContext = std::make_shared(); + m_spSharedContext->pSketchEditState = m_pSketchEditState; + m_spSharedContext->pSketchInputProjector = &m_inputProjector; + m_spSharedContext->pLastErrorText = m_pLastErrorText; + m_spSharedContext->IsSectionEditingActive = [this]() { return IsEditingActive_(); }; + m_spSharedContext->OnGeometryChanged = [this]() { if (m_onGeometryChanged) m_onGeometryChanged(); }; + m_spSharedContext->OnDraftChanged = [this]() { if (m_onDraftChanged) m_onDraftChanged(); }; + m_spSharedContext->pSketchInteractionController = m_pSketchInteractionController.get(); + m_spSharedContext->SnapTolerancePixels = 10.0; + m_spSharedContext->ClearHighlightFeedback = [this]() { ClearHighlightFeedback_(); }; + m_spSharedContext->RefreshInteractionFeedback = [this]() { RefreshInteractionFeedback_(); }; + m_spSharedContext->SyncEditSession = [this]() { SyncEditSession_(); }; + if (m_pSketchEditState) + { + m_pSketchEditState->SetActiveTool(SolidSketchToolKind::Select); + } +} + +void SolidSectionEditOperation::OnCancel() +{ + ExecuteSectionCancel(); +} + +bool SolidSectionEditOperation::CanConsumeCommand() +{ + return true; +} + +bool SolidSectionEditOperation::ConsumeCommand(IUiView* pCurrentView, const std::string& commandId, const CommandParameter& params) +{ + (void)pCurrentView; + (void)params; + return RouteSketchCommand_(commandId); +} + +void SolidSectionEditOperation::OnChildOperationFinished(const OperationResult& result) +{ + if (!m_pSketchEditState) + { + return; + } + + if (result.FinishStatus == OperationFinishStatus::Successful) + { + if (result.FinishReason != OperationFinishReason::CompletedByParent) + { + ApplyTool_(m_pSketchEditState->GetActiveTool()); + } + return; + } + + if (result.FinishStatus == OperationFinishStatus::Cancelled) + { + ApplyTool_(SolidSketchToolKind::Select); + } +} + +bool SolidSectionEditOperation::OnKeyDown(const KeyEvent& e) +{ + if (static_cast(e.key) == InputKeyCode::Escape) + { + ExecuteSectionCancel(); + return true; + } + if (static_cast(e.key) == InputKeyCode::Enter) + { + ExecuteSectionOk(); + return true; + } + return false; +} + +void SolidSectionEditOperation::ActivateLineTool() +{ + ApplyTool_(SolidSketchToolKind::Line); +} + +void SolidSectionEditOperation::ActivateCircleTool() +{ + ApplyTool_(SolidSketchToolKind::CircleCenterPoint); +} + +void SolidSectionEditOperation::ActivateArcTool() +{ + ApplyTool_(SolidSketchToolKind::ArcCenterEnds); +} + +void SolidSectionEditOperation::ActivateRectangleTool() +{ + ApplyTool_(SolidSketchToolKind::RectangleCorner); +} + +void SolidSectionEditOperation::ActivateEllipseTool() +{ + ApplyTool_(SolidSketchToolKind::EllipseCenterPoint); +} + +void SolidSectionEditOperation::ActivateSelectionTool() +{ + ApplyTool_(SolidSketchToolKind::Select); +} + +void SolidSectionEditOperation::ExecuteDimensionCommand() +{ + if (m_pLastErrorText) + *m_pLastErrorText = "Dimension command is reserved for the next phase."; +} + +void SolidSectionEditOperation::ExecuteConstraintCommand() +{ + if (m_pLastErrorText) *m_pLastErrorText = "Constraint command is reserved for the next phase."; +} + +void SolidSectionEditOperation::ExecuteSectionOk() +{ + if (m_pSketchEditState) + { + m_pSketchEditState->CancelDraft(); + m_pSketchEditState->SetActiveTool(SolidSketchToolKind::Select); + } + ClearHighlightFeedback_(); + (void)CompleteOwnedChildOperation(); + SyncEditSession_(); + + const SolidSketchSectionAnalysis analysis = m_pSketchEditState ? m_pSketchEditState->AnalyzeSection() : SolidSketchSectionAnalysis{}; + const bool bSectionValid = analysis.ClosedProfileCount > 0 + && analysis.OpenChainCount == 0 + && !analysis.HasDanglingGeometry + && !analysis.HasSelfIntersection + && !analysis.HasZeroAreaProfile; + if (!bSectionValid) + { + if (m_pLastErrorText) + { + *m_pLastErrorText = "Sketch section is invalid. A closed, non-self-intersecting profile is required."; + } + return; + } + + RebuildResult_(true); + if (m_onAccepted) + { + m_onAccepted(); + } +} + +void SolidSectionEditOperation::ExecuteSectionCancel() +{ + if (m_pSketchEditState) + { + m_pSketchEditState->CancelDraft(); + m_pSketchEditState->SetActiveTool(SolidSketchToolKind::Select); + } + ClearHighlightFeedback_(); + (void)CompleteOwnedChildOperation(); + RebuildResult_(false); + if (m_onCancelled) + { + m_onCancelled(); + } +} + +SolidSectionEditOperation* SolidSectionEditOperation::FindActive(ISession* pSession) noexcept +{ + IOperationManager* const pOperationManager = pSession ? pSession->GetOperationManagerFw() : nullptr; + if (!pOperationManager) + { + return nullptr; + } + + const std::size_t depth = pOperationManager->ActiveDepth(); + for (std::size_t i = depth; i > 0; --i) + { + if (auto* const pOp = dynamic_cast(pOperationManager->GetOperationAt(i - 1u))) + { + return pOp; + } + } + return nullptr; +} + +void SolidSectionEditOperation::ApplyTool_(SolidSketchToolKind tool) +{ + if (!m_pSketchEditState) + { + return; + } + m_pSketchEditState->CancelDraft(); + m_pSketchEditState->SetActiveTool(tool); + ClearHighlightFeedback_(); + if (tool != SolidSketchToolKind::Select) + { + if (!StartToolOperation_(tool) && m_pLastErrorText) + { + *m_pLastErrorText = "Sketch tool child operation could not be started."; + } + } + if (m_onDraftChanged) + { + m_onDraftChanged(); + } +} + +bool SolidSectionEditOperation::RouteSketchCommand_(const std::string& commandId) +{ + using namespace Cmd; + + if (commandId == SKETCH_LINE) + { + PrepareForToolSwitch_(); + ActivateLineTool(); + return true; + } + if (commandId == SKETCH_CIRCLE) + { + PrepareForToolSwitch_(); + ActivateCircleTool(); + return true; + } + if (commandId == SKETCH_ARC) + { + PrepareForToolSwitch_(); + ActivateArcTool(); + return true; + } + if (commandId == SKETCH_RECTANGLE) + { + PrepareForToolSwitch_(); + ActivateRectangleTool(); + return true; + } + if (commandId == SKETCH_ELLIPSE) + { + PrepareForToolSwitch_(); + ActivateEllipseTool(); + return true; + } + if (commandId == SKETCH_SELECT) + { + PrepareForToolSwitch_(); + ActivateSelectionTool(); + return true; + } + if (commandId == SKETCH_OK) + { + ExecuteSectionOk(); + return true; + } + if (commandId == SKETCH_CANCEL) + { + ExecuteSectionCancel(); + return true; + } + if (commandId == SKETCH_DIM_DIMENSION || + commandId == SKETCH_DIM_HORIZONTAL || + commandId == SKETCH_DIM_VERTICAL || + commandId == SKETCH_DIM_ANGLE || + commandId == SKETCH_DIM_RADIUS || + commandId == SKETCH_DIM_DIAMETER || + commandId == SKETCH_DIM_BASELINE || + commandId == SKETCH_DIM_PERIMETER || + commandId == SKETCH_DIM_REFERENCE || + commandId == SKETCH_DIM_GENERAL) + { + ExecuteDimensionCommand(); + return true; + } + if (commandId == SKETCH_CONSTRAINT_COINCIDENT) + { + ExecuteConstraintCommand(); + return true; + } + + return false; +} + +void SolidSectionEditOperation::PrepareForToolSwitch_() +{ + if (m_pSketchEditState) + { + m_pSketchEditState->CancelDraft(); + + // 关键:在结束当前 child operation 之前, + // 先把当前工具置回 Select,避免 OnChildOperationFinished() + // 按“旧工具”把 child operation 又重启一遍。 + m_pSketchEditState->SetActiveTool(SolidSketchToolKind::Select); + } + ClearHighlightFeedback_(); + (void)CompleteOwnedChildOperation(); +} + +bool SolidSectionEditOperation::StartToolOperation_(SolidSketchToolKind tool) +{ + switch (tool) + { + case SolidSketchToolKind::Line: + return StartChildOperation(std::make_unique(m_spSharedContext)); + case SolidSketchToolKind::CircleCenterPoint: + return StartChildOperation(std::make_unique(m_spSharedContext)); + case SolidSketchToolKind::ArcCenterEnds: + return StartChildOperation(std::make_unique(m_spSharedContext)); + case SolidSketchToolKind::RectangleCorner: + return StartChildOperation(std::make_unique(m_spSharedContext)); + case SolidSketchToolKind::EllipseCenterPoint: + return StartChildOperation(std::make_unique(m_spSharedContext)); + default: + return false; + } +} + +bool SolidSectionEditOperation::IsEditingActive_() const noexcept +{ + return !OperationBase::IsFinished(); +} + +void SolidSectionEditOperation::SyncEditSession_() +{ + if (!m_pSketchEditSession || !m_pSketchEditState) + { + return; + } + std::shared_ptr workingSketch = m_pSketchEditState->GetSketch(); + if (m_pSketchInteractionController && workingSketch) + { + alice::SketchAutoConstraintOptions autoOptions; + autoOptions.EnableCoincident = true; + autoOptions.EnableAxisAligned = true; + autoOptions.EnableSolve = (m_pDocument != nullptr); + (void)m_pSketchInteractionController->PostProcessSketch(*workingSketch, autoOptions, nullptr); + m_pSketchInteractionController->SetSketch(workingSketch); + } + (void)m_pSketchEditSession->SetWorkingSketch(workingSketch); + (void)m_pSketchEditSession->SetPlacementReferences(m_placementContext.SketchPlaneId, m_placementContext.PlacementReferenceId); + const SolidSketchSectionAnalysis analysis = m_pSketchEditState->AnalyzeSection(); + (void)m_pSketchEditSession->SetSectionAnalysis(analysis.ClosedProfileCount, + analysis.OpenChainCount, + analysis.HasSelfIntersection, + analysis.HasDanglingGeometry, + analysis.HasZeroAreaProfile); + (void)m_pSketchEditSession->SyncKernelCurveBindings(); + (void)m_pSketchEditSession->SyncWorkingDefinitionFromSketch(); +} + +void SolidSectionEditOperation::RebuildResult_(bool accepted) +{ + SolidSectionEditResultData data; + data.Accepted = accepted; + if (m_pSketchEditState) + { + data.Sketch = m_pSketchEditState->GetSketch(); + data.Analysis = m_pSketchEditState->AnalyzeSection(); + } + OperationResult result = accepted + ? OperationResult::Successful(OperationFinishReason::Enter) + : OperationResult::Cancelled(OperationFinishReason::Esc); + result.Payload = std::make_unique(data); + SetOperationResult(std::move(result)); +} + +void SolidSectionEditOperation::ClearHighlightFeedback_() +{ + const bool hadFeedback = m_pSketchInteractionController && m_pSketchInteractionController->HasResolvedFeedback(); + if (m_pSketchInteractionController) + { + m_pSketchInteractionController->ClearResolvedFeedback(); + } + alice::ISession* pSession = alice::CoreAppUtil::GetCurrentSession(); + alice::ISnappingManager* pSnappingManager = pSession ? pSession->GetSnappingManagerFw() : nullptr; + if (pSnappingManager) + { + pSnappingManager->ClearResolvedSnapPoint(); + pSnappingManager->SetResolvedEntityToken({}); + } + alice::ISelectionManager* pSelectionManager = pSession ? pSession->GetSelectionManagerFw() : nullptr; + if (pSelectionManager) + { + pSelectionManager->ClearPreselection(); + } + if (hadFeedback) + { + RefreshInteractionFeedback_(); + } +} + +void SolidSectionEditOperation::RefreshInteractionFeedback_() +{ + alice::ISession* const pSession = alice::CoreAppUtil::GetCurrentSession(); + alice::ISnappingManager* const pSnappingManager = pSession ? pSession->GetSnappingManagerFw() : nullptr; + if (pSnappingManager != nullptr) + { + if (m_pSketchInteractionController && m_pSketchInteractionController->HasResolvedFeedback()) + { + const alice::SketchPoint2d point = m_pSketchInteractionController->GetResolvedFeedbackPoint(); + pSnappingManager->SetResolvedSnapPoint(alice::Vector2d(point.X(), point.Y())); + pSnappingManager->SetResolvedEntityToken(m_pSketchInteractionController->GetResolvedFeedbackToken()); + } + else + { + pSnappingManager->ClearResolvedSnapPoint(); + pSnappingManager->SetResolvedEntityToken({}); + } + } + + if (m_onDraftChanged) + { + m_onDraftChanged(); + } +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionEditOperation.h b/Designer/Interaction/SolidDesignerInteraction/SolidSectionEditOperation.h new file mode 100644 index 00000000..244c90a5 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionEditOperation.h @@ -0,0 +1,74 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "SolidAuthoringOperationBase.h" +#include "SolidSectionEditSharedContext.h" +#include "SolidSectionOperationResults.h" +#include "SolidSketchPlacementContext.h" +#include "SolidSketchInputProjector.h" + +namespace alice { class ISession; class ISketchEditSession; class IDocument; class ISketchInteractionController; } + +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSectionEditOperation final : public SolidAuthoringOperationBase + { + public: + SolidSectionEditOperation(alice::IDocument* pDocument, + SolidSketchEditState* pSketchEditState, + alice::ISketchEditSession* pSketchEditSession, + const SolidSketchPlacementContext& placementContext, + std::string* pLastErrorText, + std::function onGeometryChanged, + std::function onDraftChanged, + std::function onAccepted, + std::function onCancelled); + ~SolidSectionEditOperation() override; + + void InitOperation(alice::IUiView* pCurrentView) override; + void OnCancel() override; + void OnChildOperationFinished(const alice::OperationResult& result) override; + bool CanConsumeCommand() override; + bool ConsumeCommand(alice::IUiView* pCurrentView, const std::string& commandId, const alice::CommandParameter& params) override; + bool OnKeyDown(const alice::KeyEvent& e) override; + + void ActivateLineTool(); + void ActivateCircleTool(); + void ActivateArcTool(); + void ActivateRectangleTool(); + void ActivateEllipseTool(); + void ActivateSelectionTool(); + void ExecuteSectionOk(); + void ExecuteSectionCancel(); + void ExecuteDimensionCommand(); + void ExecuteConstraintCommand(); + + static SolidSectionEditOperation* FindActive(alice::ISession* pSession) noexcept; + const alice::ISketchInteractionController* GetSketchInteractionController() const noexcept { return m_pSketchInteractionController.get(); } + + private: + void ApplyTool_(SolidSketchToolKind tool); + bool StartToolOperation_(SolidSketchToolKind tool); + bool RouteSketchCommand_(const std::string& commandId); + void PrepareForToolSwitch_(); + bool IsEditingActive_() const noexcept; + void SyncEditSession_(); + void RebuildResult_(bool accepted); + void ClearHighlightFeedback_(); + void RefreshInteractionFeedback_(); + + private: + alice::IDocument* m_pDocument = nullptr; + SolidSketchEditState* m_pSketchEditState = nullptr; + alice::ISketchEditSession* m_pSketchEditSession = nullptr; + SolidSketchPlacementContext m_placementContext{}; + SolidSketchInputProjector m_inputProjector; + std::shared_ptr m_spSharedContext; + std::string* m_pLastErrorText = nullptr; + std::function m_onGeometryChanged; + std::function m_onDraftChanged; + std::function m_onAccepted; + std::function m_onCancelled; + std::unique_ptr m_pSketchInteractionController; + alice::ObjectId m_idHighlightObject; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionEditSharedContext.h b/Designer/Interaction/SolidDesignerInteraction/SolidSectionEditSharedContext.h new file mode 100644 index 00000000..c84efa53 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionEditSharedContext.h @@ -0,0 +1,87 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "SolidSketchEditState.h" +#include "SolidSketchInputProjector.h" +#include "SolidSectionOperationResults.h" +#include "AlicePointerEvent.h" +#include "AliceISketchInteractionController.h" + +#include +#include +#include +#include + +namespace sdr +{ + struct SolidSectionEditSharedContext + { + SolidSketchEditState* pSketchEditState = nullptr; + ISolidSketchInputProjector* pSketchInputProjector = nullptr; + std::string* pLastErrorText = nullptr; + std::function IsSectionEditingActive; + std::function OnGeometryChanged; + std::function OnDraftChanged; + alice::ISketchInteractionController* pSketchInteractionController = nullptr; + double SnapTolerancePixels = 10.0; + std::function ClearHighlightFeedback; + std::function RefreshInteractionFeedback; + std::function SyncEditSession; + }; + + inline bool TryProjectPointerToSectionPoint(const SolidSectionEditSharedContext& context, + const alice::PointerEvent& e, + alice::SketchPoint2d& outPoint) + { + if (context.IsSectionEditingActive && !context.IsSectionEditingActive()) + { + if (context.pLastErrorText) + { + *context.pLastErrorText = "Section editing is no longer active."; + } + return false; + } + if (!context.pSketchInputProjector) + { + if (context.pLastErrorText) + { + *context.pLastErrorText = "Sketch input projector is not available."; + } + return false; + } + alice::SketchPoint2d projectedPoint; + if (!context.pSketchInputProjector->TryProjectScreenPointToSketch(e.x, e.y, projectedPoint)) + { + return false; + } + + if (context.pSketchInteractionController == nullptr) + { + outPoint = projectedPoint; + return true; + } + + const SolidSketchPlacementContext placementContext = context.pSketchInputProjector->GetPlacementContext(); + alice::SketchInteractionResolveResult result; + alice::SketchInputResolveOptions resolveOptions; + resolveOptions.ProjectionScale = std::max(placementContext.ScreenToModelScale, 1.0e-9); + resolveOptions.SnapTolerancePixels = std::max(context.SnapTolerancePixels, 1.0); + if (!context.pSketchInteractionController->ResolveProjectedPoint(projectedPoint, + resolveOptions, + result)) + { + outPoint = projectedPoint; + if (result.FeedbackChanged && context.RefreshInteractionFeedback) + { + context.RefreshInteractionFeedback(); + } + return true; + } + + outPoint = result.ResolvedPoint; + if (result.FeedbackChanged && context.RefreshInteractionFeedback) + { + context.RefreshInteractionFeedback(); + } + return true; + } +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionEllipseOperation.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidSectionEllipseOperation.cpp new file mode 100644 index 00000000..3ae1b046 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionEllipseOperation.cpp @@ -0,0 +1,107 @@ +#include "SolidSectionEllipseOperation.h" + +using namespace sdr; +using namespace alice; + +namespace +{ + static bool IsLeftButtonDown_(const PointerEvent& e) + { + return (e.buttons & 1u) != 0u; + } +} + +SolidSectionEllipseOperation::SolidSectionEllipseOperation(std::shared_ptr context) noexcept + : SolidSectionCurveOperationBase(std::move(context)) +{ +} + +SolidSectionEllipseOperation::~SolidSectionEllipseOperation() = default; + +void SolidSectionEllipseOperation::OnPointerDown(const PointerEvent& e) +{ + if (!IsLeftButtonDown_(e) || !IsActive_() || !m_spContext || !m_spContext->pSketchEditState) + { + return; + } + + SketchPoint2d point; + if (!TryProjectPointerToSectionPoint(*m_spContext, e, point)) + { + return; + } + + SolidSketchEditState& state = *m_spContext->pSketchEditState; + const SolidSketchEllipseDraft& draft = state.GetEllipseDraft(); + if (!draft.Active) + { + state.BeginEllipse(point); + NotifyDraftChanged_(); + return; + } + + const bool committed = state.CommitEllipse(point); + if (committed) + { + NotifyGeometryChanged_(); + } + NotifyDraftChanged_(); +} + +void SolidSectionEllipseOperation::OnPointerMove(const PointerEvent& e) +{ + if (!IsActive_() || !m_spContext || !m_spContext->pSketchEditState) + { + return; + } + + const SolidSketchEllipseDraft& draft = m_spContext->pSketchEditState->GetEllipseDraft(); + if (!draft.Active) + { + return; + } + + SketchPoint2d point; + if (!TryProjectPointerToSectionPoint(*m_spContext, e, point)) + { + return; + } + + m_spContext->pSketchEditState->UpdateEllipse(point); + NotifyDraftChanged_(); +} + +void SolidSectionEllipseOperation::OnPointerUp(const PointerEvent& e) +{ + (void)e; +} + +void SolidSectionEllipseOperation::OnCancel() +{ + if (!m_spContext || !m_spContext->pSketchEditState) + { + FinishCancelled_(); + return; + } + + if (m_spContext->pSketchEditState->GetEllipseDraft().Active) + { + m_spContext->pSketchEditState->CancelDraft(); + ClearFeedback_(); + NotifyDraftChanged_(); + return; + } + + ClearFeedback_(); + FinishCancelled_(); +} + +bool SolidSectionEllipseOperation::OnKeyDown(const KeyEvent& e) +{ + if (static_cast(e.key) != InputKeyCode::Escape) + { + return false; + } + OnCancel(); + return true; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionEllipseOperation.h b/Designer/Interaction/SolidDesignerInteraction/SolidSectionEllipseOperation.h new file mode 100644 index 00000000..d2d08de3 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionEllipseOperation.h @@ -0,0 +1,19 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "SolidSectionCurveOperationBase.h" + +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSectionEllipseOperation final : public SolidSectionCurveOperationBase + { + public: + explicit SolidSectionEllipseOperation(std::shared_ptr context) noexcept; + ~SolidSectionEllipseOperation() override; + + void OnPointerDown(const alice::PointerEvent& e) override; + void OnPointerMove(const alice::PointerEvent& e) override; + void OnPointerUp(const alice::PointerEvent& e) override; + void OnCancel() override; + bool OnKeyDown(const alice::KeyEvent& e) override; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionLineOperation.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidSectionLineOperation.cpp new file mode 100644 index 00000000..b0520ab5 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionLineOperation.cpp @@ -0,0 +1,204 @@ +#include "SolidSectionLineOperation.h" + +using namespace sdr; +using namespace alice; + +namespace +{ + static bool IsLeftButtonDown_(const PointerEvent& e) + { + return (e.buttons & 1u) != 0u; + } +} +#if 0 +SolidSectionLineOperation::SolidSectionLineOperation(std::shared_ptr context) noexcept + : SolidSectionCurveOperationBase(std::move(context)) +{ +} + +SolidSectionLineOperation::~SolidSectionLineOperation() = default; + +void SolidSectionLineOperation::OnPointerDown(const PointerEvent& e) +{ + if (!IsLeftButtonDown_(e) || !IsActive_() || !m_spContext || !m_spContext->pSketchEditState) + { + return; + } + + SketchPoint2d point; + if (!TryProjectPointerToSectionPoint(*m_spContext, e, point)) + { + return; + } + + SolidSketchEditState& state = *m_spContext->pSketchEditState; + const SolidSketchLineDraft& draft = state.GetLineDraft(); + if (!draft.Active) + { + state.BeginLine(point); + NotifyDraftChanged_(); + return; + } + + const bool committed = state.CommitLine(point); + if (committed) + { + NotifyGeometryChanged_(); + state.BeginLine(point); + } + NotifyDraftChanged_(); +} + +void SolidSectionLineOperation::OnPointerMove(const PointerEvent& e) +{ + if (!IsActive_() || !m_spContext || !m_spContext->pSketchEditState) + { + return; + } + + const SolidSketchLineDraft& draft = m_spContext->pSketchEditState->GetLineDraft(); + if (!draft.Active) + { + return; + } + + SketchPoint2d point; + if (!TryProjectPointerToSectionPoint(*m_spContext, e, point)) + { + return; + } + + m_spContext->pSketchEditState->UpdateLine(point); + NotifyDraftChanged_(); +} + +void SolidSectionLineOperation::OnPointerUp(const PointerEvent& e) +{ + (void)e; +} + +void SolidSectionLineOperation::OnCancel() +{ + if (!m_spContext || !m_spContext->pSketchEditState) + { + FinishCancelled_(); + return; + } + + if (m_spContext->pSketchEditState->GetLineDraft().Active) + { + m_spContext->pSketchEditState->CancelDraft(); + ClearFeedback_(); + NotifyDraftChanged_(); + return; + } + + ClearFeedback_(); + FinishCancelled_(); +} + +bool SolidSectionLineOperation::OnKeyDown(const KeyEvent& e) +{ + if (static_cast(e.key) != InputKeyCode::Escape) + { + return false; + } + OnCancel(); + return true; +} +#endif + + +SolidSectionLineOperation::SolidSectionLineOperation(std::shared_ptr context) noexcept + : SolidSectionCurveOperationBase(std::move(context)) +{ +} + +SolidSectionLineOperation::~SolidSectionLineOperation() = default; + +void SolidSectionLineOperation::OnPointerDown(const PointerEvent& e) +{ + if ((e.buttons & 1u) == 0u || !IsActive_()) + { + return; + } + + SketchPoint2d point; + if (!TryProjectPointerToSectionPoint(*m_spContext, e, point)) + { + return; + } + + SolidSketchEditState* const pState = m_spContext ? m_spContext->pSketchEditState : nullptr; + if (pState == nullptr) + { + return; + } + + const SolidSketchLineDraft& draft = pState->GetLineDraft(); + + // 第一次点击:仅确定起点,进入预览状态 + if (!draft.Active) + { + pState->BeginLine(point); + + NotifyDraftChanged_(); + return; + } + + // 第二次点击:提交当前线段 + const bool committed = pState->CommitLine(point); + if (!committed) + { + // 无效输入不应直接退工具, + // 只保留当前工具继续等待下一次有效输入。 + + NotifyDraftChanged_(); + return; + } + + // 提交成功:同步正式草图数据 + NotifyGeometryChanged_(); + + // 连续画线:终点自动作为下一段起点 + pState->BeginLine(point); + + NotifyDraftChanged_(); +} + +void SolidSectionLineOperation::OnPointerMove(const PointerEvent& e) +{ + if (!IsActive_() || !m_spContext) + { + return; + } + + SolidSketchEditState* const pState = m_spContext ? m_spContext->pSketchEditState : nullptr; + if (pState == nullptr) + { + return; + } + + if (!pState->GetLineDraft().Active) + { + return; + } + + SketchPoint2d point; + if (!TryProjectPointerToSectionPoint(*m_spContext, e, point)) + { + return; + } + + pState->UpdateLine(point); + + NotifyDraftChanged_(); +} + +void SolidSectionLineOperation::OnPointerUp(const PointerEvent& e) +{ + (void)e; + // 关键:不要在 PointerUp 提交。 + // 否则第一次点击会立刻 BeginLine + CommitLine, + // 起点终点几乎重合,工具会自我取消,线永远画不出来。 +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionLineOperation.h b/Designer/Interaction/SolidDesignerInteraction/SolidSectionLineOperation.h new file mode 100644 index 00000000..82c5517c --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionLineOperation.h @@ -0,0 +1,19 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "SolidSectionCurveOperationBase.h" + +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSectionLineOperation final : public SolidSectionCurveOperationBase + { + public: + explicit SolidSectionLineOperation(std::shared_ptr context) noexcept; + ~SolidSectionLineOperation() override; + + void OnPointerDown(const alice::PointerEvent& e) override; + void OnPointerMove(const alice::PointerEvent& e) override; + void OnPointerUp(const alice::PointerEvent& e) override; + //void OnCancel() override; + //bool OnKeyDown(const alice::KeyEvent& e) override; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionOperationResults.h b/Designer/Interaction/SolidDesignerInteraction/SolidSectionOperationResults.h new file mode 100644 index 00000000..5d39a96c --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionOperationResults.h @@ -0,0 +1,41 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "AliceOperationResult.h" +#include "AliceObjectId.h" +#include "SolidSketchPlacementContext.h" +#include "SolidSketchSectionTypes.h" +#include "SolidSketchEditState.h" + +namespace alice +{ + class ISketch; +} + +namespace sdr +{ + struct SOLID_DESIGNER_INTERACTION_EXPORT SolidSectionPlacementResultData final : public alice::IOperationOutputData + { + bool Accepted = false; + SolidSketchPlacementContext PlacementContext{}; + SolidSketchSectionInput SectionInput{}; + std::string ErrorText; + + std::unique_ptr Clone() const override + { + return std::make_unique(*this); + } + }; + + struct SOLID_DESIGNER_INTERACTION_EXPORT SolidSectionEditResultData final : public alice::IOperationOutputData + { + bool Accepted = false; + std::shared_ptr Sketch; + SolidSketchSectionAnalysis Analysis{}; + std::string ErrorText; + + std::unique_ptr Clone() const override + { + return std::make_unique(*this); + } + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionPickFilters.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidSectionPickFilters.cpp new file mode 100644 index 00000000..81e79a14 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionPickFilters.cpp @@ -0,0 +1,16 @@ +#include "SolidSectionPickFilters.h" + +using namespace sdr; +using namespace alice; + +void SolidSketchPlanePickFilter::ConfigurePickTargets(PickTargetOptions& ioOptions) const { m_filter.ConfigurePickTargets(ioOptions); } +bool SolidSketchPlanePickFilter::AllowHit(const PickHit& hit) const { return m_filter.AllowHit(hit); } +bool SolidSketchPlanePickFilter::AllowRepresentationNode(const RepresentationNodeReference& node) const { return m_filter.AllowRepresentationNode(node); } + +void SolidOrientationReferencePickFilter::ConfigurePickTargets(PickTargetOptions& ioOptions) const { m_filter.ConfigurePickTargets(ioOptions); } +bool SolidOrientationReferencePickFilter::AllowHit(const PickHit& hit) const { return m_filter.AllowHit(hit); } +bool SolidOrientationReferencePickFilter::AllowRepresentationNode(const RepresentationNodeReference& node) const { return m_filter.AllowRepresentationNode(node); } + +void SolidExistingSketchPickFilter::ConfigurePickTargets(PickTargetOptions& ioOptions) const { m_filter.ConfigurePickTargets(ioOptions); } +bool SolidExistingSketchPickFilter::AllowHit(const PickHit& hit) const { return m_filter.AllowHit(hit); } +bool SolidExistingSketchPickFilter::AllowRepresentationNode(const RepresentationNodeReference& node) const { return m_filter.AllowRepresentationNode(node); } diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionPickFilters.h b/Designer/Interaction/SolidDesignerInteraction/SolidSectionPickFilters.h new file mode 100644 index 00000000..f8b4d0ad --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionPickFilters.h @@ -0,0 +1,39 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "SolidPickFilters.h" +#include "AliceIPickingManager.h" + +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSketchPlanePickFilter final : public alice::IPickFilter + { + public: + void ConfigurePickTargets(alice::PickTargetOptions& ioOptions) const override; + bool AllowHit(const alice::PickHit& hit) const override; + bool AllowRepresentationNode(const alice::RepresentationNodeReference& node) const override; + private: + SolidSemanticPickFilter m_filter{ SolidPickIntent::SketchPlaneInput }; + }; + + class SOLID_DESIGNER_INTERACTION_EXPORT SolidOrientationReferencePickFilter final : public alice::IPickFilter + { + public: + void ConfigurePickTargets(alice::PickTargetOptions& ioOptions) const override; + bool AllowHit(const alice::PickHit& hit) const override; + bool AllowRepresentationNode(const alice::RepresentationNodeReference& node) const override; + private: + SolidSemanticPickFilter m_filter{ SolidPickIntent::OrientationReferenceInput }; + }; + + class SOLID_DESIGNER_INTERACTION_EXPORT SolidExistingSketchPickFilter final : public alice::IPickFilter + { + public: + void ConfigurePickTargets(alice::PickTargetOptions& ioOptions) const override; + bool AllowHit(const alice::PickHit& hit) const override; + bool AllowRepresentationNode(const alice::RepresentationNodeReference& node) const override; + private: + SolidSemanticPickFilter m_filter{{ alice::PickHitKind::SketchRegion, alice::PickHitKind::SketchCurve, alice::PickHitKind::Object, alice::PickHitKind::FeatureResult }, + { alice::SemanticRoleKind::SketchRegion, alice::SemanticRoleKind::SketchCurve, alice::SemanticRoleKind::SketchPoint }, + true}; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionPlacementOperation.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidSectionPlacementOperation.cpp new file mode 100644 index 00000000..37d53b1a --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionPlacementOperation.cpp @@ -0,0 +1,109 @@ +#include "SolidSectionPlacementOperation.h" + +#include "AlicePickReferenceOperation.h" +#include "SolidSectionPickFilters.h" +#include "AliceIUiView.h" + +using namespace sdr; +using namespace alice; + +SolidSectionPlacementOperation::SolidSectionPlacementOperation(ObjectId preselectedPlaneId, + std::string preselectedPlaneKey, + std::string preselectedPlaneRole) + : m_idSketchPlane(preselectedPlaneId) + , m_strSketchPlaneKey(std::move(preselectedPlaneKey)) + , m_strSketchPlaneRole(std::move(preselectedPlaneRole)) + , m_bPickedPlane(preselectedPlaneId.IsValid()) +{ +} + +SolidSectionPlacementOperation::~SolidSectionPlacementOperation() = default; + +void SolidSectionPlacementOperation::InitOperation(IUiView* pCurrentView) +{ + SolidAuthoringOperationBase::InitOperation(pCurrentView); + if (m_bPickedPlane) + { + (void)BeginPickOrientationReference_(); + return; + } + (void)BeginPickSketchPlane_(); +} + +void SolidSectionPlacementOperation::OnCancel() +{ + SolidSectionPlacementResultData data; + data.Accepted = false; + OperationResult result = OperationResult::Cancelled(OperationFinishReason::Esc); + result.Payload = std::make_unique(data); + SetOperationResult(std::move(result)); +} + +void SolidSectionPlacementOperation::OnChildOperationFinished(const OperationResult& result) +{ + const auto* const pPick = dynamic_cast(result.Payload.get()); + if (result.FinishStatus != OperationFinishStatus::Successful || !pPick || pPick->Cancelled || !pPick->ReferenceId.IsValid()) + { + SetOperationResult(result); + return; + } + + if (!m_bPickedPlane) + { + m_idSketchPlane = pPick->ReferenceId; + m_strSketchPlaneKey = pPick->SelectionKey; + m_strSketchPlaneRole = pPick->SemanticRole; + m_bPickedPlane = true; + (void)BeginPickOrientationReference_(); + return; + } + + m_idOrientationReference = pPick->ReferenceId; + m_strOrientationKey = pPick->SelectionKey; + m_strOrientationRole = pPick->SemanticRole; + CompleteAccepted_(); +} + +bool SolidSectionPlacementOperation::BeginPickSketchPlane_() +{ + PickReferenceInputData input; + input.PromptText = "Select sketch plane."; + input.AllowPreselection = true; + return StartChildOperation(std::make_unique(input, std::make_shared())); +} + +bool SolidSectionPlacementOperation::BeginPickOrientationReference_() +{ + PickReferenceInputData input; + input.PromptText = "Select orientation reference."; + input.AllowPreselection = true; + return StartChildOperation(std::make_unique(input, std::make_shared())); +} + +void SolidSectionPlacementOperation::CompleteAccepted_() +{ + SolidSectionPlacementResultData data; + data.Accepted = m_idSketchPlane.IsValid(); + data.SectionInput.SketchPlaneReferenceId = m_idSketchPlane; + data.SectionInput.PlacementReferenceId = m_idOrientationReference; + data.SectionInput.SketchPlaneGraphicToken = m_strSketchPlaneKey; + data.SectionInput.SketchPlaneGraphicRole = m_strSketchPlaneRole; + data.SectionInput.PlacementReferenceGraphicToken = m_strOrientationKey; + data.SectionInput.PlacementReferenceGraphicRole = m_strOrientationRole; + data.PlacementContext.SketchPlaneId = m_idSketchPlane; + data.PlacementContext.PlacementReferenceId = m_idOrientationReference; + + OperationResult result = OperationResult::Successful(OperationFinishReason::PointerAccept); + result.Payload = std::make_unique(data); + SetOperationResult(std::move(result)); +} + +void SolidSectionPlacementOperation::CompleteFailed_(const std::string& errorText) +{ + SolidSectionPlacementResultData data; + data.Accepted = false; + data.ErrorText = errorText; + OperationResult result = OperationResult::Failed(OperationFinishReason::ValidationFailed, errorText); + result.Payload = std::make_unique(data); + SetOperationResult(std::move(result)); +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionPlacementOperation.h b/Designer/Interaction/SolidDesignerInteraction/SolidSectionPlacementOperation.h new file mode 100644 index 00000000..2577c729 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionPlacementOperation.h @@ -0,0 +1,37 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "SolidAuthoringOperationBase.h" +#include "AliceObjectId.h" +#include "AlicePickReferenceOperation.h" +#include "SolidSectionOperationResults.h" + +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSectionPlacementOperation final : public SolidAuthoringOperationBase + { + public: + SolidSectionPlacementOperation(alice::ObjectId preselectedPlaneId = {}, + std::string preselectedPlaneKey = {}, + std::string preselectedPlaneRole = {}); + ~SolidSectionPlacementOperation() override; + + void InitOperation(alice::IUiView* pCurrentView) override; + void OnCancel() override; + void OnChildOperationFinished(const alice::OperationResult& result) override; + + private: + bool BeginPickSketchPlane_(); + bool BeginPickOrientationReference_(); + void CompleteAccepted_(); + void CompleteFailed_(const std::string& errorText); + + private: + alice::ObjectId m_idSketchPlane; + alice::ObjectId m_idOrientationReference; + std::string m_strSketchPlaneKey; + std::string m_strSketchPlaneRole; + std::string m_strOrientationKey; + std::string m_strOrientationRole; + bool m_bPickedPlane = false; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionRectangleOperation.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidSectionRectangleOperation.cpp new file mode 100644 index 00000000..ab40dd83 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionRectangleOperation.cpp @@ -0,0 +1,107 @@ +#include "SolidSectionRectangleOperation.h" + +using namespace sdr; +using namespace alice; + +namespace +{ + static bool IsLeftButtonDown_(const PointerEvent& e) + { + return (e.buttons & 1u) != 0u; + } +} + +SolidSectionRectangleOperation::SolidSectionRectangleOperation(std::shared_ptr context) noexcept + : SolidSectionCurveOperationBase(std::move(context)) +{ +} + +SolidSectionRectangleOperation::~SolidSectionRectangleOperation() = default; + +void SolidSectionRectangleOperation::OnPointerDown(const PointerEvent& e) +{ + if (!IsLeftButtonDown_(e) || !IsActive_() || !m_spContext || !m_spContext->pSketchEditState) + { + return; + } + + SketchPoint2d point; + if (!TryProjectPointerToSectionPoint(*m_spContext, e, point)) + { + return; + } + + SolidSketchEditState& state = *m_spContext->pSketchEditState; + const SolidSketchRectangleDraft& draft = state.GetRectangleDraft(); + if (!draft.Active) + { + state.BeginRectangle(point); + NotifyDraftChanged_(); + return; + } + + const bool committed = state.CommitRectangle(point); + if (committed) + { + NotifyGeometryChanged_(); + } + NotifyDraftChanged_(); +} + +void SolidSectionRectangleOperation::OnPointerMove(const PointerEvent& e) +{ + if (!IsActive_() || !m_spContext || !m_spContext->pSketchEditState) + { + return; + } + + const SolidSketchRectangleDraft& draft = m_spContext->pSketchEditState->GetRectangleDraft(); + if (!draft.Active) + { + return; + } + + SketchPoint2d point; + if (!TryProjectPointerToSectionPoint(*m_spContext, e, point)) + { + return; + } + + m_spContext->pSketchEditState->UpdateRectangle(point); + NotifyDraftChanged_(); +} + +void SolidSectionRectangleOperation::OnPointerUp(const PointerEvent& e) +{ + (void)e; +} + +void SolidSectionRectangleOperation::OnCancel() +{ + if (!m_spContext || !m_spContext->pSketchEditState) + { + FinishCancelled_(); + return; + } + + if (m_spContext->pSketchEditState->GetRectangleDraft().Active) + { + m_spContext->pSketchEditState->CancelDraft(); + ClearFeedback_(); + NotifyDraftChanged_(); + return; + } + + ClearFeedback_(); + FinishCancelled_(); +} + +bool SolidSectionRectangleOperation::OnKeyDown(const KeyEvent& e) +{ + if (static_cast(e.key) != InputKeyCode::Escape) + { + return false; + } + OnCancel(); + return true; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSectionRectangleOperation.h b/Designer/Interaction/SolidDesignerInteraction/SolidSectionRectangleOperation.h new file mode 100644 index 00000000..399e947a --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSectionRectangleOperation.h @@ -0,0 +1,19 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "SolidSectionCurveOperationBase.h" + +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSectionRectangleOperation final : public SolidSectionCurveOperationBase + { + public: + explicit SolidSectionRectangleOperation(std::shared_ptr context) noexcept; + ~SolidSectionRectangleOperation() override; + + void OnPointerDown(const alice::PointerEvent& e) override; + void OnPointerMove(const alice::PointerEvent& e) override; + void OnPointerUp(const alice::PointerEvent& e) override; + void OnCancel() override; + bool OnKeyDown(const alice::KeyEvent& e) override; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSketchConstraintOperation.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidSketchConstraintOperation.cpp new file mode 100644 index 00000000..f494c585 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSketchConstraintOperation.cpp @@ -0,0 +1,27 @@ +#include "SolidSketchConstraintOperation.h" + +#include "AliceCoreAppUtil.h" +#include "SolidSectionEditOperation.h" + +using namespace sdr; + +SolidSketchConstraintOperation::SolidSketchConstraintOperation(std::string constraintKind) noexcept + : m_strConstraintKind(std::move(constraintKind)) +{} + +SolidSketchConstraintOperation::~SolidSketchConstraintOperation() = default; + +void SolidSketchConstraintOperation::InitOperation(alice::IUiView* pCurrentView) +{ + alice::OperationBase::InitOperation(pCurrentView); + if (auto* const pSectionOperation = SolidSectionEditOperation::FindActive(alice::CoreAppUtil::GetCurrentSession())) + { + pSectionOperation->ExecuteConstraintCommand(); + } + m_bFinished = true; +} + +bool SolidSketchConstraintOperation::IsFinished() const noexcept +{ + return m_bFinished; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSketchConstraintOperation.h b/Designer/Interaction/SolidDesignerInteraction/SolidSketchConstraintOperation.h new file mode 100644 index 00000000..45e9e3c4 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSketchConstraintOperation.h @@ -0,0 +1,18 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "AliceOperationBase.h" +#include +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSketchConstraintOperation final : public alice::OperationBase + { + public: + explicit SolidSketchConstraintOperation(std::string constraintKind = "constraint") noexcept; + ~SolidSketchConstraintOperation() override; + void InitOperation(alice::IUiView* pCurrentView) override; + bool IsFinished() const noexcept override; + private: + std::string m_strConstraintKind; + bool m_bFinished{ false }; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSketchDimensionOperation.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidSketchDimensionOperation.cpp new file mode 100644 index 00000000..16c9278e --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSketchDimensionOperation.cpp @@ -0,0 +1,27 @@ +#include "SolidSketchDimensionOperation.h" + +#include "AliceCoreAppUtil.h" +#include "SolidSectionEditOperation.h" + +using namespace sdr; + +SolidSketchDimensionOperation::SolidSketchDimensionOperation(std::string dimensionKind) noexcept + : m_strDimensionKind(std::move(dimensionKind)) +{} + +SolidSketchDimensionOperation::~SolidSketchDimensionOperation() = default; + +void SolidSketchDimensionOperation::InitOperation(alice::IUiView* pCurrentView) +{ + alice::OperationBase::InitOperation(pCurrentView); + if (auto* const pSectionOperation = SolidSectionEditOperation::FindActive(alice::CoreAppUtil::GetCurrentSession())) + { + pSectionOperation->ExecuteDimensionCommand(); + } + m_bFinished = true; +} + +bool SolidSketchDimensionOperation::IsFinished() const noexcept +{ + return m_bFinished; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSketchDimensionOperation.h b/Designer/Interaction/SolidDesignerInteraction/SolidSketchDimensionOperation.h new file mode 100644 index 00000000..3435eb52 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSketchDimensionOperation.h @@ -0,0 +1,18 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "AliceOperationBase.h" +#include +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSketchDimensionOperation final : public alice::OperationBase + { + public: + explicit SolidSketchDimensionOperation(std::string dimensionKind = "dimension") noexcept; + ~SolidSketchDimensionOperation() override; + void InitOperation(alice::IUiView* pCurrentView) override; + bool IsFinished() const noexcept override; + private: + std::string m_strDimensionKind; + bool m_bFinished{ false }; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSketchEditState.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidSketchEditState.cpp new file mode 100644 index 00000000..de1c483e --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSketchEditState.cpp @@ -0,0 +1,644 @@ +#include "SolidSketchEditState.h" + +#include "AliceSketchSectionAnalyzer.h" +#include "AliceSketchObjectModel.h" +#include "AliceISketchCurve.h" +#include "AliceISketchLine.h" +#include "AliceISketchCircle.h" +#include "AliceISketchArc.h" +#include "AliceISketchEllipse.h" + +#include +#include +#include +#include + +using namespace sdr; +using namespace alice; + +namespace +{ + constexpr double kTwoPi = 6.28318530717958647692; + + static double SegmentLength_(const SketchPoint2d& a, const SketchPoint2d& b) + { + const double dx = b.X() - a.X(); + const double dy = b.Y() - a.Y(); + return std::sqrt(dx * dx + dy * dy); + } + + static double Distance_(const SketchPoint2d& a, const SketchPoint2d& b) + { + return SegmentLength_(a, b); + } + + static double NormalizeAngle_(double angle) + { + while (angle < 0.0) + { + angle += kTwoPi; + } + while (angle >= kTwoPi) + { + angle -= kTwoPi; + } + return angle; + } + + static double PositiveSweep_(double startAngle, double endAngle) + { + const double s = NormalizeAngle_(startAngle); + const double e = NormalizeAngle_(endAngle); + return e >= s ? e - s : (kTwoPi - s) + e; + } + + static std::string BuildCurveBindingKey_(const char* prefix, const Guid& curveId) + { + return std::string(prefix) + GuidUtils::ToString(curveId); + } + + static std::string BuildCurveSelectionKey_(const Guid& curveId) + { + return BuildCurveBindingKey_("sketchcurve:", curveId); + } + + static std::string BuildCurveDisplayKey_(const Guid& curveId) + { + return BuildCurveBindingKey_("sketchdisplay:", curveId); + } + + static std::string BuildCurveSolverKey_(const Guid& curveId) + { + return BuildCurveBindingKey_("sketchsolver:", curveId); + } + + static void EnsureCurveHeaderBindingKeys_(SketchSemanticEntityHeader& header) + { + if (!GuidUtils::IsValid(header.Id)) + { + header.Id = GuidUtils::Generate(); + } + if (header.SelectionBindingKey.empty()) + { + header.SelectionBindingKey = BuildCurveSelectionKey_(header.Id); + } + if (header.DisplayBindingKey.empty()) + { + header.DisplayBindingKey = BuildCurveDisplayKey_(header.Id); + } + if (header.SolverBindingKey.empty()) + { + header.SolverBindingKey = BuildCurveSolverKey_(header.Id); + } + } + + template + static void EnsureCurveBindingKeys_(TCurveContainer& curves) + { + for (auto& curve : curves) + { + EnsureCurveHeaderBindingKeys_(curve.Header); + } + } + + static bool ParseIndexedToken_(const std::string& token, const char* prefix, std::size_t& outIndex) + { + const std::string expectedPrefix = std::string(prefix) + "."; + if (token.rfind(expectedPrefix, 0) != 0) + { + return false; + } + + const std::size_t dot = token.find('.', expectedPrefix.size()); + const std::string indexText = token.substr(expectedPrefix.size(), + dot == std::string::npos ? std::string::npos : dot - expectedPrefix.size()); + if (indexText.empty()) + { + return false; + } + + try + { + outIndex = static_cast(std::stoull(indexText)); + return true; + } + catch (...) + { + return false; + } + } + + static std::string NormalizeEntityToken_(std::string token) + { + const std::size_t pointPos = token.find(".point."); + if (pointPos != std::string::npos) + { + token.erase(pointPos); + } + return token; + } + + static bool TryParseCurveSelectionGuid_(const std::string& token, Guid& outGuid) + { + const std::string normalized = NormalizeEntityToken_(token); + constexpr const char* prefix = "sketchcurve:"; + if (normalized.rfind(prefix, 0) != 0) + { + return false; + } + outGuid = GuidUtils::FromString(normalized.substr(std::char_traits::length(prefix))); + return GuidUtils::IsValid(outGuid); + } +} + +SolidSketchEditState::SolidSketchEditState() + : m_spSketch(std::make_shared()) +{ + EnsureSketch_().SetId(GuidUtils::Generate()); +} + +SolidSketchEditState::~SolidSketchEditState() = default; + +void SolidSketchEditState::Reset() +{ + const ObjectId planeId = GetSketchRef_().GetOwnerPlaneId(); + m_spSketch = std::make_shared(); + EnsureSketch_().SetId(GuidUtils::Generate()); + EnsureSketch_().SetOwnerPlaneId(planeId); + m_tool = SolidSketchToolKind::Line; + CancelDraft(); +} + +void SolidSketchEditState::SetSketchPlaneReferenceId(const ObjectId& id) +{ + EnsureSketch_().SetOwnerPlaneId(id); +} + +void SolidSketchEditState::SetPlacementReferenceId(const ObjectId& id) +{ + EnsureSketch_().SetPlacementReferenceId(id); +} + +std::shared_ptr SolidSketchEditState::GetSketch() const noexcept +{ + return m_spSketch; +} + +void SolidSketchEditState::SetActiveTool(SolidSketchToolKind tool) noexcept +{ + m_tool = tool; +} + +SolidSketchToolKind SolidSketchEditState::GetActiveTool() const noexcept +{ + return m_tool; +} + +void SolidSketchEditState::BeginLine(const SketchPoint2d& point) +{ + CancelDraft(); + m_lineDraft.Active = true; + m_lineDraft.Start = point; + m_lineDraft.Current = point; +} + +void SolidSketchEditState::UpdateLine(const SketchPoint2d& point) +{ + if (m_lineDraft.Active) + { + m_lineDraft.Current = point; + } +} + +bool SolidSketchEditState::CommitLine(const SketchPoint2d& point, double minLength) +{ + if (!m_lineDraft.Active) + { + return false; + } + + m_lineDraft.Current = point; + if (SegmentLength_(m_lineDraft.Start, m_lineDraft.Current) <= minLength) + { + return false; + } + + auto curve = std::make_shared(); + auto& data = curve->GetDataFw(); + data.Start = m_lineDraft.Start; + data.End = m_lineDraft.Current; + data.Header.Name = L"Line"; + EnsureCurveHeaderBindingKeys_(data.Header); + EnsureSketch_().AddCurve(curve); + + m_lineDraft = {}; + return true; +} + +const SolidSketchLineDraft& SolidSketchEditState::GetLineDraft() const noexcept +{ + return m_lineDraft; +} + +void SolidSketchEditState::BeginCircle(const SketchPoint2d& center) +{ + CancelDraft(); + m_circleDraft.Active = true; + m_circleDraft.Center = center; + m_circleDraft.Current = center; +} + +void SolidSketchEditState::UpdateCircle(const SketchPoint2d& point) +{ + if (m_circleDraft.Active) + { + m_circleDraft.Current = point; + } +} + +bool SolidSketchEditState::CommitCircle(const SketchPoint2d& point, double minRadius) +{ + if (!m_circleDraft.Active) + { + return false; + } + + m_circleDraft.Current = point; + const double radius = Distance_(m_circleDraft.Center, m_circleDraft.Current); + if (radius <= minRadius) + { + return false; + } + + auto curve = std::make_shared(); + auto& data = curve->GetDataFw(); + data.Center = m_circleDraft.Center; + data.Radius = radius; + data.Header.Name = L"Circle"; + EnsureCurveHeaderBindingKeys_(data.Header); + EnsureSketch_().AddCurve(curve); + + m_circleDraft = {}; + return true; +} + +const SolidSketchCircleDraft& SolidSketchEditState::GetCircleDraft() const noexcept +{ + return m_circleDraft; +} + +void SolidSketchEditState::BeginArc(const SketchPoint2d& center) +{ + CancelDraft(); + m_arcDraft.Active = true; + m_arcDraft.Step = 1; + m_arcDraft.Center = center; + m_arcDraft.Start = center; + m_arcDraft.Current = center; +} + +void SolidSketchEditState::UpdateArc(const SketchPoint2d& point) +{ + if (m_arcDraft.Active) + { + m_arcDraft.Current = point; + } +} + +bool SolidSketchEditState::AdvanceArc(const SketchPoint2d& point, double minRadius) +{ + if (!m_arcDraft.Active || m_arcDraft.Step != 1) + { + return false; + } + if (Distance_(m_arcDraft.Center, point) <= minRadius) + { + return false; + } + + m_arcDraft.Start = point; + m_arcDraft.Current = point; + m_arcDraft.Step = 2; + return true; +} + +bool SolidSketchEditState::CommitArc(const SketchPoint2d& point, double minSweepRad) +{ + if (!m_arcDraft.Active || m_arcDraft.Step != 2) + { + return false; + } + + const double radius = Distance_(m_arcDraft.Center, m_arcDraft.Start); + if (radius <= 1.0e-9) + { + return false; + } + + const double startAngle = std::atan2(m_arcDraft.Start.Y() - m_arcDraft.Center.Y(), + m_arcDraft.Start.X() - m_arcDraft.Center.X()); + const double endAngle = std::atan2(point.Y() - m_arcDraft.Center.Y(), + point.X() - m_arcDraft.Center.X()); + if (PositiveSweep_(startAngle, endAngle) <= minSweepRad) + { + return false; + } + + auto curve = std::make_shared(); + auto& data = curve->GetDataFw(); + data.Center = m_arcDraft.Center; + data.Radius = radius; + data.StartAngleRad = NormalizeAngle_(startAngle); + data.EndAngleRad = NormalizeAngle_(endAngle); + data.Header.Name = L"Arc"; + EnsureCurveHeaderBindingKeys_(data.Header); + EnsureSketch_().AddCurve(curve); + + m_arcDraft = {}; + return true; +} + +const SolidSketchArcDraft& SolidSketchEditState::GetArcDraft() const noexcept +{ + return m_arcDraft; +} + +void SolidSketchEditState::BeginRectangle(const SketchPoint2d& point) +{ + CancelDraft(); + m_rectangleDraft.Active = true; + m_rectangleDraft.Corner0 = point; + m_rectangleDraft.Corner1 = point; +} + +void SolidSketchEditState::UpdateRectangle(const SketchPoint2d& point) +{ + if (m_rectangleDraft.Active) + { + m_rectangleDraft.Corner1 = point; + } +} + +bool SolidSketchEditState::CommitRectangle(const SketchPoint2d& point, double minSide) +{ + if (!m_rectangleDraft.Active) + { + return false; + } + + m_rectangleDraft.Corner1 = point; + const double minX = std::min(m_rectangleDraft.Corner0.X(), m_rectangleDraft.Corner1.X()); + const double minY = std::min(m_rectangleDraft.Corner0.Y(), m_rectangleDraft.Corner1.Y()); + const double maxX = std::max(m_rectangleDraft.Corner0.X(), m_rectangleDraft.Corner1.X()); + const double maxY = std::max(m_rectangleDraft.Corner0.Y(), m_rectangleDraft.Corner1.Y()); + if ((maxX - minX) <= minSide || (maxY - minY) <= minSide) + { + return false; + } + + const std::array corners{ + SketchPoint2d{ minX, minY }, + SketchPoint2d{ maxX, minY }, + SketchPoint2d{ maxX, maxY }, + SketchPoint2d{ minX, maxY } + }; + + SketchProfileLoopDefinitionData loop; + loop.Id = GuidUtils::Generate(); + loop.Name = L"RectangleProfile"; + loop.IsClosed = true; + + for (int i = 0; i < 4; ++i) + { + auto curve = std::make_shared(); + auto& data = curve->GetDataFw(); + data.Start = corners[i]; + data.End = corners[(i + 1) % 4]; + data.Header.Name = L"RectangleEdge"; + EnsureCurveHeaderBindingKeys_(data.Header); + loop.CurveIds.push_back(data.Header.Id); + EnsureSketch_().AddCurve(curve); + } + + EnsureSketch_().AddProfile(std::make_shared(loop)); + m_rectangleDraft = {}; + return true; +} + +const SolidSketchRectangleDraft& SolidSketchEditState::GetRectangleDraft() const noexcept +{ + return m_rectangleDraft; +} + +void SolidSketchEditState::BeginEllipse(const SketchPoint2d& center) +{ + CancelDraft(); + m_ellipseDraft.Active = true; + m_ellipseDraft.Center = center; + m_ellipseDraft.Current = center; +} + +void SolidSketchEditState::UpdateEllipse(const SketchPoint2d& point) +{ + if (m_ellipseDraft.Active) + { + m_ellipseDraft.Current = point; + } +} + +bool SolidSketchEditState::CommitEllipse(const SketchPoint2d& point, double minRadius) +{ + if (!m_ellipseDraft.Active) + { + return false; + } + + m_ellipseDraft.Current = point; + const double rx = std::abs(point.X() - m_ellipseDraft.Center.X()); + const double ry = std::abs(point.Y() - m_ellipseDraft.Center.Y()); + if (rx <= minRadius || ry <= minRadius) + { + return false; + } + + auto curve = std::make_shared(); + auto& data = curve->GetDataFw(); + data.Center = m_ellipseDraft.Center; + data.RadiusX = rx; + data.RadiusY = ry; + data.RotationRad = 0.0; + data.Header.Name = L"Ellipse"; + EnsureCurveHeaderBindingKeys_(data.Header); + EnsureSketch_().AddCurve(curve); + + SketchProfileLoopDefinitionData loop; + loop.Id = GuidUtils::Generate(); + loop.Name = L"EllipseProfile"; + loop.IsClosed = true; + loop.CurveIds.push_back(data.Header.Id); + EnsureSketch_().AddProfile(std::make_shared(loop)); + + m_ellipseDraft = {}; + return true; +} + +const SolidSketchEllipseDraft& SolidSketchEditState::GetEllipseDraft() const noexcept +{ + return m_ellipseDraft; +} + +bool SolidSketchEditState::HasActiveDraft() const noexcept +{ + return m_lineDraft.Active || m_circleDraft.Active || m_arcDraft.Active || m_rectangleDraft.Active || m_ellipseDraft.Active; +} + +const Guid* SolidSketchEditState::ResolveEntityGuid_(const std::string& entityToken) const noexcept +{ + if (!m_spSketch) + { + return nullptr; + } + + Guid guid{}; + if (TryParseCurveSelectionGuid_(entityToken, guid)) + { + for (const auto& curve : m_spSketch->GetCurves()) + { + if (curve && curve->GetHeader().Id == guid) + { + return &curve->GetHeader().Id; + } + } + } + + const std::string token = NormalizeEntityToken_(entityToken); + std::size_t index = 0; + if (ParseIndexedToken_(token, "line", index) || ParseIndexedToken_(token, "circle", index) || ParseIndexedToken_(token, "arc", index) || ParseIndexedToken_(token, "ellipse", index)) + { + const auto curves = m_spSketch->GetCurves(); + if (index < curves.size() && curves[index]) + { + return &curves[index]->GetHeader().Id; + } + } + return nullptr; +} + + +bool SolidSketchEditState::AddDimensionDefinition(const std::string& entityToken, + const std::wstring& kind, + double value, + bool isDriving) +{ + const Guid* pEntityId = ResolveEntityGuid_(entityToken); + if (!pEntityId) + { + return false; + } + + SketchDimensionDefinitionData d; + d.Id = GuidUtils::Generate(); + d.Kind = kind; + d.IsDriving = isDriving; + d.IsReference = !isDriving; + d.Value = value; + d.Name = L"Dimension"; + d.EntityIds.push_back(*pEntityId); + EnsureSketch_().AddDimension(d); + return true; +} + +bool SolidSketchEditState::AddConstraintDefinition(const std::vector& entityTokens, + const std::wstring& kind, + double value, + bool isDriving) +{ + SketchConstraintDefinitionData data; + data.Id = GuidUtils::Generate(); + data.Kind = kind; + data.IsDriving = isDriving; + data.IsReference = !isDriving; + data.Value = value; + data.Name = L"Constraint"; + for (const auto& token : entityTokens) + { + if (const Guid* pId = ResolveEntityGuid_(token)) + { + data.EntityIds.push_back(*pId); + } + } + if (data.EntityIds.empty()) + { + return false; + } + + EnsureSketch_().AddConstraint(std::make_shared(data)); + return true; +} + +void SolidSketchEditState::CancelDraft() noexcept +{ + m_lineDraft = {}; + m_circleDraft = {}; + m_arcDraft = {}; + m_rectangleDraft = {}; + m_ellipseDraft = {}; +} + +void SolidSketchEditState::SetSketch(const std::shared_ptr& sketch) +{ + if (!sketch) + { + m_spSketch.reset(); + CancelDraft(); + return; + } + + if (const auto concrete = std::dynamic_pointer_cast(sketch)) + { + m_spSketch = concrete; + } + else + { + m_spSketch = Sketch::CloneFrom(*sketch); + } + CancelDraft(); +} + +SolidSketchSectionAnalysis SolidSketchEditState::AnalyzeSection() const +{ + SolidSketchSectionAnalysis out; + alice::SketchSectionAnalyzer analyzer; + if (!m_spSketch) + { + return out; + } + + (void)analyzer.Analyze(*m_spSketch, + out.ClosedProfileCount, + out.OpenChainCount, + out.HasDanglingGeometry, + out.HasSelfIntersection, + out.HasZeroAreaProfile); + return out; +} + +Sketch& SolidSketchEditState::EnsureSketch_() +{ + if (!m_spSketch) + { + m_spSketch = std::make_shared(); + m_spSketch->SetId(GuidUtils::Generate()); + } + return *m_spSketch; +} + +const Sketch& SolidSketchEditState::GetSketchRef_() const +{ + if (!m_spSketch) + { + const_cast(this)->m_spSketch = std::make_shared(); + const_cast(this)->m_spSketch->SetId(GuidUtils::Generate()); + } + return *m_spSketch; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSketchEditState.h b/Designer/Interaction/SolidDesignerInteraction/SolidSketchEditState.h new file mode 100644 index 00000000..6757e663 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSketchEditState.h @@ -0,0 +1,108 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "AliceSketchSemanticTypes.h" +#include "AliceGuidUtils.h" + +#include +#include +#include +#include +#include + +namespace alice +{ + class ISketch; + class Sketch; +} + +namespace sdr +{ + enum class SolidSketchToolKind : std::uint8_t + { + Select = 0, + Line = 1, + CircleCenterPoint = 2, + ArcCenterEnds = 3, + RectangleCorner = 4, + EllipseCenterPoint = 5, + }; + + struct SolidSketchLineDraft{ bool Active=false; alice::SketchPoint2d Start; alice::SketchPoint2d Current; }; + struct SolidSketchCircleDraft{ bool Active=false; alice::SketchPoint2d Center; alice::SketchPoint2d Current; }; + struct SolidSketchArcDraft{ bool Active=false; std::uint8_t Step=0; alice::SketchPoint2d Center; alice::SketchPoint2d Start; alice::SketchPoint2d Current; }; + struct SolidSketchRectangleDraft{ bool Active=false; alice::SketchPoint2d Corner0; alice::SketchPoint2d Corner1; }; + struct SolidSketchEllipseDraft{ bool Active=false; alice::SketchPoint2d Center; alice::SketchPoint2d Current; }; + + struct SolidSketchSectionAnalysis + { + std::int64_t ClosedProfileCount = 0; + std::int64_t OpenChainCount = 0; + bool HasDanglingGeometry = false; + bool HasSelfIntersection = false; + bool HasZeroAreaProfile = false; + }; + + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSketchEditState + { + public: + SolidSketchEditState(); + ~SolidSketchEditState(); + + void Reset(); + void SetSketchPlaneReferenceId(const alice::ObjectId& id); + void SetPlacementReferenceId(const alice::ObjectId& id); + std::shared_ptr GetSketch() const noexcept; + + void SetActiveTool(SolidSketchToolKind tool) noexcept; + SolidSketchToolKind GetActiveTool() const noexcept; + + void BeginLine(const alice::SketchPoint2d& point); + void UpdateLine(const alice::SketchPoint2d& point); + bool CommitLine(const alice::SketchPoint2d& point, double minLength = 1.0e-9); + const SolidSketchLineDraft& GetLineDraft() const noexcept; + + void BeginCircle(const alice::SketchPoint2d& center); + void UpdateCircle(const alice::SketchPoint2d& point); + bool CommitCircle(const alice::SketchPoint2d& point, double minRadius = 1.0e-9); + const SolidSketchCircleDraft& GetCircleDraft() const noexcept; + + void BeginArc(const alice::SketchPoint2d& center); + void UpdateArc(const alice::SketchPoint2d& point); + bool AdvanceArc(const alice::SketchPoint2d& point, double minRadius = 1.0e-9); + bool CommitArc(const alice::SketchPoint2d& point, double minSweepRad = 1.0e-6); + const SolidSketchArcDraft& GetArcDraft() const noexcept; + + void BeginRectangle(const alice::SketchPoint2d& point); + void UpdateRectangle(const alice::SketchPoint2d& point); + bool CommitRectangle(const alice::SketchPoint2d& point, double minSide = 1.0e-9); + const SolidSketchRectangleDraft& GetRectangleDraft() const noexcept; + + void BeginEllipse(const alice::SketchPoint2d& center); + void UpdateEllipse(const alice::SketchPoint2d& point); + bool CommitEllipse(const alice::SketchPoint2d& point, double minRadius = 1.0e-9); + const SolidSketchEllipseDraft& GetEllipseDraft() const noexcept; + + bool HasActiveDraft() const noexcept; + + bool AddDimensionDefinition(const std::string& entityToken, const std::wstring& kind, double value = 0.0, bool isDriving = true); + bool AddConstraintDefinition(const std::vector& entityTokens, const std::wstring& kind, double value = 0.0, bool isDriving = true); + + void CancelDraft() noexcept; + void SetSketch(const std::shared_ptr& sketch); + SolidSketchSectionAnalysis AnalyzeSection() const; + + private: + alice::Sketch& EnsureSketch_(); + const alice::Sketch& GetSketchRef_() const; + const Guid* ResolveEntityGuid_(const std::string& entityToken) const noexcept; + + private: + std::shared_ptr m_spSketch; + SolidSketchToolKind m_tool{ SolidSketchToolKind::Line }; + SolidSketchLineDraft m_lineDraft; + SolidSketchCircleDraft m_circleDraft; + SolidSketchArcDraft m_arcDraft; + SolidSketchRectangleDraft m_rectangleDraft; + SolidSketchEllipseDraft m_ellipseDraft; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSketchInputProjector.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidSketchInputProjector.cpp new file mode 100644 index 00000000..71a9f59f --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSketchInputProjector.cpp @@ -0,0 +1,130 @@ +#include "SolidSketchInputProjector.h" + +#include +#include + +#include "AliceGeometryQuery3d.h" +#include "AliceVector3d.h" + +using namespace sdr; + +namespace +{ + static alice::Vector3d MakeVec3(double x, double y, double z) { return alice::Vector3d(x, y, z); } + static alice::Vector3d Mul(const alice::Vector3d& v, double s) { return alice::Vector3d(v.X() * s, v.Y() * s, v.Z() * s); } + static alice::Vector3d Normalize(const alice::Vector3d& v, const alice::Vector3d& fallback) + { + alice::Vector3d normalized(v); + if (normalized.Normalize() <= 1.0e-12) + { + return fallback; + } + return normalized; + } +} + +ISolidSketchInputProjector::~ISolidSketchInputProjector() = default; +SolidSketchInputProjector::SolidSketchInputProjector() = default; +SolidSketchInputProjector::~SolidSketchInputProjector() = default; + +void SolidSketchInputProjector::SetPlacementContext(const SolidSketchPlacementContext& context) +{ + m_context = context; +} + +SolidSketchPlacementContext SolidSketchInputProjector::GetPlacementContext() const +{ + return m_context; +} + +void SolidSketchInputProjector::SetPlaneAnchorFromRepresentationNodeHit(const alice::RepresentationNodeHitResult& hit) +{ + m_context.PlaneAnchorX = hit.ModelX; + m_context.PlaneAnchorY = hit.ModelY; + m_context.PlaneAnchorZ = hit.ModelZ; + m_context.HasPlaneAnchor = true; +} + +bool SolidSketchInputProjector::TryProjectScreenPointToSketch(double screenX, + double screenY, + alice::SketchPoint2d& outPoint) const +{ + const double viewportWidth = std::max(1.0, m_context.ViewportPixelWidth); + const double viewportHeight = std::max(1.0, m_context.ViewportPixelHeight); + + const alice::Vector3d eye = MakeVec3(m_context.CameraEyeX, m_context.CameraEyeY, m_context.CameraEyeZ); + const alice::Vector3d target = MakeVec3(m_context.CameraTargetX, m_context.CameraTargetY, m_context.CameraTargetZ); + const alice::Vector3d forward = Normalize(target - eye, MakeVec3(0.0, 0.0, -1.0)); + alice::Vector3d up = Normalize(MakeVec3(m_context.CameraUpX, m_context.CameraUpY, m_context.CameraUpZ), MakeVec3(0.0, 1.0, 0.0)); + alice::Vector3d right = Normalize(forward.Cross(up), MakeVec3(1.0, 0.0, 0.0)); + up = Normalize(right.Cross(forward), up); + + const alice::Vector3d planeOrigin = m_context.HasPlaneAnchor + ? MakeVec3(m_context.PlaneAnchorX, m_context.PlaneAnchorY, m_context.PlaneAnchorZ) + : target; + const alice::Vector3d planeXAxis = m_context.HasPlaneFrame + ? Normalize(MakeVec3(m_context.PlaneXAxisX, m_context.PlaneXAxisY, m_context.PlaneXAxisZ), right) + : right; + const alice::Vector3d planeYAxis = m_context.HasPlaneFrame + ? Normalize(MakeVec3(m_context.PlaneYAxisX, m_context.PlaneYAxisY, m_context.PlaneYAxisZ), up) + : up; + const alice::Vector3d planeNormal = m_context.HasPlaneFrame + ? Normalize(MakeVec3(m_context.PlaneNormalX, m_context.PlaneNormalY, m_context.PlaneNormalZ), forward) + : forward; + + const double ndcX = (screenX / viewportWidth) * 2.0 - 1.0; + const double ndcY = 1.0 - (screenY / viewportHeight) * 2.0; + const double aspect = std::max(1.0e-6, viewportWidth / viewportHeight); + + alice::Vector3d rayOrigin; + alice::Vector3d rayDirection; + if (m_context.PerspectiveProjection) + { + const double tanHalf = std::tan(std::max(1.0e-6, m_context.CameraFovYRadians) * 0.5); + const double halfHeight = tanHalf; + const double halfWidth = halfHeight * aspect; + rayOrigin = eye; + rayDirection = Normalize(forward + Mul(right, ndcX * halfWidth) + Mul(up, ndcY * halfHeight), forward); + } + else + { + // OCCT orthographic camera semantics: + // Graphic3d_Camera::Scale() is the full viewport size for aspect == 1, + // not the half-height. Therefore the visible half-height in view space + // is Scale * 0.5, and the half-width is half-height * aspect. + const double halfHeight = std::max(1.0e-6, m_context.CameraOrthoScale * 0.5); + const double halfWidth = halfHeight * aspect; + rayOrigin = eye + Mul(right, ndcX * halfWidth) + Mul(up, ndcY * halfHeight); + rayDirection = forward; + } + + double hitParameter = 0.0; + alice::Vector3d hitPoint; + if (alice::GeometryQuery3d::TryIntersectRayPlane(rayOrigin, + rayDirection, + planeOrigin, + planeNormal, + hitParameter, + hitPoint) && + hitParameter >= -1.0e-6) + { + const alice::Vector3d localDelta = hitPoint - planeOrigin; + const double projectedX = localDelta.Dot(planeXAxis); + const double projectedY = localDelta.Dot(planeYAxis); + outPoint = alice::SketchPoint2d{ m_context.FlipHorizontal ? -projectedX : projectedX, projectedY }; + return true; + } + + const double dxPixels = screenX - m_context.ScreenOriginX; + const double dyPixels = m_context.ScreenOriginY - screenY; + const double orthoScale = std::max(1.0e-6, m_context.CameraOrthoScale); + const double worldPerPixelY = m_context.PerspectiveProjection + ? std::max(1.0e-9, m_context.ScreenToModelScale) + : orthoScale / viewportHeight; + const double worldPerPixelX = worldPerPixelY * aspect; + const alice::Vector3d worldDelta = Mul(planeXAxis, dxPixels * worldPerPixelX) + Mul(planeYAxis, dyPixels * worldPerPixelY); + const double projectedX = worldDelta.Dot(planeXAxis); + outPoint = alice::SketchPoint2d{ m_context.FlipHorizontal ? -projectedX : projectedX, + worldDelta.Dot(planeYAxis) }; + return true; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSketchInputProjector.h b/Designer/Interaction/SolidDesignerInteraction/SolidSketchInputProjector.h new file mode 100644 index 00000000..c746eaa7 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSketchInputProjector.h @@ -0,0 +1,38 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "AliceSketchSemanticTypes.h" +#include "AliceIPickingManager.h" +#include "SolidSketchPlacementContext.h" + +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT ISolidSketchInputProjector + { + public: + virtual ~ISolidSketchInputProjector(); + + virtual void SetPlacementContext(const SolidSketchPlacementContext& context) = 0; + virtual SolidSketchPlacementContext GetPlacementContext() const = 0; + virtual void SetPlaneAnchorFromRepresentationNodeHit(const alice::RepresentationNodeHitResult& hit) = 0; + virtual bool TryProjectScreenPointToSketch(double screenX, + double screenY, + alice::SketchPoint2d& outPoint) const = 0; + }; + + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSketchInputProjector final : public ISolidSketchInputProjector + { + public: + SolidSketchInputProjector(); + ~SolidSketchInputProjector() override; + + void SetPlacementContext(const SolidSketchPlacementContext& context) override; + SolidSketchPlacementContext GetPlacementContext() const override; + void SetPlaneAnchorFromRepresentationNodeHit(const alice::RepresentationNodeHitResult& hit) override; + bool TryProjectScreenPointToSketch(double screenX, + double screenY, + alice::SketchPoint2d& outPoint) const override; + + private: + SolidSketchPlacementContext m_context{}; + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSketchPlacementContext.h b/Designer/Interaction/SolidDesignerInteraction/SolidSketchPlacementContext.h new file mode 100644 index 00000000..44a2c9e8 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSketchPlacementContext.h @@ -0,0 +1,8 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "AliceFeatureAuthoringInputs.h" + +namespace sdr +{ + using SolidSketchPlacementContext = alice::SketchPlacementContextData; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSketchReferenceSetBuilder.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidSketchReferenceSetBuilder.cpp new file mode 100644 index 00000000..37fe390d --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSketchReferenceSetBuilder.cpp @@ -0,0 +1,59 @@ +#include "SolidSketchReferenceSetBuilder.h" + +#include "AliceFeatureReferenceRuntime.h" +#include "AliceIFeatureReferenceFactory.h" +#include "AliceISketch.h" +#include "AliceISketchCurve.h" +#include "AliceGuidUtils.h" + +using namespace sdr; +using namespace alice; + +namespace +{ + +} + +std::shared_ptr SolidSketchReferenceSetBuilder::BuildPersistentSketchReferenceSet( + const ObjectId& sourceSketchId, + const ISketch& sketch) +{ + IFeatureReferenceFactory* const pFactory = IFeatureReferenceFactory::Get(); + if (!pFactory) + { + return nullptr; + } + + std::shared_ptr pSet = pFactory->CreateReferenceSet(); + auto pConcrete = std::dynamic_pointer_cast(pSet); + if (!pConcrete || !sourceSketchId.IsValid()) + { + return pSet; + } + + pConcrete->AddObjectReference(pFactory->CreateObjectReference(sourceSketchId)); + + const auto curves = sketch.GetCurves(); + for (const auto& curve : curves) + { + if (!curve) + { + continue; + } + + const auto& header = curve->GetHeader(); + if (alice::GuidUtils::IsValid(header.Id)) + { + pConcrete->AddSketchEntityReference(pFactory->CreateSketchEntityReferenceById(sourceSketchId, header.Id)); + continue; + } + + if (!header.SelectionBindingKey.empty()) + { + pConcrete->AddSketchEntityReference(pFactory->CreateSketchEntityReference(sourceSketchId, header.SelectionBindingKey)); + } + } + return pSet; +} + + diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSketchReferenceSetBuilder.h b/Designer/Interaction/SolidDesignerInteraction/SolidSketchReferenceSetBuilder.h new file mode 100644 index 00000000..b0d17025 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSketchReferenceSetBuilder.h @@ -0,0 +1,24 @@ +#pragma once +#include "SolidDesignerInteraction.h" + +#include "AliceObjectId.h" + +#include + +namespace alice +{ + class IFeatureReferenceSet; + class ISketch; +} + +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSketchReferenceSetBuilder + { + public: + static std::shared_ptr BuildPersistentSketchReferenceSet( + const alice::ObjectId& sourceSketchId, + const alice::ISketch& sketch); + + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSketchRepresentationProjection.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidSketchRepresentationProjection.cpp new file mode 100644 index 00000000..7e845e7d --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSketchRepresentationProjection.cpp @@ -0,0 +1,318 @@ +#include "SolidSketchRepresentationProjection.h" + +#include "AliceGuidUtils.h" +#include "AliceRepresentationGroupNode.h" +#include "AliceCurveRepresentationNode.h" +#include "AliceLineRepresentationNode.h" +#include "AliceArcRepresentationNode.h" +#include "AliceEllipseRepresentationNode.h" +#include "AliceRepresentationGeometryFactory.h" +#include "AliceSketchObjectModel.h" +#include "AliceISketchLine.h" +#include "AliceISketchCircle.h" +#include "AliceISketchArc.h" +#include "AliceISketchEllipse.h" +#include "AliceISketchBezier.h" +#include "AliceISketchBSpline.h" +#include "AliceVector2d.h" +#include "AliceVector3d.h" +#include "SketchKernelCurvePrimitives.h" + +#include +#include + +namespace +{ + static alice::Vector3d MakeVec3(double x, double y, double z) + { + return alice::Vector3d(x, y, z); + } + + static alice::Vector3d NormalizeOrFallback(alice::Vector3d value, const alice::Vector3d& fallback) + { + if (value.Normalize() <= 1.0e-12) + { + return fallback; + } + return value; + } + + static bool ResolvePlacementFrame(const sdr::SolidSketchPlacementContext& context, + alice::Vector3d& outOrigin, + alice::Vector3d& outXAxis, + alice::Vector3d& outYAxis) + { + outOrigin = context.HasPlaneAnchor + ? MakeVec3(context.PlaneAnchorX, context.PlaneAnchorY, context.PlaneAnchorZ) + : MakeVec3(context.CameraTargetX, context.CameraTargetY, context.CameraTargetZ); + + if (context.HasPlaneFrame) + { + outXAxis = NormalizeOrFallback(MakeVec3(context.PlaneXAxisX, context.PlaneXAxisY, context.PlaneXAxisZ), alice::Vector3d::UnitX); + outYAxis = NormalizeOrFallback(MakeVec3(context.PlaneYAxisX, context.PlaneYAxisY, context.PlaneYAxisZ), alice::Vector3d::UnitY); + return true; + } + + const alice::Vector3d eye = MakeVec3(context.CameraEyeX, context.CameraEyeY, context.CameraEyeZ); + const alice::Vector3d target = MakeVec3(context.CameraTargetX, context.CameraTargetY, context.CameraTargetZ); + alice::Vector3d up = NormalizeOrFallback(MakeVec3(context.CameraUpX, context.CameraUpY, context.CameraUpZ), alice::Vector3d::UnitY); + const alice::Vector3d forward = NormalizeOrFallback(target - eye, alice::Vector3d::NegaUnitZ); + outXAxis = NormalizeOrFallback(forward.Cross(up), alice::Vector3d::UnitX); + outYAxis = NormalizeOrFallback(outXAxis.Cross(forward), up); + return true; + } + + static alice::Vector3d MapSketchPointToWorld(const sdr::SolidSketchPlacementContext& ctx, const alice::SketchPoint2d& point) + { + alice::Vector3d origin; + alice::Vector3d xAxis; + alice::Vector3d yAxis; + ResolvePlacementFrame(ctx, origin, xAxis, yAxis); + const double x = ctx.FlipHorizontal ? -point.X() : point.X(); + return origin + xAxis * x + yAxis * point.Y(); + } + + static std::uint64_t HashSketchNodeId(alice::ObjectId idObject, const std::string& token) + { + const std::uint64_t seed = static_cast(idObject.RawValue()); + const std::uint64_t hash = static_cast(std::hash{}(token)); + return seed ^ (hash + 0x9e3779b97f4a7c15ULL + (seed << 6u) + (seed >> 2u)); + } + + static std::vector ScaleCoords(const std::vector& points, int axis) + { + std::vector values; + values.reserve(points.size()); + for (const alice::Vector3d& point : points) + { + const double coord = axis == 0 ? point.X() : (axis == 1 ? point.Y() : point.Z()); + values.push_back(static_cast(std::llround(coord * 1000.0))); + } + return values; + } + + static std::string ResolveCurveToken(const alice::SketchSemanticEntityHeader& header) + { + if (!header.SelectionBindingKey.empty()) + { + return header.SelectionBindingKey; + } + if (!header.DisplayBindingKey.empty()) + { + return header.DisplayBindingKey; + } + return std::string("sketchcurve:") + alice::GuidUtils::ToString(header.Id); + } + + static std::string ResolveCurveRole(const alice::ISketchCurve& curve) + { + return curve.IsConstruction() ? "sketch.construction.curve" : "sketch.curve"; + } + + static std::shared_ptr CreateCurvePlaneGeometry(const sdr::SolidSketchPlacementContext& placementContext) + { + alice::Vector3d origin; + alice::Vector3d xAxis; + alice::Vector3d yAxis; + if (!ResolvePlacementFrame(placementContext, origin, xAxis, yAxis)) + { + return {}; + } + alice::Vector3d normal = NormalizeOrFallback(xAxis.Cross(yAxis), alice::Vector3d::UnitZ); + auto pPlane = alice::rep::geom::CreatePlaneGeometry(origin, normal, 1.0, 1.0); + if (pPlane) + { + pPlane->SetOrigin(origin); + pPlane->SetDirections(xAxis, yAxis); + } + return pPlane; + } + + static std::shared_ptr BuildPolylineNode(alice::ObjectId idObject, + const std::string& name, + const std::string& role, + const std::string& token, + const std::vector& points) + { + if (points.size() < 2u) + { + return {}; + } + auto pNode = std::make_shared(); + pNode->SetPersistentNodeId(HashSketchNodeId(idObject, token)); + pNode->SetOwnerObjectId(idObject); + pNode->SetDebugName(name); + pNode->SetSemanticRole(role); + pNode->SetCurveBindingToken(token); + pNode->SetCurveStyleTokenStorage(role); + pNode->SetSampledPolylineXs(ScaleCoords(points, 0)); + pNode->SetSampledPolylineYs(ScaleCoords(points, 1)); + pNode->SetSampledPolylineZs(ScaleCoords(points, 2)); + return pNode; + } + + static std::shared_ptr BuildLineNode(alice::ObjectId idObject, + const sdr::SolidSketchPlacementContext& placementContext, + const alice::ISketchLine& line) + { + auto pNode = std::make_shared(); + const auto& header = line.GetHeader(); + const std::string token = ResolveCurveToken(header); + const std::string role = ResolveCurveRole(line); + pNode->SetPersistentNodeId(HashSketchNodeId(idObject, token)); + pNode->SetOwnerObjectId(idObject); + pNode->SetDebugName(token); + pNode->SetSemanticRole(role); + pNode->SetCurveBindingToken(token); + pNode->SetCurveStyleToken(role); + pNode->SetIsConstruction(line.IsConstruction()); + pNode->SetPlaneGeometry(CreateCurvePlaneGeometry(placementContext)); + auto pGeom = std::dynamic_pointer_cast( + alice::feature_edit::detail::CreateSketchLineCurve2d( + alice::Vector2d(line.GetStart().X(), line.GetStart().Y()), + alice::Vector2d(line.GetEnd().X(), line.GetEnd().Y()))); + pNode->SetGeometry(std::move(pGeom)); + return pNode; + } + + static std::shared_ptr BuildArcNode(alice::ObjectId idObject, + const sdr::SolidSketchPlacementContext& placementContext, + const alice::ISketchArc& arc) + { + auto pNode = std::make_shared(); + const auto& header = arc.GetHeader(); + const std::string token = ResolveCurveToken(header); + const std::string role = ResolveCurveRole(arc); + pNode->SetPersistentNodeId(HashSketchNodeId(idObject, token)); + pNode->SetOwnerObjectId(idObject); + pNode->SetDebugName(token); + pNode->SetSemanticRole(role); + pNode->SetCurveBindingToken(token); + pNode->SetCurveStyleToken(role); + pNode->SetIsConstruction(arc.IsConstruction()); + pNode->SetPlaneGeometry(CreateCurvePlaneGeometry(placementContext)); + auto pGeom = std::dynamic_pointer_cast( + alice::feature_edit::detail::CreateSketchArcCurve2d( + alice::Vector2d(arc.GetCenter().X(), arc.GetCenter().Y()), + arc.GetRadius(), + arc.GetStartAngleRad(), + arc.GetEndAngleRad(), + true)); + pNode->SetGeometry(std::move(pGeom)); + return pNode; + } + + static std::shared_ptr BuildEllipseNode(alice::ObjectId idObject, + const sdr::SolidSketchPlacementContext& placementContext, + const alice::SketchSemanticEntityHeader& header, + bool isConstruction, + const alice::SketchPoint2d& center, + double radiusX, + double radiusY, + double rotationRad) + { + auto pNode = std::make_shared(); + const std::string token = ResolveCurveToken(header); + const std::string role = isConstruction ? "sketch.construction.curve" : "sketch.curve"; + pNode->SetPersistentNodeId(HashSketchNodeId(idObject, token)); + pNode->SetOwnerObjectId(idObject); + pNode->SetDebugName(token); + pNode->SetSemanticRole(role); + pNode->SetCurveBindingToken(token); + pNode->SetCurveStyleToken(role); + pNode->SetIsConstruction(isConstruction); + pNode->SetPlaneGeometry(CreateCurvePlaneGeometry(placementContext)); + auto pGeom = std::dynamic_pointer_cast( + alice::feature_edit::detail::CreateSketchEllipseCurve2d( + alice::Vector2d(center.X(), center.Y()), + radiusX, + radiusY, + rotationRad)); + pNode->SetGeometry(std::move(pGeom)); + return pNode; + } +} + +void sdr::SolidSketchRepresentationProjection::AppendProjectedSketchCurves(alice::rep::RepresentationGroupNode& root, + alice::ObjectId idObject, + const SolidSketchPlacementContext& placementContext, + const std::shared_ptr& pSketch) +{ + if (!pSketch) + { + return; + } + + for (const auto& curve : pSketch->GetCurves()) + { + if (!curve) + { + continue; + } + + if (const auto line = std::dynamic_pointer_cast(curve)) + { + root.AppendChild(BuildLineNode(idObject, placementContext, *line)); + } + else if (const auto circle = std::dynamic_pointer_cast(curve)) + { + root.AppendChild(BuildEllipseNode(idObject, + placementContext, + circle->GetHeader(), + circle->IsConstruction(), + circle->GetCenter(), + circle->GetRadius(), + circle->GetRadius(), + 0.0)); + } + else if (const auto arc = std::dynamic_pointer_cast(curve)) + { + root.AppendChild(BuildArcNode(idObject, placementContext, *arc)); + } + else if (const auto ellipse = std::dynamic_pointer_cast(curve)) + { + root.AppendChild(BuildEllipseNode(idObject, + placementContext, + ellipse->GetHeader(), + ellipse->IsConstruction(), + ellipse->GetCenter(), + ellipse->GetRadiusX(), + ellipse->GetRadiusY(), + ellipse->GetRotationRad())); + } + else if (const auto bezier = std::dynamic_pointer_cast(curve)) + { + std::vector points; + points.reserve(bezier->GetControlPoints().size()); + for (const auto& point : bezier->GetControlPoints()) + { + points.push_back(MapSketchPointToWorld(placementContext, point)); + } + if (auto pNode = BuildPolylineNode(idObject, + ResolveCurveToken(bezier->GetHeader()), + ResolveCurveRole(*bezier), + ResolveCurveToken(bezier->GetHeader()), + points)) + { + root.AppendChild(pNode); + } + } + else if (const auto bspline = std::dynamic_pointer_cast(curve)) + { + std::vector points; + points.reserve(bspline->GetControlPoints().size()); + for (const auto& point : bspline->GetControlPoints()) + { + points.push_back(MapSketchPointToWorld(placementContext, point)); + } + if (auto pNode = BuildPolylineNode(idObject, + ResolveCurveToken(bspline->GetHeader()), + ResolveCurveRole(*bspline), + ResolveCurveToken(bspline->GetHeader()), + points)) + { + root.AppendChild(pNode); + } + } + } +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSketchRepresentationProjection.h b/Designer/Interaction/SolidDesignerInteraction/SolidSketchRepresentationProjection.h new file mode 100644 index 00000000..81425099 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSketchRepresentationProjection.h @@ -0,0 +1,24 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "SolidSketchPlacementContext.h" + +#include + +namespace alice +{ + class ObjectId; + class ISketch; + namespace rep { class RepresentationGroupNode; } +} + +namespace sdr +{ + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSketchRepresentationProjection final + { + public: + static void AppendProjectedSketchCurves(alice::rep::RepresentationGroupNode& root, + alice::ObjectId idObject, + const SolidSketchPlacementContext& placementContext, + const std::shared_ptr& pSketch); + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSketchSectionTypes.h b/Designer/Interaction/SolidDesignerInteraction/SolidSketchSectionTypes.h new file mode 100644 index 00000000..0f85c7fb --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSketchSectionTypes.h @@ -0,0 +1,8 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "AliceFeatureAuthoringInputs.h" + +namespace sdr +{ + using SolidSketchSectionInput = alice::SketchSectionBuildInput; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSweepAuthoringPayloadBuilder.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidSweepAuthoringPayloadBuilder.cpp new file mode 100644 index 00000000..ef194231 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSweepAuthoringPayloadBuilder.cpp @@ -0,0 +1,44 @@ +#include "SolidSweepAuthoringPayloadBuilder.h" + +#include "AliceFeatureLifecycleModels.h" +#include "AliceIFeatureDefinition.h" +#include "AliceIFeatureReferenceSet.h" + +using namespace sdr; +using namespace alice; + +bool SolidSweepAuthoringPayload::IsComplete() const noexcept +{ + return Definition != nullptr && ReferenceSet != nullptr; +} + +SolidSweepAuthoringPayload SolidSweepAuthoringPayloadBuilder::Build(std::shared_ptr definition, + std::shared_ptr referenceSet) +{ + SolidSweepAuthoringPayload payload; + payload.Definition = std::move(definition); + payload.ReferenceSet = std::move(referenceSet); + return payload; +} + +FeatureCreateRequestModel SolidSweepAuthoringPayloadBuilder::BuildCreateRequest(const SolidSweepAuthoringPayload& payload, + FeatureLifecycleApplyMode applyMode, + FeatureDomain targetDomain, + FeatureId targetFeatureId, + bool allowIncompleteCommit) +{ + FeatureCreateRequestModel request; + request.SetTargetDomain(targetDomain); + request.SetApplyMode(applyMode); + if (payload.Definition) + { + request.SetDefinitionCandidate(payload.Definition->Clone()); + } + request.SetReferenceSetCandidate(payload.ReferenceSet); + request.SetAllowIncompleteCommit(allowIncompleteCommit); + if (targetFeatureId.IsValid()) + { + request.SetTargetFeatureId(targetFeatureId); + } + return request; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidSweepAuthoringPayloadBuilder.h b/Designer/Interaction/SolidDesignerInteraction/SolidSweepAuthoringPayloadBuilder.h new file mode 100644 index 00000000..24d4a23d --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidSweepAuthoringPayloadBuilder.h @@ -0,0 +1,37 @@ +#pragma once +#include "SolidDesignerInteraction.h" + +#include "AliceFeaturePrimitives.h" + +#include + +namespace alice +{ + class IFeatureDefinition; + class IFeatureReferenceSet; + class FeatureCreateRequestModel; +} + +namespace sdr +{ + struct SOLID_DESIGNER_INTERACTION_EXPORT SolidSweepAuthoringPayload final + { + std::shared_ptr Definition; + std::shared_ptr ReferenceSet; + + [[nodiscard]] bool IsComplete() const noexcept; + }; + + class SOLID_DESIGNER_INTERACTION_EXPORT SolidSweepAuthoringPayloadBuilder final + { + public: + static SolidSweepAuthoringPayload Build(std::shared_ptr definition, + std::shared_ptr referenceSet); + + static alice::FeatureCreateRequestModel BuildCreateRequest(const SolidSweepAuthoringPayload& payload, + alice::FeatureLifecycleApplyMode applyMode, + alice::FeatureDomain targetDomain, + alice::FeatureId targetFeatureId = {}, + bool allowIncompleteCommit = false); + }; +} diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidViewNavigationOperation.cpp b/Designer/Interaction/SolidDesignerInteraction/SolidViewNavigationOperation.cpp new file mode 100644 index 00000000..c67b6826 --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidViewNavigationOperation.cpp @@ -0,0 +1,117 @@ +#include "SolidViewNavigationOperation.h" + +#include "UiManager/AliceModelViewNavigationService.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "AliceIMainWindow.h" +#include "AliceIUiApplicationFactory.h" +#include "AliceIUiApplication.h" +#include "AliceViewKinds.h" +#include "AliceIUiView.h" +#include "SolidSectionEditOperation.h" +#include "SolidExtrudeCreateOperation.h" + + +using namespace sdr; +using namespace alice; + +namespace +{ + static std::shared_ptr ResolveActiveUiView_() + { + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (!pSession) + { + return {}; + } + + IDocument* const pDocument = pSession->GetActiveDocument(); + if (!pDocument) + { + return {}; + } + + IUiApplicationFactory* const pFactory = IUiApplicationFactory::Get(); + if (!pFactory || !pFactory->GetUiApplication()) + { + return {}; + } + + IMainWindow* const pMainWindow = const_cast(pFactory->GetUiApplication()->GetMainWindow()); + if (!pMainWindow) + { + return {}; + } + + const bool bEditingSketch = (SolidSectionEditOperation::FindActive(pSession) != nullptr) || + ([](ISession* pCurrentSession) + { + if (auto* const pExtrudeOperation = SolidExtrudeCreateOperation::FindActive(pCurrentSession)) + { + return pExtrudeOperation->IsEditingSketch(); + } + return false; + }(pSession)); + if (bEditingSketch) + { + for (const auto& pView : pMainWindow->GetOpenViews(pDocument)) + { + if (pView && pView->GetViewKind() == alice::g_Sketch2DView) + { + return pView; + } + } + } + + return pMainWindow->GetPrimaryOpenView(pDocument); + } +} + +SolidViewNavigationOperation::SolidViewNavigationOperation(alice::ModelViewStandardOrientation eOrientation, bool bRestoreHome) noexcept + : m_eOrientation(eOrientation) + , m_eAction(bRestoreHome ? SolidViewNavigationAction::RestoreHome : SolidViewNavigationAction::ApplyStandardOrientation) +{ +} + +SolidViewNavigationOperation::SolidViewNavigationOperation(SolidViewNavigationAction eAction) noexcept + : m_eOrientation(alice::ModelViewStandardOrientation::Unknown) + , m_eAction(eAction) +{ +} + +SolidViewNavigationOperation::~SolidViewNavigationOperation() = default; + +void SolidViewNavigationOperation::InitOperation(IUiView* pCurrentView) +{ + alice::OperationBase::InitOperation(pCurrentView); + ModelViewNavigationService navigationService; + const auto pView = ResolveActiveUiView_(); + + switch (m_eAction) + { + case SolidViewNavigationAction::RestoreHome: + navigationService.RestoreHomeOrientation(pView); + break; + case SolidViewNavigationAction::FitAll: + navigationService.FitAll(pView); + break; + case SolidViewNavigationAction::LookNormalToWorkPlane: + navigationService.LookNormalToWorkPlane(pView); + break; + case SolidViewNavigationAction::ToggleViewCube: + navigationService.ToggleOrientationCubeVisible(pView); + break; + case SolidViewNavigationAction::ApplyStandardOrientation: + default: + navigationService.ApplyStandardOrientation(pView, m_eOrientation, false); + break; + } + + m_bFinished = true; +} + +bool SolidViewNavigationOperation::IsFinished() const noexcept +{ + return m_bFinished; +} + diff --git a/Designer/Interaction/SolidDesignerInteraction/SolidViewNavigationOperation.h b/Designer/Interaction/SolidDesignerInteraction/SolidViewNavigationOperation.h new file mode 100644 index 00000000..130ea33b --- /dev/null +++ b/Designer/Interaction/SolidDesignerInteraction/SolidViewNavigationOperation.h @@ -0,0 +1,32 @@ +#pragma once +#include "SolidDesignerInteraction.h" +#include "AliceOperationBase.h" +#include "AliceIModelView.h" + +namespace sdr +{ + enum class SolidViewNavigationAction : unsigned char + { + ApplyStandardOrientation = 0, + RestoreHome, + FitAll, + LookNormalToWorkPlane, + ToggleViewCube + }; + + class SOLID_DESIGNER_INTERACTION_EXPORT SolidViewNavigationOperation final : public alice::OperationBase + { + public: + explicit SolidViewNavigationOperation(alice::ModelViewStandardOrientation eOrientation, bool bRestoreHome = false) noexcept; + explicit SolidViewNavigationOperation(SolidViewNavigationAction eAction) noexcept; + ~SolidViewNavigationOperation() override; + + void InitOperation(alice::IUiView* pCurrentView) override; + bool IsFinished() const noexcept override; + + private: + alice::ModelViewStandardOrientation m_eOrientation; + SolidViewNavigationAction m_eAction{ SolidViewNavigationAction::ApplyStandardOrientation }; + bool m_bFinished{ false }; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/BaseCommands/SolidBaseCommand.h b/Designer/UI/SolidDesignerCommand/BaseCommands/SolidBaseCommand.h index 0a1c4205..6c203871 100644 --- a/Designer/UI/SolidDesignerCommand/BaseCommands/SolidBaseCommand.h +++ b/Designer/UI/SolidDesignerCommand/BaseCommands/SolidBaseCommand.h @@ -1,5 +1,6 @@ #pragma once #include "AliceICommand.h" +#include "AliceIOperation.h" #include #include diff --git a/Designer/UI/SolidDesignerCommand/CMakeLists.txt b/Designer/UI/SolidDesignerCommand/CMakeLists.txt index e559d40e..f2430fd5 100644 --- a/Designer/UI/SolidDesignerCommand/CMakeLists.txt +++ b/Designer/UI/SolidDesignerCommand/CMakeLists.txt @@ -36,6 +36,8 @@ file(GLOB SDC_FILES "${ABS_SDC}/HelpCommands/*.h" "${ABS_SDC}/HelpCommands/*.cpp" "${ABS_SDC}/GeneralCommands/*.h" "${ABS_SDC}/GeneralCommands/*.cpp" "${ABS_SDC}/ModelCommands/*.h" "${ABS_SDC}/ModelCommands/*.cpp" + "${ABS_SDC}/SketchCommands/*.h" "${ABS_SDC}/SketchCommands/*.cpp" + "${ABS_SDC}/ViewCommands/*.h" "${ABS_SDC}/ViewCommands/*.cpp" ) source_group(TREE "${ABS_SDC}" FILES ${SDC_FILES}) @@ -50,17 +52,45 @@ link_directories(${ALICE_LIB_DIR}) #----------------------------------------------------------------------------- include_directories(${CMAKE_SOURCE_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Foundation/AliceBasicTool/Public) -include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Foundation/AliceFoundation/Public) -include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Runtime/AlicePluginSystem/Public) -include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceCommandInterface/Public) -include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceOperationInterface/Public) -include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceCoreApplicationInterface/Public) -include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceModelInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Foundation/AliceBasicTool/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Foundation/AliceFoundation/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Math/AliceMaths/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Runtime/AlicePluginSystem/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Runtime/Interface/AliceRenderSystemInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Core/Runtime/AliceRenderSystem/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceCommandInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceOperationSystemInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/Interface/AliceCoreApplicationInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceModelInterface/Public) include_directories(${PROJECT_SOURCE_DIR}/Alice/UI/QFrameWork/AliceUiFrameWork/Public) include_directories(${PROJECT_SOURCE_DIR}/Designer/UI/SolidDesignerUI/Public) +include_directories(${PROJECT_SOURCE_DIR}/Designer/UI/SolidDesignerCommand) +include_directories(${PROJECT_SOURCE_DIR}/Designer/UI/SolidDesignerCommand/BaseCommands) +include_directories(${PROJECT_SOURCE_DIR}/Designer/UI/SolidDesignerCommand/EditCommands) +include_directories(${PROJECT_SOURCE_DIR}/Designer/UI/SolidDesignerCommand/GeneralCommands) +include_directories(${PROJECT_SOURCE_DIR}/Designer/UI/SolidDesignerCommand/ModelCommands) +include_directories(${PROJECT_SOURCE_DIR}/Designer/UI/SolidDesignerCommand/SketchCommands) +include_directories(${PROJECT_SOURCE_DIR}/Designer/UI/SolidDesignerCommand/ViewCommands) + +include_directories(${PROJECT_SOURCE_DIR}/Designer/Interaction/SolidDesignerInteraction) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/View/AliceUiViewInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Interaction/AliceCommonOperation/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceViewModelInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureHistoryInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceViewPrimitiveInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Designer/UI/SolidDesignerCommand) + +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceModelInterface/Public/Feature) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceConstraintSystemInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureDefinitionInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AlicePartFeatureInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureDefinitionInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureEditInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceObjectRepresentationModelInterface) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceObjectRepresentationModelInterface/Public) +include_directories(${PROJECT_SOURCE_DIR}/Alice/Data/Interface/AliceFeatureObjectModelInterface/Public) #----------------------------------------------------------------------------- # 定义项目构建中间文件的生成目录 #----------------------------------------------------------------------------- @@ -176,13 +206,20 @@ target_link_libraries(SolidDesignerCommand PRIVATE AliceBasicTool AliceCoreApplicationInterface AliceCommandInterface - AliceOperationInterface + AliceOperationSystemInterface AliceModelInterface + AliceFeatureObjectModelInterface + AliceObjectRepresentationModelInterface AliceUiFrameWork AlicePluginSystem SolidDesignerUI + SolidDesignerInteraction + AliceCommonOperation + AliceRenderSystemInterface + AliceRenderSystem + AlicePartFeatureInterface ) -message("*--*--*--*--*--*--*--*--*--*--*--**--*--*--End SolidDesignerCommand*--*--*--*--*--*--*--*--*--*--*--*--*--*") \ No newline at end of file +message("*--*--*--*--*--*--*--*--*--*--*--**--*--*--End SolidDesignerCommand*--*--*--*--*--*--*--*--*--*--*--*--*--*") diff --git a/Designer/UI/SolidDesignerCommand/EditCommands/SolidSelectSingleCommand.cpp b/Designer/UI/SolidDesignerCommand/EditCommands/SolidSelectSingleCommand.cpp new file mode 100644 index 00000000..73b6cfb5 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/EditCommands/SolidSelectSingleCommand.cpp @@ -0,0 +1,106 @@ +#include "SolidSelectSingleCommand.h" + +#include "SolidDesignerCommands.h" +#include "Designer/Interaction/SolidDesignerInteraction/SolidDefaultPickOperation.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "AliceIDocument.h" +#include "AliceIUiView.h" +#include "AliceIMainWindow.h" +#include "AliceIUiApplication.h" +#include "AliceIUiApplicationFactory.h" +#include "AliceCommandParameter.h" + +using namespace sdr; +using namespace alice; + + +namespace +{ + static void ConfigureDefaultViewShortcuts_() + { + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (!pSession) + { + return; + } + + IDocument* const pDocument = pSession->GetActiveDocument(); + if (!pDocument) + { + return; + } + + IUiApplicationFactory* const pFactory = IUiApplicationFactory::Get(); + if (!pFactory) + { + return; + } + + IUiApplication* const pUiApp = pFactory->GetUiApplication(); + if (!pUiApp) + { + return; + } + + IMainWindow* const pMainWindow = const_cast(pUiApp->GetMainWindow()); + if (!pMainWindow) + { + return; + } + + const std::shared_ptr pView = pMainWindow->GetPrimaryOpenView(pDocument); + if (!pView) + { + return; + } + + pView->SetShortcutCommand("Ctrl+Z", std::string(Cmd::EDIT_UNDO)); + pView->SetShortcutCommand("Ctrl+Y", std::string(Cmd::EDIT_REDO)); + pView->SetShortcutCommand("Ctrl+Shift+Z", std::string(Cmd::EDIT_REDO)); + } +} + + +SolidSelectSingleCommand::SolidSelectSingleCommand() noexcept + : AppCommandBase(std::string(Cmd::SELECT_SINGLE)) +{ +} + +SolidSelectSingleCommand::~SolidSelectSingleCommand() = default; + +bool SolidSelectSingleCommand::IsSupported() const +{ + return true; +} + +bool SolidSelectSingleCommand::IsVisible() const +{ + return true; +} + +bool SolidSelectSingleCommand::IsEnabled() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return pSession && pSession->GetActiveDocument() != nullptr; +} + +std::string SolidSelectSingleCommand::DisabledReason() const +{ + if (!IsEnabled()) + { + return "Single-selection default edit action requires an active document."; + } + return {}; +} + +std::unique_ptr SolidSelectSingleCommand::Execute(const CommandParameter& param) +{ + if (!IsEnabled()) + { + return nullptr; + } + + ConfigureDefaultViewShortcuts_(); + return std::make_unique(param.GetString("view_kind", {})); +} diff --git a/Designer/UI/SolidDesignerCommand/EditCommands/SolidSelectSingleCommand.h b/Designer/UI/SolidDesignerCommand/EditCommands/SolidSelectSingleCommand.h new file mode 100644 index 00000000..ef2e49c3 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/EditCommands/SolidSelectSingleCommand.h @@ -0,0 +1,24 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace alice +{ + struct CommandParameter; + class IOperation; +} + +namespace sdr +{ + class SolidSelectSingleCommand final : public AppCommandBase + { + public: + SolidSelectSingleCommand() noexcept; + ~SolidSelectSingleCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeCancelCommand.cpp b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeCancelCommand.cpp new file mode 100644 index 00000000..b9ad6549 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeCancelCommand.cpp @@ -0,0 +1,33 @@ +#include "SolidExtrudeCancelCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" + +using namespace sdr; +using namespace alice; + +SolidExtrudeCancelCommand::SolidExtrudeCancelCommand() noexcept + : AppCommandBase(std::string(Cmd::FEATURE_EXTRUDE_CANCEL)) +{ +} + +SolidExtrudeCancelCommand::~SolidExtrudeCancelCommand() = default; + +bool SolidExtrudeCancelCommand::IsSupported() const { return true; } +bool SolidExtrudeCancelCommand::IsVisible() const { return true; } + +bool SolidExtrudeCancelCommand::IsEnabled() const +{ + return false; +} + +std::string SolidExtrudeCancelCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"No active extrude workflow can be cancelled."}; +} + +std::unique_ptr SolidExtrudeCancelCommand::Execute(const CommandParameter& param) +{ + (void)param; + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeCancelCommand.h b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeCancelCommand.h new file mode 100644 index 00000000..273cb896 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeCancelCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "BaseCommands/SolidBaseCommand.h" + +namespace sdr +{ + class SolidExtrudeCancelCommand final : public AppCommandBase + { + public: + SolidExtrudeCancelCommand() noexcept; + ~SolidExtrudeCancelCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeDashboardApplyCommand.cpp b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeDashboardApplyCommand.cpp new file mode 100644 index 00000000..5eb2c6a0 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeDashboardApplyCommand.cpp @@ -0,0 +1,40 @@ +#include "SolidExtrudeDashboardApplyCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceCommandParameter.h" +#include "AliceISession.h" +#include "SolidExtrudeCreateOperation.h" + +using namespace sdr; +using namespace alice; + +SolidExtrudeDashboardApplyCommand::SolidExtrudeDashboardApplyCommand() noexcept + : AppCommandBase(std::string(Cmd::FEATURE_EXTRUDE_DASHBOARD_APPLY)) +{ +} + +SolidExtrudeDashboardApplyCommand::~SolidExtrudeDashboardApplyCommand() = default; + +bool SolidExtrudeDashboardApplyCommand::IsSupported() const { return true; } +bool SolidExtrudeDashboardApplyCommand::IsVisible() const { return true; } +bool SolidExtrudeDashboardApplyCommand::IsEnabled() const { return SolidExtrudeCreateOperation::FindActive(CoreAppUtil::GetCurrentSession()) != nullptr; } +std::string SolidExtrudeDashboardApplyCommand::DisabledReason() const { return IsEnabled() ? std::string{} : std::string{"No active extrude workflow."}; } + +std::unique_ptr SolidExtrudeDashboardApplyCommand::Execute(const CommandParameter& param) +{ + if (auto* const pOp = SolidExtrudeCreateOperation::FindActive(CoreAppUtil::GetCurrentSession())) + { + SolidExtrudeDashboardInput input = pOp->GetDashboardInput(); + input.Depth = param.GetDouble("depth", input.Depth); + input.RemoveMaterial = param.GetBool("removeMaterial", input.RemoveMaterial); + input.ReverseDirection = param.GetBool("reverseDirection", input.ReverseDirection); + input.Symmetric = param.GetBool("symmetric", input.Symmetric); + input.Side1ExtentType = param.GetString("side1ExtentType", input.Side1ExtentType); + input.Side2ExtentType = param.GetString("side2ExtentType", input.Side2ExtentType); + input.AddTaper = param.GetBool("addTaper", input.AddTaper); + input.TaperAngle = param.GetDouble("taperAngle", input.TaperAngle); + input.FeatureName = param.GetString("featureName", input.FeatureName); + (void)pOp->UpdateDashboard(input); + } + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeDashboardApplyCommand.h b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeDashboardApplyCommand.h new file mode 100644 index 00000000..d5719180 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeDashboardApplyCommand.h @@ -0,0 +1,20 @@ +#pragma once +#include "BaseCommands/SolidBaseCommand.h" +#include +#include + +namespace sdr +{ + class SolidExtrudeDashboardApplyCommand final : public AppCommandBase + { + public: + SolidExtrudeDashboardApplyCommand() noexcept; + ~SolidExtrudeDashboardApplyCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeOkCommand.cpp b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeOkCommand.cpp new file mode 100644 index 00000000..1acc9c5e --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeOkCommand.cpp @@ -0,0 +1,41 @@ +#include "SolidExtrudeOkCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidExtrudeCreateOperation.h" + +using namespace sdr; +using namespace alice; + +SolidExtrudeOkCommand::SolidExtrudeOkCommand() noexcept + : AppCommandBase(std::string(Cmd::FEATURE_EXTRUDE_OK)) +{ +} + +SolidExtrudeOkCommand::~SolidExtrudeOkCommand() = default; + +bool SolidExtrudeOkCommand::IsSupported() const +{ + return true; +} + +bool SolidExtrudeOkCommand::IsVisible() const +{ + return true; +} + +bool SolidExtrudeOkCommand::IsEnabled() const +{ + return false; +} + +std::string SolidExtrudeOkCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"Extrude dashboard is not in a committable preview state."}; +} + +std::unique_ptr SolidExtrudeOkCommand::Execute(const CommandParameter& param) +{ + (void)param; + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeOkCommand.h b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeOkCommand.h new file mode 100644 index 00000000..28649968 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidExtrudeOkCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "BaseCommands/SolidBaseCommand.h" + +namespace sdr +{ + class SolidExtrudeOkCommand final : public AppCommandBase + { + public: + SolidExtrudeOkCommand() noexcept; + ~SolidExtrudeOkCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidFeatureEditWorkflowBridge.cpp b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidFeatureEditWorkflowBridge.cpp new file mode 100644 index 00000000..d99f7767 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidFeatureEditWorkflowBridge.cpp @@ -0,0 +1,38 @@ +#include "SolidFeatureEditWorkflowBridge.h" +#include "SolidExtrudeCreateOperation.h" +#include "AliceISession.h" +#include "AliceIDocument.h" +#include "AliceIDocumentFeatureManager.h" +#include "AliceISelectionManager.h" +#include "AliceIFeature.h" +#include "AliceIPartFeatureFamilies.h" +#include "AliceCommandParameter.h" + +using namespace sdr; +using namespace alice; + +IFeature* SolidFeatureEditWorkflowBridge::ResolveEditDefinitionTarget(ISession* pSession, + IDocument* pDocument, + const CommandParameter*) +{ + if (!pSession || !pDocument) return nullptr; + IDocumentFeatureManager* const pFeatureManager = pDocument->GetDocumentFeatureManagerFw(); + ISelectionManager* const pSelectionManager = pSession->GetSelectionManagerFw(); + if (!pFeatureManager || !pSelectionManager) return nullptr; + const auto selections = pSelectionManager->GetSelectionInputs(); + if (selections.empty()) return nullptr; + return pFeatureManager->FindFeatureById(FeatureId::FromPermanentValue(selections.front().Handle.TargetObjectId.Value())); +} + +bool SolidFeatureEditWorkflowBridge::SupportsEditDefinition(const IFeature& feature) +{ + return dynamic_cast(&feature) != nullptr; +} + +std::unique_ptr SolidFeatureEditWorkflowBridge::CreateEditDefinitionOperation(IFeature& feature, + const CommandParameter& param) +{ + CommandParameter copied = param; + copied.SetKeyValue("featureId", feature.GetFeatureId().Value()); + return std::make_unique(copied); +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidFeatureEditWorkflowBridge.h b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidFeatureEditWorkflowBridge.h new file mode 100644 index 00000000..68df7bf0 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidFeatureEditWorkflowBridge.h @@ -0,0 +1,18 @@ +#pragma once +#include + +namespace alice { class ISession; class IDocument; class IFeature; struct CommandParameter; class IOperation; } + +namespace sdr +{ + class SolidFeatureEditWorkflowBridge final + { + public: + static alice::IFeature* ResolveEditDefinitionTarget(alice::ISession* pSession, + alice::IDocument* pDocument, + const alice::CommandParameter* pParam); + static bool SupportsEditDefinition(const alice::IFeature& feature); + static std::unique_ptr CreateEditDefinitionOperation(alice::IFeature& feature, + const alice::CommandParameter& param); + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidFeatureHistoryWorkflowBridge.cpp b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidFeatureHistoryWorkflowBridge.cpp new file mode 100644 index 00000000..386387c4 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidFeatureHistoryWorkflowBridge.cpp @@ -0,0 +1,411 @@ +#include "SolidFeatureHistoryWorkflowBridge.h" + +#include "AliceIDocument.h" +#include "AliceIDocumentFeatureManager.h" +#include "AliceIFeature.h" +#include "AliceIFeatureHistoryModel.h" +#include "AliceIFeatureRollbackManager.h" +#include "AliceIFeatureReorderManager.h" +#include "AliceIFeatureNode.h" +#include "AliceISelectionManager.h" +#include "AliceISession.h" + +using namespace sdr; +using namespace alice; + +ObjectId SolidFeatureHistoryWorkflowBridge::ResolveRequestedFeatureObjectId_(const CommandParameter* pRequest) +{ + if (!pRequest) + { + return {}; + } + + const std::uint64_t nU64 = pRequest->Get("feature_id", 0ull); + if (nU64 != 0ull) + { + return ObjectId::FromPermanentValue(nU64); + } + + const int nInt = pRequest->GetInt("feature_id", 0); + if (nInt > 0) + { + return ObjectId::FromPermanentValue(static_cast(nInt)); + } + + const std::string strText = pRequest->GetString("feature_id", {}); + if (!strText.empty()) + { + try + { + return ObjectId::FromPermanentValue(static_cast(std::stoull(strText))); + } + catch (...) + { + } + } + + return {}; +} + +IFeature* SolidFeatureHistoryWorkflowBridge::ResolveFeatureByObjectId_(IDocument* pDocument, const ObjectId& idObject) +{ + if (!pDocument || !idObject.IsValid()) + { + return nullptr; + } + + if (IDocumentObject* const pObject = pDocument->FindObjectById(idObject)) + { + return dynamic_cast(pObject); + } + + IFeature* pMatchedFeature = nullptr; + pDocument->EnumerateObjects([&](IDocumentObject* pObject) + { + if (pMatchedFeature) + { + return; + } + + auto* const pFeature = dynamic_cast(pObject); + if (pFeature && pFeature->GetFeatureId() == FeatureId(idObject.RawValue())) + { + pMatchedFeature = pFeature; + } + }); + return pMatchedFeature; +} + +IFeature* SolidFeatureHistoryWorkflowBridge::ResolveHistoryTarget(ISession* pSession, + IDocument* pDocument, + const CommandParameter* pRequest) +{ + if (!pDocument) + { + return nullptr; + } + + const ObjectId idExplicitFeature = ResolveRequestedFeatureObjectId_(pRequest); + if (idExplicitFeature.IsValid()) + { + if (IFeature* const pFeature = ResolveFeatureByObjectId_(pDocument, idExplicitFeature)) + { + return pFeature; + } + } + + const ISelectionManager* const pSelectionManager = pSession ? pSession->GetSelectionManager() : nullptr; + if (!pSelectionManager) + { + return nullptr; + } + + const std::vector selection = pSelectionManager->GetSelection(); + for (const SelectionItem& item : selection) + { + const CommandSelectionInput input = item.ToCommandSelectionInput(false, pSelectionManager->GetSelectionOwnerContext()); + if (IFeature* const pFeature = ResolveFeatureByObjectId_(pDocument, input.Handle.TargetObjectId)) + { + return pFeature; + } + } + + return nullptr; +} + +bool SolidFeatureHistoryWorkflowBridge::ResolveHistoryDependencies_(IDocument* pDocument, + IDocumentFeatureManager*& pOutFeatureManager, + IFeatureHistoryModel*& pOutHistoryModel) +{ + pOutFeatureManager = pDocument ? pDocument->GetDocumentFeatureManagerFw() : nullptr; + pOutHistoryModel = pOutFeatureManager ? pOutFeatureManager->GetFeatureHistoryModelFw() : nullptr; + return pOutFeatureManager != nullptr && pOutHistoryModel != nullptr; +} + +void SolidFeatureHistoryWorkflowBridge::SynchronizeFeatureStatusesFromHistory_(IDocument& document, + IDocumentFeatureManager& featureManager, + const IFeatureHistoryModel& history) +{ + history.EnumerateNodes([&](const IFeatureNode& node) + { + IFeature* const pFeature = featureManager.FindFeatureById(node.GetFeatureId()); + if (!pFeature) + { + return; + } + + const FeatureStatus eCurrent = pFeature->GetStatus(); + const FeatureNodeState eState = node.GetNodeState(); + + // Keep runtime-owned failure/incomplete/repair states intact when the history node is active. + if (eState == FeatureNodeState::HiddenByRollback) + { + pFeature->SetStatus(FeatureStatus::SuppressedByRollback); + return; + } + + switch (eState) + { + case FeatureNodeState::Suppressed: + pFeature->SetStatus(FeatureStatus::SuppressedByUser); + return; + case FeatureNodeState::Frozen: + pFeature->SetStatus(FeatureStatus::Frozen); + return; + case FeatureNodeState::Failed: + pFeature->SetStatus(FeatureStatus::Failed); + return; + case FeatureNodeState::UnresolvedReference: + pFeature->SetStatus(FeatureStatus::UnresolvedReference); + return; + case FeatureNodeState::EditingPreview: + pFeature->SetStatus(FeatureStatus::EditingPreview); + return; + case FeatureNodeState::Active: + default: + break; + } + + if (eCurrent == FeatureStatus::SuppressedByUser || + eCurrent == FeatureStatus::SuppressedByRollback || + eCurrent == FeatureStatus::Frozen) + { + pFeature->SetStatus(FeatureStatus::Active); + } + }); + + // Mark features hidden by rollback after the active-state pass so the tree and runtime stay aligned. + history.EnumerateNodes([&](const IFeatureNode& node) + { + if (node.GetNodeState() != FeatureNodeState::HiddenByRollback) + { + return; + } + + if (IFeature* const pFeature = featureManager.FindFeatureById(node.GetFeatureId())) + { + pFeature->SetStatus(FeatureStatus::SuppressedByRollback); + } + }); + + document.EnumerateObjects([&](IDocumentObject* pObject) + { + auto* const pFeature = dynamic_cast(pObject); + if (!pFeature) + { + return; + } + featureManager.NotifyFeatureSemanticChanged(*pFeature); + }); +} + +void SolidFeatureHistoryWorkflowBridge::RebuildActiveFeaturesFromHistory_(IDocumentFeatureManager& featureManager, + const IFeatureHistoryModel& history) +{ + history.EnumerateNodes([&](const IFeatureNode& node) + { + IFeature* const pFeature = featureManager.FindFeatureById(node.GetFeatureId()); + if (!pFeature) + { + return; + } + + const FeatureStatus eStatus = pFeature->GetStatus(); + if (eStatus == FeatureStatus::SuppressedByUser || + eStatus == FeatureStatus::SuppressedByRollback || + eStatus == FeatureStatus::EditingPreview) + { + return; + } + + featureManager.RequestFeatureRebuild(*pFeature); + }); +} + +bool SolidFeatureHistoryWorkflowBridge::SuppressFeature(ISession* pSession, + IDocument* pDocument, + const CommandParameter* pRequest) +{ + IDocumentFeatureManager* pFeatureManager = nullptr; + IFeatureHistoryModel* pHistory = nullptr; + if (!ResolveHistoryDependencies_(pDocument, pFeatureManager, pHistory)) + { + return false; + } + + IFeature* const pFeature = ResolveHistoryTarget(pSession, pDocument, pRequest); + if (!pFeature) + { + return false; + } + + IFeatureNode* const pNode = pHistory->FindNodeByFeatureFw(pFeature->GetFeatureId()); + if (!pNode) + { + return false; + } + if (!pHistory->SuppressNode(pNode->GetNodeId())) + { + return false; + } + + SynchronizeFeatureStatusesFromHistory_(*pDocument, *pFeatureManager, *pHistory); + RebuildActiveFeaturesFromHistory_(*pFeatureManager, *pHistory); + return true; +} + +bool SolidFeatureHistoryWorkflowBridge::ResumeFeature(ISession* pSession, + IDocument* pDocument, + const CommandParameter* pRequest) +{ + IDocumentFeatureManager* pFeatureManager = nullptr; + IFeatureHistoryModel* pHistory = nullptr; + if (!ResolveHistoryDependencies_(pDocument, pFeatureManager, pHistory)) + { + return false; + } + + IFeature* const pFeature = ResolveHistoryTarget(pSession, pDocument, pRequest); + if (!pFeature) + { + return false; + } + + IFeatureNode* const pNode = pHistory->FindNodeByFeatureFw(pFeature->GetFeatureId()); + if (!pNode) + { + return false; + } + if (!pHistory->ResumeNode(pNode->GetNodeId())) + { + return false; + } + + SynchronizeFeatureStatusesFromHistory_(*pDocument, *pFeatureManager, *pHistory); + RebuildActiveFeaturesFromHistory_(*pFeatureManager, *pHistory); + return true; +} + +bool SolidFeatureHistoryWorkflowBridge::SetRollbackCursorHere(ISession* pSession, + IDocument* pDocument, + const CommandParameter* pRequest) +{ + IDocumentFeatureManager* pFeatureManager = nullptr; + IFeatureHistoryModel* pHistory = nullptr; + if (!ResolveHistoryDependencies_(pDocument, pFeatureManager, pHistory)) + { + return false; + } + + IFeature* const pFeature = ResolveHistoryTarget(pSession, pDocument, pRequest); + if (!pFeature) + { + return false; + } + + IFeatureNode* const pNode = pHistory->FindNodeByFeatureFw(pFeature->GetFeatureId()); + if (!pNode) + { + return false; + } + if (!pHistory->SetRollbackCursor(pNode->GetNodeId())) + { + return false; + } + + SynchronizeFeatureStatusesFromHistory_(*pDocument, *pFeatureManager, *pHistory); + RebuildActiveFeaturesFromHistory_(*pFeatureManager, *pHistory); + return true; +} + +bool SolidFeatureHistoryWorkflowBridge::ClearRollbackCursor(IDocument* pDocument) +{ + IDocumentFeatureManager* pFeatureManager = nullptr; + IFeatureHistoryModel* pHistory = nullptr; + if (!ResolveHistoryDependencies_(pDocument, pFeatureManager, pHistory)) + { + return false; + } + + if (!pHistory->SetRollbackCursor(FeatureNodeId::Invalid())) + { + return false; + } + + SynchronizeFeatureStatusesFromHistory_(*pDocument, *pFeatureManager, *pHistory); + RebuildActiveFeaturesFromHistory_(*pFeatureManager, *pHistory); + return true; +} + + +bool SolidFeatureHistoryWorkflowBridge::ReorderFeature(ISession* pSession, + IDocument* pDocument, + const CommandParameter* pRequest) +{ + IDocumentFeatureManager* pFeatureManager = nullptr; + IFeatureHistoryModel* pHistory = nullptr; + if (!ResolveHistoryDependencies_(pDocument, pFeatureManager, pHistory)) + { + return false; + } + + IFeature* const pFeature = ResolveHistoryTarget(pSession, pDocument, pRequest); + if (!pFeature) + { + return false; + } + + ObjectId idAnchor{}; + if (pRequest) + { + const std::uint64_t nAnchorU64 = pRequest->Get("anchor_feature_id", 0ull); + if (nAnchorU64 != 0ull) + { + idAnchor = ObjectId::FromPermanentValue(nAnchorU64); + } + else + { + const int nAnchorInt = pRequest->GetInt("anchor_feature_id", 0); + if (nAnchorInt > 0) + { + idAnchor = ObjectId::FromPermanentValue(static_cast(nAnchorInt)); + } + else + { + const std::string strAnchor = pRequest->GetString("anchor_feature_id", {}); + if (!strAnchor.empty()) + { + try { idAnchor = ObjectId::FromPermanentValue(static_cast(std::stoull(strAnchor))); } catch (...) {} + } + } + } + } + IFeature* const pAnchorFeature = ResolveFeatureByObjectId_(pDocument, idAnchor); + if (!pAnchorFeature) + { + return false; + } + + IFeatureNode* const pNode = pHistory->FindNodeByFeatureFw(pFeature->GetFeatureId()); + IFeatureNode* const pAnchorNode = pHistory->FindNodeByFeatureFw(pAnchorFeature->GetFeatureId()); + if (!pNode || !pAnchorNode) + { + return false; + } + + InsertMode eMode = InsertMode::Before; + if (pRequest && pRequest->GetString("insert_mode", {}) == "after") + { + eMode = InsertMode::After; + } + + IFeatureReorderManager* const pReorder = pFeatureManager->GetFeatureReorderManagerFw(); + if (!pReorder || !pReorder->ReorderNode(pNode->GetNodeId(), pAnchorNode->GetNodeId(), eMode)) + { + return false; + } + + SynchronizeFeatureStatusesFromHistory_(*pDocument, *pFeatureManager, *pHistory); + RebuildActiveFeaturesFromHistory_(*pFeatureManager, *pHistory); + return true; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidFeatureHistoryWorkflowBridge.h b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidFeatureHistoryWorkflowBridge.h new file mode 100644 index 00000000..83c91e3a --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidFeatureHistoryWorkflowBridge.h @@ -0,0 +1,48 @@ +#pragma once + +#include "AliceCommandParameter.h" +#include "AliceObjectId.h" + +namespace alice +{ + class IDocument; + class IDocumentFeatureManager; + class IFeature; + class IFeatureHistoryModel; + class ISession; +} + +namespace sdr +{ + class SolidFeatureHistoryWorkflowBridge final + { + public: + static alice::IFeature* ResolveHistoryTarget(alice::ISession* pSession, + alice::IDocument* pDocument, + const alice::CommandParameter* pRequest); + + static bool SuppressFeature(alice::ISession* pSession, + alice::IDocument* pDocument, + const alice::CommandParameter* pRequest); + static bool ResumeFeature(alice::ISession* pSession, + alice::IDocument* pDocument, + const alice::CommandParameter* pRequest); + static bool SetRollbackCursorHere(alice::ISession* pSession, + alice::IDocument* pDocument, + const alice::CommandParameter* pRequest); + static bool ClearRollbackCursor(alice::IDocument* pDocument); + static bool ReorderFeature(alice::ISession* pSession, alice::IDocument* pDocument, const alice::CommandParameter* pRequest); + + private: + static alice::ObjectId ResolveRequestedFeatureObjectId_(const alice::CommandParameter* pRequest); + static alice::IFeature* ResolveFeatureByObjectId_(alice::IDocument* pDocument, const alice::ObjectId& idObject); + static bool ResolveHistoryDependencies_(alice::IDocument* pDocument, + alice::IDocumentFeatureManager*& pOutFeatureManager, + alice::IFeatureHistoryModel*& pOutHistoryModel); + static void SynchronizeFeatureStatusesFromHistory_(alice::IDocument& document, + alice::IDocumentFeatureManager& featureManager, + const alice::IFeatureHistoryModel& history); + static void RebuildActiveFeaturesFromHistory_(alice::IDocumentFeatureManager& featureManager, + const alice::IFeatureHistoryModel& history); + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelEditDefinitionCommand.cpp b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelEditDefinitionCommand.cpp new file mode 100644 index 00000000..5db8e415 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelEditDefinitionCommand.cpp @@ -0,0 +1,91 @@ +#include "SolidModelEditDefinitionCommand.h" + +#include "AliceCommandParameter.h" +#include "AliceCoreAppUtil.h" +#include "AliceIDocument.h" +#include "AliceIDocumentFeatureManager.h" +#include "AliceIFeature.h" +#include "SolidFeatureEditWorkflowBridge.h" +#include "AliceIOperation.h" +#include "AliceISession.h" +#include "AliceISelectionManager.h" +#include "SolidDesignerCommands.h" + +using namespace sdr; +using namespace alice; + +SolidModelEditDefinitionCommand::SolidModelEditDefinitionCommand() noexcept + : AppCommandBase(std::string(Cmd::MODEL_FEATURE_EDITDEFINITION)) +{ +} + +SolidModelEditDefinitionCommand::~SolidModelEditDefinitionCommand() = default; + +bool SolidModelEditDefinitionCommand::IsSupported() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + return pDocument && pDocument->GetDocumentKind() == DocumentKind::Part && pDocument->GetDocumentFeatureManagerFw() != nullptr; +} + +bool SolidModelEditDefinitionCommand::IsVisible() const +{ + return IsSupported(); +} + +bool SolidModelEditDefinitionCommand::IsEnabled() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + if (!pDocument || pDocument->IsReadOnly()) + { + return false; + } + + IFeature* const pFeature = SolidFeatureEditWorkflowBridge::ResolveEditDefinitionTarget(pSession, pDocument, nullptr); + if (!pFeature) + { + return false; + } + + return SolidFeatureEditWorkflowBridge::SupportsEditDefinition(*pFeature); +} + +std::string SolidModelEditDefinitionCommand::DisabledReason() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + if (!pDocument) + { + return "No active part document is available."; + } + if (pDocument->IsReadOnly()) + { + return "The active document is read-only."; + } + + IFeature* const pFeature = SolidFeatureEditWorkflowBridge::ResolveEditDefinitionTarget(pSession, pDocument, nullptr); + if (!pFeature) + { + return "Select an editable extrude, revolve, sweep, or hole feature first."; + } + if (!SolidFeatureEditWorkflowBridge::SupportsEditDefinition(*pFeature)) + { + return "Edit Definition currently supports part.extrude, part.revolve, part.sweep, and part.hole."; + } + + return {}; +} + +std::unique_ptr SolidModelEditDefinitionCommand::Execute(const alice::CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + IFeature* const pFeature = SolidFeatureEditWorkflowBridge::ResolveEditDefinitionTarget(pSession, pDocument, ¶m); + if (!pFeature) + { + return nullptr; + } + + return SolidFeatureEditWorkflowBridge::CreateEditDefinitionOperation(*pFeature, param); +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelEditDefinitionCommand.h b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelEditDefinitionCommand.h new file mode 100644 index 00000000..c42d6c41 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelEditDefinitionCommand.h @@ -0,0 +1,27 @@ +#pragma once +#include "BaseCommands/SolidBaseCommand.h" +#include +#include + +namespace alice +{ + class IOperation; + struct CommandParameter; +} + +namespace sdr +{ + class SolidModelEditDefinitionCommand final : public AppCommandBase + { + public: + SolidModelEditDefinitionCommand() noexcept; + ~SolidModelEditDefinitionCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelExtrudeCommand.cpp b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelExtrudeCommand.cpp index 8f2c6bb7..6d758498 100644 --- a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelExtrudeCommand.cpp +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelExtrudeCommand.cpp @@ -1,42 +1,95 @@ #include "SolidModelExtrudeCommand.h" #include "SolidDesignerCommands.h" +#include "SolidExtrudeCreateOperation.h" +#include "AliceCommandParameter.h" +#include "AliceCoreAppUtil.h" +#include "AliceIDocument.h" +#include "AliceIDocumentFeatureManager.h" #include "AliceIOperation.h" +#include "AliceISession.h" using namespace sdr; using namespace alice; sdr::SolidModelExtrudeCommand::SolidModelExtrudeCommand() noexcept - : AppCommandBase(std::string(Cmd::MODEL_EXTRUDE)) + : AppCommandBase(std::string(Cmd::MODEL_EXTRUDE)) { - } -sdr::SolidModelExtrudeCommand::~SolidModelExtrudeCommand() -{ - -} +sdr::SolidModelExtrudeCommand::~SolidModelExtrudeCommand() = default; bool SolidModelExtrudeCommand::IsSupported() const { - return false; + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (!pSession) + { + return false; + } + + IDocument* const pDocument = pSession->GetActiveDocument(); + if (!pDocument) + { + return false; + } + + return pDocument->GetDocumentKind() == DocumentKind::Part && pDocument->GetDocumentFeatureManagerFw() != nullptr; } bool SolidModelExtrudeCommand::IsVisible() const { - return false; + return IsSupported(); } bool SolidModelExtrudeCommand::IsEnabled() const { - return false; + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (!pSession) + { + return false; + } + + IDocument* const pDocument = pSession->GetActiveDocument(); + if (!pDocument) + { + return false; + } + + return !pDocument->IsReadOnly() && pDocument->GetDocumentKind() == DocumentKind::Part && pDocument->GetDocumentFeatureManagerFw() != nullptr; } std::string SolidModelExtrudeCommand::DisabledReason() const { - return {}; + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (!pSession) + { + return "Current session is not available."; + } + + IDocument* const pDocument = pSession->GetActiveDocument(); + if (!pDocument) + { + return "No active part document is available."; + } + + if (pDocument->IsReadOnly()) + { + return "The active document is read-only."; + } + + if (pDocument->GetDocumentKind() != DocumentKind::Part) + { + return "Extrude is currently enabled only for part documents."; + } + + if (!pDocument->GetDocumentFeatureManagerFw()) + { + return "Document feature manager is not available."; + } + + return {}; } std::unique_ptr SolidModelExtrudeCommand::Execute(const alice::CommandParameter& param) { - return nullptr; + return std::make_unique(param); } \ No newline at end of file diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureClearRollbackCommand.cpp b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureClearRollbackCommand.cpp new file mode 100644 index 00000000..fa61fb12 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureClearRollbackCommand.cpp @@ -0,0 +1,37 @@ +#include "SolidModelFeatureClearRollbackCommand.h" + +#include "AliceCoreAppUtil.h" +#include "AliceIDocument.h" +#include "AliceISession.h" +#include "SolidFeatureHistoryWorkflowBridge.h" + +using namespace sdr; +using namespace alice; + +static constexpr const char* kRollbackClearCmdId = "model.feature.rollbackClear"; + +SolidModelFeatureClearRollbackCommand::SolidModelFeatureClearRollbackCommand() noexcept + : AppCommandBase(kRollbackClearCmdId) +{ +} + +SolidModelFeatureClearRollbackCommand::~SolidModelFeatureClearRollbackCommand() = default; + +bool SolidModelFeatureClearRollbackCommand::IsSupported() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + return pDocument && pDocument->GetDocumentKind() == DocumentKind::Part && pDocument->GetDocumentFeatureManagerFw() != nullptr; +} + +bool SolidModelFeatureClearRollbackCommand::IsVisible() const { return IsSupported(); } +bool SolidModelFeatureClearRollbackCommand::IsEnabled() const { return IsSupported(); } +std::string SolidModelFeatureClearRollbackCommand::DisabledReason() const { return {}; } + +std::unique_ptr SolidModelFeatureClearRollbackCommand::Execute(const alice::CommandParameter&) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + (void)SolidFeatureHistoryWorkflowBridge::ClearRollbackCursor(pDocument); + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureClearRollbackCommand.h b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureClearRollbackCommand.h new file mode 100644 index 00000000..d20f9389 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureClearRollbackCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "BaseCommands/SolidBaseCommand.h" + +namespace sdr +{ + class SolidModelFeatureClearRollbackCommand final : public AppCommandBase + { + public: + SolidModelFeatureClearRollbackCommand() noexcept; + ~SolidModelFeatureClearRollbackCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureReorderCommand.cpp b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureReorderCommand.cpp new file mode 100644 index 00000000..ef94fe7e --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureReorderCommand.cpp @@ -0,0 +1,35 @@ +#include "SolidModelFeatureReorderCommand.h" + +#include "AliceCoreAppUtil.h" +#include "AliceIDocument.h" +#include "AliceISession.h" +#include "SolidDesignerCommands.h" +#include "SolidFeatureHistoryWorkflowBridge.h" + +using namespace sdr; +using namespace alice; + +SolidModelFeatureReorderCommand::SolidModelFeatureReorderCommand() noexcept + : AppCommandBase(std::string(Cmd::MODEL_FEATURE_REORDER)) +{ +} + +SolidModelFeatureReorderCommand::~SolidModelFeatureReorderCommand() = default; + +bool SolidModelFeatureReorderCommand::IsSupported() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + return pDocument && pDocument->GetDocumentKind() == DocumentKind::Part && pDocument->GetDocumentFeatureManagerFw() != nullptr; +} + +bool SolidModelFeatureReorderCommand::IsVisible() const { return IsSupported(); } +bool SolidModelFeatureReorderCommand::IsEnabled() const { return IsSupported(); } +std::string SolidModelFeatureReorderCommand::DisabledReason() const { return {}; } +std::unique_ptr SolidModelFeatureReorderCommand::Execute(const alice::CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + (void)SolidFeatureHistoryWorkflowBridge::ReorderFeature(pSession, pDocument, ¶m); + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureReorderCommand.h b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureReorderCommand.h new file mode 100644 index 00000000..3a2bafb1 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureReorderCommand.h @@ -0,0 +1,17 @@ +#pragma once +#include "BaseCommands/SolidBaseCommand.h" + +namespace sdr +{ + class SolidModelFeatureReorderCommand final : public AppCommandBase + { + public: + SolidModelFeatureReorderCommand() noexcept; + ~SolidModelFeatureReorderCommand() override; + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureResumeCommand.cpp b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureResumeCommand.cpp new file mode 100644 index 00000000..72201bdb --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureResumeCommand.cpp @@ -0,0 +1,44 @@ +#include "SolidModelFeatureResumeCommand.h" + +#include "AliceCoreAppUtil.h" +#include "AliceIDocument.h" +#include "AliceISession.h" +#include "SolidDesignerCommands.h" +#include "SolidFeatureHistoryWorkflowBridge.h" + +using namespace sdr; +using namespace alice; + +SolidModelFeatureResumeCommand::SolidModelFeatureResumeCommand() noexcept + : AppCommandBase(std::string(Cmd::MODEL_FEATURE_RESUME)) +{ +} + +SolidModelFeatureResumeCommand::~SolidModelFeatureResumeCommand() = default; + +bool SolidModelFeatureResumeCommand::IsSupported() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + return pDocument && pDocument->GetDocumentKind() == DocumentKind::Part && pDocument->GetDocumentFeatureManagerFw() != nullptr; +} + +bool SolidModelFeatureResumeCommand::IsVisible() const { return IsSupported(); } + +bool SolidModelFeatureResumeCommand::IsEnabled() const +{ + return IsSupported(); +} + +std::string SolidModelFeatureResumeCommand::DisabledReason() const +{ + return {}; +} + +std::unique_ptr SolidModelFeatureResumeCommand::Execute(const alice::CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + (void)SolidFeatureHistoryWorkflowBridge::ResumeFeature(pSession, pDocument, ¶m); + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureResumeCommand.h b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureResumeCommand.h new file mode 100644 index 00000000..83d80eb3 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureResumeCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "BaseCommands/SolidBaseCommand.h" + +namespace sdr +{ + class SolidModelFeatureResumeCommand final : public AppCommandBase + { + public: + SolidModelFeatureResumeCommand() noexcept; + ~SolidModelFeatureResumeCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureRollbackHereCommand.cpp b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureRollbackHereCommand.cpp new file mode 100644 index 00000000..6481ca0a --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureRollbackHereCommand.cpp @@ -0,0 +1,37 @@ +#include "SolidModelFeatureRollbackHereCommand.h" + +#include "AliceCoreAppUtil.h" +#include "AliceIDocument.h" +#include "AliceISession.h" +#include "SolidFeatureHistoryWorkflowBridge.h" + +using namespace sdr; +using namespace alice; + +static constexpr const char* kRollbackHereCmdId = "model.feature.rollbackHere"; + +SolidModelFeatureRollbackHereCommand::SolidModelFeatureRollbackHereCommand() noexcept + : AppCommandBase(kRollbackHereCmdId) +{ +} + +SolidModelFeatureRollbackHereCommand::~SolidModelFeatureRollbackHereCommand() = default; + +bool SolidModelFeatureRollbackHereCommand::IsSupported() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + return pDocument && pDocument->GetDocumentKind() == DocumentKind::Part && pDocument->GetDocumentFeatureManagerFw() != nullptr; +} + +bool SolidModelFeatureRollbackHereCommand::IsVisible() const { return IsSupported(); } +bool SolidModelFeatureRollbackHereCommand::IsEnabled() const { return IsSupported(); } +std::string SolidModelFeatureRollbackHereCommand::DisabledReason() const { return {}; } + +std::unique_ptr SolidModelFeatureRollbackHereCommand::Execute(const alice::CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + (void)SolidFeatureHistoryWorkflowBridge::SetRollbackCursorHere(pSession, pDocument, ¶m); + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureRollbackHereCommand.h b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureRollbackHereCommand.h new file mode 100644 index 00000000..e2f58335 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureRollbackHereCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "BaseCommands/SolidBaseCommand.h" + +namespace sdr +{ + class SolidModelFeatureRollbackHereCommand final : public AppCommandBase + { + public: + SolidModelFeatureRollbackHereCommand() noexcept; + ~SolidModelFeatureRollbackHereCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureSuppressCommand.cpp b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureSuppressCommand.cpp new file mode 100644 index 00000000..a4af930b --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureSuppressCommand.cpp @@ -0,0 +1,44 @@ +#include "SolidModelFeatureSuppressCommand.h" + +#include "AliceCoreAppUtil.h" +#include "AliceIDocument.h" +#include "AliceISession.h" +#include "SolidDesignerCommands.h" +#include "SolidFeatureHistoryWorkflowBridge.h" + +using namespace sdr; +using namespace alice; + +SolidModelFeatureSuppressCommand::SolidModelFeatureSuppressCommand() noexcept + : AppCommandBase(std::string(Cmd::MODEL_FEATURE_SUPPRESS)) +{ +} + +SolidModelFeatureSuppressCommand::~SolidModelFeatureSuppressCommand() = default; + +bool SolidModelFeatureSuppressCommand::IsSupported() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + return pDocument && pDocument->GetDocumentKind() == DocumentKind::Part && pDocument->GetDocumentFeatureManagerFw() != nullptr; +} + +bool SolidModelFeatureSuppressCommand::IsVisible() const { return IsSupported(); } + +bool SolidModelFeatureSuppressCommand::IsEnabled() const +{ + return IsSupported(); +} + +std::string SolidModelFeatureSuppressCommand::DisabledReason() const +{ + return {}; +} + +std::unique_ptr SolidModelFeatureSuppressCommand::Execute(const alice::CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + (void)SolidFeatureHistoryWorkflowBridge::SuppressFeature(pSession, pDocument, ¶m); + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureSuppressCommand.h b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureSuppressCommand.h new file mode 100644 index 00000000..b88350ff --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelFeatureSuppressCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "BaseCommands/SolidBaseCommand.h" + +namespace sdr +{ + class SolidModelFeatureSuppressCommand final : public AppCommandBase + { + public: + SolidModelFeatureSuppressCommand() noexcept; + ~SolidModelFeatureSuppressCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelHoleCommand.cpp b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelHoleCommand.cpp index d5dc2124..4399fdf9 100644 --- a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelHoleCommand.cpp +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelHoleCommand.cpp @@ -1,42 +1,39 @@ #include "SolidModelHoleCommand.h" #include "SolidDesignerCommands.h" +//#include "SolidHoleCreateOperation.h" +#include "AliceCommandParameter.h" +#include "AliceCoreAppUtil.h" +#include "AliceIDocument.h" +#include "AliceIDocumentFeatureManager.h" #include "AliceIOperation.h" +#include "AliceISession.h" using namespace sdr; using namespace alice; -sdr::SolidModelHoleCommand::SolidModelHoleCommand() noexcept - : AppCommandBase(std::string(Cmd::MODEL_HOLE)) -{ - -} - -sdr::SolidModelHoleCommand::~SolidModelHoleCommand() -{ - -} +sdr::SolidModelHoleCommand::SolidModelHoleCommand() noexcept : AppCommandBase(std::string(Cmd::MODEL_HOLE)) {} +sdr::SolidModelHoleCommand::~SolidModelHoleCommand() = default; bool SolidModelHoleCommand::IsSupported() const { - return false; + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + return pDocument && pDocument->GetDocumentKind() == DocumentKind::Part && pDocument->GetDocumentFeatureManagerFw() != nullptr; } -bool SolidModelHoleCommand::IsVisible() const -{ - return false; -} +bool SolidModelHoleCommand::IsVisible() const { return IsSupported(); } bool SolidModelHoleCommand::IsEnabled() const { - return false; + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + return pDocument && !pDocument->IsReadOnly() && pDocument->GetDocumentKind() == DocumentKind::Part && pDocument->GetDocumentFeatureManagerFw() != nullptr; } -std::string SolidModelHoleCommand::DisabledReason() const -{ - return {}; -} +std::string SolidModelHoleCommand::DisabledReason() const { return IsEnabled() ? std::string{} : std::string("Hole is currently enabled only for writable part documents."); } std::unique_ptr SolidModelHoleCommand::Execute(const alice::CommandParameter& param) { - return nullptr; + //return std::make_unique(param); + return nullptr; } \ No newline at end of file diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelRevolveCommand.cpp b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelRevolveCommand.cpp index 709cb3e6..c5465c3b 100644 --- a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelRevolveCommand.cpp +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelRevolveCommand.cpp @@ -1,42 +1,39 @@ #include "SolidModelRevolveCommand.h" #include "SolidDesignerCommands.h" +//#include "SolidRevolveCreateOperation.h" +#include "AliceCommandParameter.h" +#include "AliceCoreAppUtil.h" +#include "AliceIDocument.h" +#include "AliceIDocumentFeatureManager.h" #include "AliceIOperation.h" +#include "AliceISession.h" using namespace sdr; using namespace alice; -sdr::SolidModelRevolveCommand::SolidModelRevolveCommand() noexcept - : AppCommandBase(std::string(Cmd::MODEL_REVOLVE)) -{ - -} - -sdr::SolidModelRevolveCommand::~SolidModelRevolveCommand() -{ - -} +sdr::SolidModelRevolveCommand::SolidModelRevolveCommand() noexcept : AppCommandBase(std::string(Cmd::MODEL_REVOLVE)) {} +sdr::SolidModelRevolveCommand::~SolidModelRevolveCommand() = default; bool SolidModelRevolveCommand::IsSupported() const { - return false; + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + return pDocument && pDocument->GetDocumentKind() == DocumentKind::Part && pDocument->GetDocumentFeatureManagerFw() != nullptr; } -bool SolidModelRevolveCommand::IsVisible() const -{ - return false; -} +bool SolidModelRevolveCommand::IsVisible() const { return IsSupported(); } bool SolidModelRevolveCommand::IsEnabled() const { - return false; + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + return pDocument && !pDocument->IsReadOnly() && pDocument->GetDocumentKind() == DocumentKind::Part && pDocument->GetDocumentFeatureManagerFw() != nullptr; } -std::string SolidModelRevolveCommand::DisabledReason() const -{ - return {}; -} +std::string SolidModelRevolveCommand::DisabledReason() const { return IsEnabled() ? std::string{} : std::string("Revolve is currently enabled only for writable part documents."); } std::unique_ptr SolidModelRevolveCommand::Execute(const alice::CommandParameter& param) { - return nullptr; + //return std::make_unique(param); + return nullptr; } \ No newline at end of file diff --git a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelSweepCommand.cpp b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelSweepCommand.cpp index 24497de6..26053200 100644 --- a/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelSweepCommand.cpp +++ b/Designer/UI/SolidDesignerCommand/ModelCommands/SolidModelSweepCommand.cpp @@ -1,42 +1,50 @@ #include "SolidModelSweepCommand.h" #include "SolidDesignerCommands.h" +//#include "SolidSweepCreateOperation.h" +#include "AliceCommandParameter.h" +#include "AliceCoreAppUtil.h" +#include "AliceIDocument.h" +#include "AliceIDocumentFeatureManager.h" #include "AliceIOperation.h" +#include "AliceISession.h" using namespace sdr; using namespace alice; -sdr::SolidModelSweepCommand::SolidModelSweepCommand() noexcept - : AppCommandBase(std::string(Cmd::MODEL_SWEEP)) +sdr::SolidModelSweepCommand::SolidModelSweepCommand() noexcept + : AppCommandBase(std::string(Cmd::MODEL_SWEEP)) { } -sdr::SolidModelSweepCommand::~SolidModelSweepCommand() -{ - -} +sdr::SolidModelSweepCommand::~SolidModelSweepCommand() = default; bool SolidModelSweepCommand::IsSupported() const { - return false; + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + return pDocument && pDocument->GetDocumentKind() == DocumentKind::Part && pDocument->GetDocumentFeatureManagerFw() != nullptr; } -bool SolidModelSweepCommand::IsVisible() const -{ - return false; +bool SolidModelSweepCommand::IsVisible() const +{ + return IsSupported(); } bool SolidModelSweepCommand::IsEnabled() const { - return false; + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + IDocument* const pDocument = pSession ? pSession->GetActiveDocument() : nullptr; + return pDocument && !pDocument->IsReadOnly() && pDocument->GetDocumentKind() == DocumentKind::Part && pDocument->GetDocumentFeatureManagerFw() != nullptr; } -std::string SolidModelSweepCommand::DisabledReason() const -{ - return {}; +std::string SolidModelSweepCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string("Sweep is currently enabled only for writable part documents."); } std::unique_ptr SolidModelSweepCommand::Execute(const alice::CommandParameter& param) { - return nullptr; + //return std::make_unique(param); + return nullptr; } \ No newline at end of file diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchArcCommand.cpp b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchArcCommand.cpp new file mode 100644 index 00000000..4c887f4c --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchArcCommand.cpp @@ -0,0 +1,47 @@ +#include "SolidSketchArcCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidSectionEditOperation.h" +#include "SolidExtrudeCreateOperation.h" + +using namespace sdr; +using namespace alice; + +SolidSketchArcCommand::SolidSketchArcCommand() noexcept + : AppCommandBase(std::string(Cmd::SKETCH_ARC)) +{ +} + +SolidSketchArcCommand::~SolidSketchArcCommand() = default; + +bool SolidSketchArcCommand::IsSupported() const +{ + return true; +} + +bool SolidSketchArcCommand::IsVisible() const +{ + return true; +} + +bool SolidSketchArcCommand::IsEnabled() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return (SolidSectionEditOperation::FindActive(pSession) != nullptr); +} + +std::string SolidSketchArcCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"No active extrude/section workflow."}; +} + +std::unique_ptr SolidSketchArcCommand::Execute(const CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (auto* const pOp = SolidSectionEditOperation::FindActive(pSession)) + { + pOp->ActivateArcTool(); + } + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchArcCommand.h b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchArcCommand.h new file mode 100644 index 00000000..25c88d2a --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchArcCommand.h @@ -0,0 +1,24 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace alice +{ + struct CommandParameter; + class IOperation; +} + +namespace sdr +{ + class SolidSketchArcCommand final : public AppCommandBase + { + public: + SolidSketchArcCommand() noexcept; + ~SolidSketchArcCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchCancelCommand.cpp b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchCancelCommand.cpp new file mode 100644 index 00000000..92878822 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchCancelCommand.cpp @@ -0,0 +1,47 @@ +#include "SolidSketchCancelCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidSectionEditOperation.h" +#include "SolidExtrudeCreateOperation.h" + +using namespace sdr; +using namespace alice; + +SolidSketchCancelCommand::SolidSketchCancelCommand() noexcept + : AppCommandBase(std::string(Cmd::SKETCH_CANCEL)) +{ +} + +SolidSketchCancelCommand::~SolidSketchCancelCommand() = default; + +bool SolidSketchCancelCommand::IsSupported() const +{ + return true; +} + +bool SolidSketchCancelCommand::IsVisible() const +{ + return true; +} + +bool SolidSketchCancelCommand::IsEnabled() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return (SolidSectionEditOperation::FindActive(pSession) != nullptr); +} + +std::string SolidSketchCancelCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"No active extrude/section workflow."}; +} + +std::unique_ptr SolidSketchCancelCommand::Execute(const CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (auto* const pOp = SolidSectionEditOperation::FindActive(pSession)) + { + pOp->ExecuteSectionCancel(); + } + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchCancelCommand.h b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchCancelCommand.h new file mode 100644 index 00000000..23ac55b4 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchCancelCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "BaseCommands/SolidBaseCommand.h" + +namespace sdr +{ + class SolidSketchCancelCommand final : public AppCommandBase + { + public: + SolidSketchCancelCommand() noexcept; + ~SolidSketchCancelCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchCircleCommand.cpp b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchCircleCommand.cpp new file mode 100644 index 00000000..51a2a286 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchCircleCommand.cpp @@ -0,0 +1,47 @@ +#include "SolidSketchCircleCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidSectionEditOperation.h" +#include "SolidExtrudeCreateOperation.h" + +using namespace sdr; +using namespace alice; + +SolidSketchCircleCommand::SolidSketchCircleCommand() noexcept + : AppCommandBase(std::string(Cmd::SKETCH_CIRCLE)) +{ +} + +SolidSketchCircleCommand::~SolidSketchCircleCommand() = default; + +bool SolidSketchCircleCommand::IsSupported() const +{ + return true; +} + +bool SolidSketchCircleCommand::IsVisible() const +{ + return true; +} + +bool SolidSketchCircleCommand::IsEnabled() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return (SolidSectionEditOperation::FindActive(pSession) != nullptr); +} + +std::string SolidSketchCircleCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"No active extrude/section workflow."}; +} + +std::unique_ptr SolidSketchCircleCommand::Execute(const CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (auto* const pOp = SolidSectionEditOperation::FindActive(pSession)) + { + pOp->ActivateCircleTool(); + } + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchCircleCommand.h b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchCircleCommand.h new file mode 100644 index 00000000..8dac24f4 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchCircleCommand.h @@ -0,0 +1,24 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace alice +{ + struct CommandParameter; + class IOperation; +} + +namespace sdr +{ + class SolidSketchCircleCommand final : public AppCommandBase + { + public: + SolidSketchCircleCommand() noexcept; + ~SolidSketchCircleCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchConstraintCommand.cpp b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchConstraintCommand.cpp new file mode 100644 index 00000000..77dd4b51 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchConstraintCommand.cpp @@ -0,0 +1,44 @@ +#include "SolidSketchConstraintCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidSectionEditOperation.h" + +using namespace sdr; +using namespace alice; + +SolidSketchConstraintCommand::SolidSketchConstraintCommand() noexcept + : AppCommandBase(std::string(Cmd::SKETCH_CONSTRAINT_COINCIDENT)) +{ +} + +SolidSketchConstraintCommand::~SolidSketchConstraintCommand() = default; + +bool SolidSketchConstraintCommand::IsSupported() const +{ + return true; +} + +bool SolidSketchConstraintCommand::IsVisible() const +{ + return true; +} + +bool SolidSketchConstraintCommand::IsEnabled() const +{ + return SolidSectionEditOperation::FindActive(CoreAppUtil::GetCurrentSession()) != nullptr; +} + +std::string SolidSketchConstraintCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"No active section editing operation."}; +} + +std::unique_ptr SolidSketchConstraintCommand::Execute(const CommandParameter&) +{ + if (auto* const pOp = SolidSectionEditOperation::FindActive(CoreAppUtil::GetCurrentSession())) + { + pOp->ExecuteConstraintCommand(); + } + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchConstraintCommand.h b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchConstraintCommand.h new file mode 100644 index 00000000..8a6adc70 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchConstraintCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace sdr +{ + class SolidSketchConstraintCommand final : public AppCommandBase + { + public: + SolidSketchConstraintCommand() noexcept; + ~SolidSketchConstraintCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchDefineInternalCommand.cpp b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchDefineInternalCommand.cpp new file mode 100644 index 00000000..787c46ac --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchDefineInternalCommand.cpp @@ -0,0 +1,47 @@ +#include "SolidSketchDefineInternalCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidSectionEditOperation.h" +#include "SolidExtrudeCreateOperation.h" + +using namespace sdr; +using namespace alice; + +SolidSketchDefineInternalCommand::SolidSketchDefineInternalCommand() noexcept + : AppCommandBase(std::string(Cmd::SKETCH_DEFINEINTERNAL)) +{ +} + +SolidSketchDefineInternalCommand::~SolidSketchDefineInternalCommand() = default; + +bool SolidSketchDefineInternalCommand::IsSupported() const +{ + return true; +} + +bool SolidSketchDefineInternalCommand::IsVisible() const +{ + return true; +} + +bool SolidSketchDefineInternalCommand::IsEnabled() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return (SolidExtrudeCreateOperation::FindActive(pSession) != nullptr); +} + +std::string SolidSketchDefineInternalCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"No active extrude/section workflow."}; +} + +std::unique_ptr SolidSketchDefineInternalCommand::Execute(const CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (auto* const pOp = SolidExtrudeCreateOperation::FindActive(pSession)) + { + (void)pOp->BeginDefineInternalSketchPlacement(); + } + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchDefineInternalCommand.h b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchDefineInternalCommand.h new file mode 100644 index 00000000..1e3f9e93 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchDefineInternalCommand.h @@ -0,0 +1,19 @@ +#pragma once + +#include "BaseCommands/SolidBaseCommand.h" + +namespace sdr +{ + class SolidSketchDefineInternalCommand final : public sdr::AppCommandBase + { + public: + SolidSketchDefineInternalCommand() noexcept; + ~SolidSketchDefineInternalCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchDimensionCommand.cpp b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchDimensionCommand.cpp new file mode 100644 index 00000000..5b24b3f6 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchDimensionCommand.cpp @@ -0,0 +1,45 @@ +#include "SolidSketchDimensionCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidSectionEditOperation.h" + +using namespace sdr; +using namespace alice; + +SolidSketchDimensionCommand::SolidSketchDimensionCommand() noexcept + : AppCommandBase(std::string(Cmd::SKETCH_DIM_DIMENSION)) +{ +} + +SolidSketchDimensionCommand::~SolidSketchDimensionCommand() = default; + +bool SolidSketchDimensionCommand::IsSupported() const +{ + return true; +} + +bool SolidSketchDimensionCommand::IsVisible() const +{ + return true; +} + +bool SolidSketchDimensionCommand::IsEnabled() const +{ + //TODO: Wrong way + return SolidSectionEditOperation::FindActive(CoreAppUtil::GetCurrentSession()) != nullptr; +} + +std::string SolidSketchDimensionCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"No active section editing operation."}; +} + +std::unique_ptr SolidSketchDimensionCommand::Execute(const CommandParameter&) +{ + if (auto* const pOp = SolidSectionEditOperation::FindActive(CoreAppUtil::GetCurrentSession())) + { + pOp->ExecuteDimensionCommand(); + } + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchDimensionCommand.h b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchDimensionCommand.h new file mode 100644 index 00000000..4bc307c3 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchDimensionCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace sdr +{ + class SolidSketchDimensionCommand final : public AppCommandBase + { + public: + SolidSketchDimensionCommand() noexcept; + ~SolidSketchDimensionCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchEditCommand.cpp b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchEditCommand.cpp new file mode 100644 index 00000000..8dab4305 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchEditCommand.cpp @@ -0,0 +1,47 @@ +#include "SolidSketchEditCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidSectionEditOperation.h" +#include "SolidExtrudeCreateOperation.h" + +using namespace sdr; +using namespace alice; + +SolidSketchEditCommand::SolidSketchEditCommand() noexcept + : AppCommandBase(std::string(Cmd::SKETCH_EDIT)) +{ +} + +SolidSketchEditCommand::~SolidSketchEditCommand() = default; + +bool SolidSketchEditCommand::IsSupported() const +{ + return true; +} + +bool SolidSketchEditCommand::IsVisible() const +{ + return true; +} + +bool SolidSketchEditCommand::IsEnabled() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return (SolidExtrudeCreateOperation::FindActive(pSession) != nullptr); +} + +std::string SolidSketchEditCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"No active extrude/section workflow."}; +} + +std::unique_ptr SolidSketchEditCommand::Execute(const CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (auto* const pOp = SolidExtrudeCreateOperation::FindActive(pSession)) + { + (void)pOp->EditSectionSketch(); + } + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchEditCommand.h b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchEditCommand.h new file mode 100644 index 00000000..a6b3f43b --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchEditCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace sdr +{ + class SolidSketchEditCommand final : public AppCommandBase + { + public: + SolidSketchEditCommand() noexcept; + ~SolidSketchEditCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& pCmdParam) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchEllipseCommand.cpp b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchEllipseCommand.cpp new file mode 100644 index 00000000..47017f8f --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchEllipseCommand.cpp @@ -0,0 +1,47 @@ +#include "SolidSketchEllipseCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidSectionEditOperation.h" +#include "SolidExtrudeCreateOperation.h" + +using namespace sdr; +using namespace alice; + +SolidSketchEllipseCommand::SolidSketchEllipseCommand() noexcept + : AppCommandBase(std::string(Cmd::SKETCH_ELLIPSE)) +{ +} + +SolidSketchEllipseCommand::~SolidSketchEllipseCommand() = default; + +bool SolidSketchEllipseCommand::IsSupported() const +{ + return true; +} + +bool SolidSketchEllipseCommand::IsVisible() const +{ + return true; +} + +bool SolidSketchEllipseCommand::IsEnabled() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return (SolidSectionEditOperation::FindActive(pSession) != nullptr); +} + +std::string SolidSketchEllipseCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"No active extrude/section workflow."}; +} + +std::unique_ptr SolidSketchEllipseCommand::Execute(const CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (auto* const pOp = SolidSectionEditOperation::FindActive(pSession)) + { + pOp->ActivateEllipseTool(); + } + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchEllipseCommand.h b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchEllipseCommand.h new file mode 100644 index 00000000..96114813 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchEllipseCommand.h @@ -0,0 +1,20 @@ +#pragma once +#include "SolidBaseCommand.h" + +#include + +namespace sdr +{ + class SolidSketchEllipseCommand final : public AppCommandBase + { + public: + explicit SolidSketchEllipseCommand() noexcept; + ~SolidSketchEllipseCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchFlipSectionOrientationCommand.cpp b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchFlipSectionOrientationCommand.cpp new file mode 100644 index 00000000..aa783150 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchFlipSectionOrientationCommand.cpp @@ -0,0 +1,47 @@ +#include "SolidSketchFlipSectionOrientationCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidSectionEditOperation.h" +#include "SolidExtrudeCreateOperation.h" + +using namespace sdr; +using namespace alice; + +SolidSketchFlipSectionOrientationCommand::SolidSketchFlipSectionOrientationCommand() noexcept + : AppCommandBase(std::string(Cmd::SKETCH_SECTION_FLIPSECTIONORIENTATION)) +{ +} + +SolidSketchFlipSectionOrientationCommand::~SolidSketchFlipSectionOrientationCommand() = default; + +bool SolidSketchFlipSectionOrientationCommand::IsSupported() const +{ + return true; +} + +bool SolidSketchFlipSectionOrientationCommand::IsVisible() const +{ + return true; +} + +bool SolidSketchFlipSectionOrientationCommand::IsEnabled() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return (SolidExtrudeCreateOperation::FindActive(pSession) != nullptr); +} + +std::string SolidSketchFlipSectionOrientationCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"No active extrude/section workflow."}; +} + +std::unique_ptr SolidSketchFlipSectionOrientationCommand::Execute(const CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (auto* const pOp = SolidExtrudeCreateOperation::FindActive(pSession)) + { + (void)pOp->FlipSectionOrientation(); + } + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchFlipSectionOrientationCommand.h b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchFlipSectionOrientationCommand.h new file mode 100644 index 00000000..3fcd6779 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchFlipSectionOrientationCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace sdr +{ + class SolidSketchFlipSectionOrientationCommand final : public AppCommandBase + { + public: + SolidSketchFlipSectionOrientationCommand() noexcept; + ~SolidSketchFlipSectionOrientationCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& pCmdParam) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchLineCommand.cpp b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchLineCommand.cpp new file mode 100644 index 00000000..861f3844 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchLineCommand.cpp @@ -0,0 +1,47 @@ +#include "SolidSketchLineCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidSectionEditOperation.h" +#include "SolidExtrudeCreateOperation.h" + +using namespace sdr; +using namespace alice; + +SolidSketchLineCommand::SolidSketchLineCommand() noexcept + : AppCommandBase(std::string(Cmd::SKETCH_LINE)) +{ +} + +SolidSketchLineCommand::~SolidSketchLineCommand() = default; + +bool SolidSketchLineCommand::IsSupported() const +{ + return true; +} + +bool SolidSketchLineCommand::IsVisible() const +{ + return true; +} + +bool SolidSketchLineCommand::IsEnabled() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return (SolidSectionEditOperation::FindActive(pSession) != nullptr); +} + +std::string SolidSketchLineCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"No active extrude/section workflow."}; +} + +std::unique_ptr SolidSketchLineCommand::Execute(const CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (auto* const pOp = SolidSectionEditOperation::FindActive(pSession)) + { + pOp->ActivateLineTool(); + } + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchLineCommand.h b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchLineCommand.h new file mode 100644 index 00000000..47abf8f9 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchLineCommand.h @@ -0,0 +1,24 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace alice +{ + struct CommandParameter; + class IOperation; +} + +namespace sdr +{ + class SolidSketchLineCommand final : public AppCommandBase + { + public: + SolidSketchLineCommand() noexcept; + ~SolidSketchLineCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchOkCommand.cpp b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchOkCommand.cpp new file mode 100644 index 00000000..051bd387 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchOkCommand.cpp @@ -0,0 +1,47 @@ +#include "SolidSketchOkCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidSectionEditOperation.h" +#include "SolidExtrudeCreateOperation.h" + +using namespace sdr; +using namespace alice; + +SolidSketchOkCommand::SolidSketchOkCommand() noexcept + : AppCommandBase(std::string(Cmd::SKETCH_OK)) +{ +} + +SolidSketchOkCommand::~SolidSketchOkCommand() = default; + +bool SolidSketchOkCommand::IsSupported() const +{ + return true; +} + +bool SolidSketchOkCommand::IsVisible() const +{ + return true; +} + +bool SolidSketchOkCommand::IsEnabled() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return (SolidSectionEditOperation::FindActive(pSession) != nullptr); +} + +std::string SolidSketchOkCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"No active extrude/section workflow."}; +} + +std::unique_ptr SolidSketchOkCommand::Execute(const CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (auto* const pOp = SolidSectionEditOperation::FindActive(pSession)) + { + pOp->ExecuteSectionOk(); + } + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchOkCommand.h b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchOkCommand.h new file mode 100644 index 00000000..56998639 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchOkCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "BaseCommands/SolidBaseCommand.h" + +namespace sdr +{ + class SolidSketchOkCommand final : public AppCommandBase + { + public: + SolidSketchOkCommand() noexcept; + ~SolidSketchOkCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchRectangleCommand.cpp b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchRectangleCommand.cpp new file mode 100644 index 00000000..15fbdb8c --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchRectangleCommand.cpp @@ -0,0 +1,47 @@ +#include "SolidSketchRectangleCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidSectionEditOperation.h" +#include "SolidExtrudeCreateOperation.h" + +using namespace sdr; +using namespace alice; + +SolidSketchRectangleCommand::SolidSketchRectangleCommand() noexcept + : AppCommandBase(std::string(Cmd::SKETCH_RECTANGLE)) +{ +} + +SolidSketchRectangleCommand::~SolidSketchRectangleCommand() = default; + +bool SolidSketchRectangleCommand::IsSupported() const +{ + return true; +} + +bool SolidSketchRectangleCommand::IsVisible() const +{ + return true; +} + +bool SolidSketchRectangleCommand::IsEnabled() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return (SolidSectionEditOperation::FindActive(pSession) != nullptr); +} + +std::string SolidSketchRectangleCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"No active extrude/section workflow."}; +} + +std::unique_ptr SolidSketchRectangleCommand::Execute(const CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (auto* const pOp = SolidSectionEditOperation::FindActive(pSession)) + { + pOp->ActivateRectangleTool(); + } + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchRectangleCommand.h b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchRectangleCommand.h new file mode 100644 index 00000000..cbde9b53 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchRectangleCommand.h @@ -0,0 +1,20 @@ +#pragma once +#include "SolidBaseCommand.h" + +#include + +namespace sdr +{ + class SolidSketchRectangleCommand final : public AppCommandBase + { + public: + explicit SolidSketchRectangleCommand() noexcept; + ~SolidSketchRectangleCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchRestoreSectionOrientationCommand.cpp b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchRestoreSectionOrientationCommand.cpp new file mode 100644 index 00000000..345c4254 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchRestoreSectionOrientationCommand.cpp @@ -0,0 +1,47 @@ +#include "SolidSketchRestoreSectionOrientationCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidSectionEditOperation.h" +#include "SolidExtrudeCreateOperation.h" + +using namespace sdr; +using namespace alice; + +SolidSketchRestoreSectionOrientationCommand::SolidSketchRestoreSectionOrientationCommand() noexcept + : AppCommandBase(std::string(Cmd::SKETCH_SECTION_RESTORESECTIONORIENTATION)) +{ +} + +SolidSketchRestoreSectionOrientationCommand::~SolidSketchRestoreSectionOrientationCommand() = default; + +bool SolidSketchRestoreSectionOrientationCommand::IsSupported() const +{ + return true; +} + +bool SolidSketchRestoreSectionOrientationCommand::IsVisible() const +{ + return true; +} + +bool SolidSketchRestoreSectionOrientationCommand::IsEnabled() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return (SolidExtrudeCreateOperation::FindActive(pSession) != nullptr); +} + +std::string SolidSketchRestoreSectionOrientationCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"No active extrude/section workflow."}; +} + +std::unique_ptr SolidSketchRestoreSectionOrientationCommand::Execute(const CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (auto* const pOp = SolidExtrudeCreateOperation::FindActive(pSession)) + { + (void)pOp->RestoreSectionOrientation(); + } + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchRestoreSectionOrientationCommand.h b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchRestoreSectionOrientationCommand.h new file mode 100644 index 00000000..766f3b34 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchRestoreSectionOrientationCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace sdr +{ + class SolidSketchRestoreSectionOrientationCommand final : public AppCommandBase + { + public: + SolidSketchRestoreSectionOrientationCommand() noexcept; + ~SolidSketchRestoreSectionOrientationCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& pCmdParam) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchReuseCommand.cpp b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchReuseCommand.cpp new file mode 100644 index 00000000..65459384 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchReuseCommand.cpp @@ -0,0 +1,47 @@ +#include "SolidSketchReuseCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidSectionEditOperation.h" +#include "SolidExtrudeCreateOperation.h" + +using namespace sdr; +using namespace alice; + +SolidSketchReuseCommand::SolidSketchReuseCommand() noexcept + : AppCommandBase(std::string(Cmd::SKETCH_REUSE)) +{ +} + +SolidSketchReuseCommand::~SolidSketchReuseCommand() = default; + +bool SolidSketchReuseCommand::IsSupported() const +{ + return true; +} + +bool SolidSketchReuseCommand::IsVisible() const +{ + return true; +} + +bool SolidSketchReuseCommand::IsEnabled() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return (SolidExtrudeCreateOperation::FindActive(pSession) != nullptr); +} + +std::string SolidSketchReuseCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"No active extrude/section workflow."}; +} + +std::unique_ptr SolidSketchReuseCommand::Execute(const CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (auto* const pOp = SolidExtrudeCreateOperation::FindActive(pSession)) + { + (void)pOp->BeginReuseExistingSketchSelection(); + } + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchReuseCommand.h b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchReuseCommand.h new file mode 100644 index 00000000..fb4e51c4 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchReuseCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace sdr +{ + class SolidSketchReuseCommand final : public AppCommandBase + { + public: + SolidSketchReuseCommand() noexcept; + ~SolidSketchReuseCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& pCmdParam) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchSelectCommand.cpp b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchSelectCommand.cpp new file mode 100644 index 00000000..11c986a6 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchSelectCommand.cpp @@ -0,0 +1,47 @@ +#include "SolidSketchSelectCommand.h" +#include "SolidDesignerCommands.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" +#include "SolidSectionEditOperation.h" +#include "SolidExtrudeCreateOperation.h" + +using namespace sdr; +using namespace alice; + +SolidSketchSelectCommand::SolidSketchSelectCommand() noexcept + : AppCommandBase(std::string(Cmd::SKETCH_SELECT)) +{ +} + +SolidSketchSelectCommand::~SolidSketchSelectCommand() = default; + +bool SolidSketchSelectCommand::IsSupported() const +{ + return true; +} + +bool SolidSketchSelectCommand::IsVisible() const +{ + return true; +} + +bool SolidSketchSelectCommand::IsEnabled() const +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return (SolidSectionEditOperation::FindActive(pSession) != nullptr); +} + +std::string SolidSketchSelectCommand::DisabledReason() const +{ + return IsEnabled() ? std::string{} : std::string{"No active extrude/section workflow."}; +} + +std::unique_ptr SolidSketchSelectCommand::Execute(const CommandParameter& param) +{ + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (auto* const pOp = SolidSectionEditOperation::FindActive(pSession)) + { + pOp->ActivateSelectionTool(); + } + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchSelectCommand.h b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchSelectCommand.h new file mode 100644 index 00000000..b463c78a --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/SketchCommands/SolidSketchSelectCommand.h @@ -0,0 +1,24 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace alice +{ + struct CommandParameter; + class IOperation; +} + +namespace sdr +{ + class SolidSketchSelectCommand final : public AppCommandBase + { + public: + SolidSketchSelectCommand() noexcept; + ~SolidSketchSelectCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/SolidDesignerCommandFactory.cpp b/Designer/UI/SolidDesignerCommand/SolidDesignerCommandFactory.cpp index 8e4d8fb5..8d3ac8a4 100644 --- a/Designer/UI/SolidDesignerCommand/SolidDesignerCommandFactory.cpp +++ b/Designer/UI/SolidDesignerCommand/SolidDesignerCommandFactory.cpp @@ -1,75 +1,116 @@ #include "SolidDesignerCommandFactory.h" + +#include "EditCommands/SolidEditCopyCommand.h" +#include "EditCommands/SolidEditCutCommand.h" +#include "EditCommands/SolidEditDeleteCommand.h" +#include "EditCommands/SolidEditPasteCommand.h" +#include "EditCommands/SolidEditRedoCommand.h" +#include "EditCommands/SolidEditSelectAllCommand.h" #include "EditCommands/SolidEditUndoCommand.h" +#include "EditCommands/SolidSelectSingleCommand.h" +#include "GeneralCommands/SolidFileCloseCommand.h" +#include "GeneralCommands/SolidFileExitCommand.h" #include "GeneralCommands/SolidFileNewCommand.h" #include "GeneralCommands/SolidFileOpenCommand.h" -#include "GeneralCommands/SolidFileSaveCommand.h" #include "GeneralCommands/SolidFileSaveAsCommand.h" -#include "GeneralCommands/SolidFileCloseCommand.h" -#include "GeneralCommands/SolidFileExitCommand.h" -#include "GeneralCommands/SolidSettingsOptionsCommand.h" +#include "GeneralCommands/SolidFileSaveCommand.h" #include "GeneralCommands/SolidManageFileRenameCommand.h" #include "GeneralCommands/SolidSelectWorkingDirectoryCommand.h" #include "GeneralCommands/SolidSessionObjectListCommand.h" +#include "GeneralCommands/SolidSettingsOptionsCommand.h" #include "HelpCommands/SolidHelpAboutCommand.h" #include "HelpCommands/SolidHelpContentsCommand.h" -#include "ModelCommands/SolidModelBlendCommand.h" +#include "ModelCommands/SolidExtrudeDashboardApplyCommand.h" +#include "ModelCommands/SolidExtrudeCancelCommand.h" +#include "ModelCommands/SolidExtrudeOkCommand.h" +#include "ModelCommands/SolidModelEditDefinitionCommand.h" #include "ModelCommands/SolidModelExtrudeCommand.h" -#include "ModelCommands/SolidModelHelicalSweepCommand.h" -#include "ModelCommands/SolidModelHoleCommand.h" -#include "ModelCommands/SolidModelRevolveCommand.h" -#include "ModelCommands/SolidModelRotationalBlendCommand.h" -#include "ModelCommands/SolidModelSweepCommand.h" -#include "ModelCommands/SolidModelSweptBlendCommand.h" -#include "ModelCommands/SolidModelVolumeHelicalSweepCommand.h" -#include "EditCommands/SolidEditCopyCommand.h" -#include "EditCommands/SolidEditCutCommand.h" -#include "EditCommands/SolidEditDeleteCommand.h" -#include "EditCommands/SolidEditPasteCommand.h" -#include "EditCommands/SolidEditRedoCommand.h" -#include "EditCommands/SolidEditSelectAllCommand.h" +#include "SketchCommands/SolidSketchArcCommand.h" +#include "SketchCommands/SolidSketchCancelCommand.h" +#include "SketchCommands/SolidSketchCircleCommand.h" +#include "SketchCommands/SolidSketchConstraintCommand.h" +#include "SketchCommands/SolidSketchDefineInternalCommand.h" +#include "SketchCommands/SolidSketchDimensionCommand.h" +#include "SketchCommands/SolidSketchEditCommand.h" +#include "SketchCommands/SolidSketchEllipseCommand.h" +#include "SketchCommands/SolidSketchFlipSectionOrientationCommand.h" +#include "SketchCommands/SolidSketchLineCommand.h" +#include "SketchCommands/SolidSketchOkCommand.h" +#include "SketchCommands/SolidSketchRectangleCommand.h" +#include "SketchCommands/SolidSketchRestoreSectionOrientationCommand.h" +#include "SketchCommands/SolidSketchReuseCommand.h" +#include "SketchCommands/SolidSketchSelectCommand.h" +#include "ViewCommands/SolidRenderBackendSwitchCommand.h" +#include "ViewCommands/SolidViewCubeCommand.h" +#include "ViewCommands/SolidViewFitAllCommand.h" +#include "ViewCommands/SolidViewFrontCommand.h" +#include "ViewCommands/SolidViewLookNormalToSketchPlaneCommand.h" +#include "ViewCommands/SolidViewRightCommand.h" +#include "ViewCommands/SolidViewTopCommand.h" +#include "ViewCommands/SolidViewTrimetricCommand.h" using namespace sdr; -sdr::SolidDesignerCommandFactory& SolidDesignerCommandFactory::GetInstance() +SolidDesignerCommandFactory& SolidDesignerCommandFactory::GetInstance() { - static SolidDesignerCommandFactory s_Instance; - return s_Instance; + static SolidDesignerCommandFactory s_Instance; + return s_Instance; } std::vector> SolidDesignerCommandFactory::CreateCommands() { - std::vector> vecCommands; - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - vecCommands.emplace_back(std::make_shared()); - - return vecCommands; + std::vector> vecCommands; + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared()); + vecCommands.emplace_back(std::make_shared("view.renderBackend.occ", alice::RenderBackendId::OCC)); + vecCommands.emplace_back(std::make_shared("view.renderBackend.skylark", alice::RenderBackendId::Skylark)); + vecCommands.emplace_back(std::make_shared("view.renderBackend.vtk", alice::RenderBackendId::VTK)); + vecCommands.emplace_back(std::make_shared("view.renderBackend.osg", alice::RenderBackendId::OSG)); + vecCommands.emplace_back(std::make_shared("view.renderBackend.ogre", alice::RenderBackendId::OGRE)); + return vecCommands; } diff --git a/Designer/UI/SolidDesignerCommand/SolidDesignerCommands.h b/Designer/UI/SolidDesignerCommand/SolidDesignerCommands.h index 33907b73..115f3cda 100644 --- a/Designer/UI/SolidDesignerCommand/SolidDesignerCommands.h +++ b/Designer/UI/SolidDesignerCommand/SolidDesignerCommands.h @@ -157,6 +157,11 @@ namespace sdr inline constexpr std::string_view MEASURE_RADIUS = "measure.radius"; // Radius inline constexpr std::string_view MEASURE_SECTION = "measure.section"; // Section Measurement + // === Category: model === + inline constexpr std::string_view FEATURE_EXTRUDE_CANCEL = "feature.extrude.cancel"; // Cancel + inline constexpr std::string_view FEATURE_EXTRUDE_DASHBOARD_APPLY = "feature.extrude.dashboard.apply"; // Apply Extrude Dashboard + inline constexpr std::string_view FEATURE_EXTRUDE_OK = "feature.extrude.ok"; // OK + // === Category: model.getData === inline constexpr std::string_view MODEL_GETDATA_COPYFROM = "model.getData.copyFrom"; // Copy From inline constexpr std::string_view MODEL_GETDATA_COPYGEOMETRY = "model.getData.copyGeometry"; // Copy Geometry @@ -240,6 +245,7 @@ namespace sdr inline constexpr std::string_view SKETCH_CONSTRCUTION_CS = "sketch.constrcution.cs"; // Coordinate System inline constexpr std::string_view SKETCH_CONSTRUCTION_CENTERLINE = "sketch.construction.centerline"; // Centerline inline constexpr std::string_view SKETCH_CONSTRUCTION_POINT = "sketch.construction.point"; // Construction Point + inline constexpr std::string_view SKETCH_DEFINEINTERNAL = "sketch.defineInternal"; // Define Internal Sketch inline constexpr std::string_view SKETCH_DISPLAY_CONSTRAINTS = "sketch.display.constraints"; // Constraints Display inline constexpr std::string_view SKETCH_DISPLAY_DIMENSIONS = "sketch.display.dimensions"; // Dimensions Display inline constexpr std::string_view SKETCH_DISPLAY_GRID = "sketch.display.grid"; // Grid Display @@ -389,10 +395,18 @@ namespace sdr // === Category: view === inline constexpr std::string_view VIEW_CLIPPINGPLANE = "view.clippingPlane"; // Clipping Plane inline constexpr std::string_view VIEW_DYNAMICSECTION = "view.dynamicSection"; // Dynamic Section + inline constexpr std::string_view VIEW_FITALL = "view.fitAll"; // Fit All inline constexpr std::string_view VIEW_FRONT = "view.front"; // Front + inline constexpr std::string_view VIEW_LOOKNORMALTOSKETCHPLANE = "view.lookNormalToSketchPlane"; // Look Normal + inline constexpr std::string_view VIEW_RENDERBACKEND_OCC = "view.renderBackend.occ"; // OCCT Viewer + inline constexpr std::string_view VIEW_RENDERBACKEND_OGRE = "view.renderBackend.ogre"; // OGRE + inline constexpr std::string_view VIEW_RENDERBACKEND_OSG = "view.renderBackend.osg"; // OSG + inline constexpr std::string_view VIEW_RENDERBACKEND_SKYLARK = "view.renderBackend.skylark"; // Skylark + inline constexpr std::string_view VIEW_RENDERBACKEND_VTK = "view.renderBackend.vtk"; // VTK inline constexpr std::string_view VIEW_RIGHT = "view.right"; // Right inline constexpr std::string_view VIEW_TOP = "view.top"; // Top inline constexpr std::string_view VIEW_TRIMETRIC = "view.trimetric"; // Trimetric + inline constexpr std::string_view VIEW_VIEWCUBE = "view.viewCube"; // View Cube // === Category: window === inline constexpr std::string_view WINDOW_ARRANGE = "window.arrange"; // Arrange Windows diff --git a/Designer/UI/SolidDesignerCommand/ViewCommands/SolidRenderBackendSwitchCommand.cpp b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidRenderBackendSwitchCommand.cpp new file mode 100644 index 00000000..1fa2dcd5 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidRenderBackendSwitchCommand.cpp @@ -0,0 +1,139 @@ +#include "SolidRenderBackendSwitchCommand.h" + +#include "AliceCoreAppUtil.h" +#include "AliceIRenderBackend.h" +#include "AliceIRenderViewPort.h" +#include "AliceISession.h" +#include "AliceIUiDocumentViewManager.h" +#include "AliceIUiView.h" +#include "AliceIViewPort.h" +#include "AliceIViewPortCanvas.h" +#include "AliceRenderBackendRegistry.h" + +#include + +using namespace sdr; +using namespace alice; + +namespace +{ + static IViewPort* ActiveViewPort_() + { + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (!pSession) + { + return nullptr; + } + + IUiDocumentViewManager* const pViewManager = pSession->GetUiDocumentViewManagerFw(); + if (!pViewManager) + { + return nullptr; + } + + const std::shared_ptr pView = pViewManager->GetActiveView(); + return pView ? pView->GetViewPort() : nullptr; + } + + static bool BackendExists_(RenderBackendId id) + { + const std::shared_ptr registry = GetGlobalRenderBackendRegistry(); + return registry && registry->Find(id) != nullptr; + } +} + +SolidRenderBackendSwitchCommand::SolidRenderBackendSwitchCommand(std::string commandId, RenderBackendId backendId) noexcept + : AppCommandBase(std::move(commandId)) + , m_backendId(backendId) +{ +} + +SolidRenderBackendSwitchCommand::~SolidRenderBackendSwitchCommand() = default; + +bool SolidRenderBackendSwitchCommand::IsSupported() const +{ + return BackendExists_(m_backendId); +} + +bool SolidRenderBackendSwitchCommand::IsVisible() const +{ + return IsSupported(); +} + +bool SolidRenderBackendSwitchCommand::IsEnabled() const +{ + return IsSupported(); +} + +bool SolidRenderBackendSwitchCommand::IsChecked() const +{ + if (const IViewPort* pViewPort = ActiveViewPort_()) + { + const std::shared_ptr backend = pViewPort->GetRenderBackend(); + if (backend) + { + return backend->GetId() == m_backendId; + } + } + + const std::shared_ptr registry = GetGlobalRenderBackendRegistry(); + return registry && registry->DefaultId() == m_backendId; +} + +std::string SolidRenderBackendSwitchCommand::DisabledReason() const +{ + return IsSupported() ? std::string{} : std::string("Requested render backend is not registered."); +} + +std::unique_ptr SolidRenderBackendSwitchCommand::Execute(const CommandParameter&) +{ + const std::shared_ptr registry = GetGlobalRenderBackendRegistry(); + if (!registry) + { + return nullptr; + } + + const std::shared_ptr backend = registry->Find(m_backendId); + if (!backend) + { + return nullptr; + } + + registry->SetDefault(m_backendId); + + IViewPort* const pViewPort = ActiveViewPort_(); + if (!pViewPort) + { + return nullptr; + } + + const std::shared_ptr oldRenderViewPort = pViewPort->GetRenderViewPort(); + std::shared_ptr newRenderViewPort = backend->CreateViewport(); + if (!newRenderViewPort) + { + return nullptr; + } + + if (oldRenderViewPort) + { + newRenderViewPort->AttachScene(oldRenderViewPort->GetAttachedScene()); + newRenderViewPort->SetCamera(oldRenderViewPort->GetCamera()); + } + + const std::shared_ptr canvas = pViewPort->GetCanvas(); + if (canvas) + { + newRenderViewPort->Resize(canvas->GetWidth(), canvas->GetHeight()); + } + + pViewPort->SetRenderBackend(backend); + pViewPort->BindRenderViewPort(newRenderViewPort); + + if (canvas) + { + canvas->SetRenderViewPort(newRenderViewPort); + } + + pViewPort->RequestRender(); + return nullptr; +} diff --git a/Designer/UI/SolidDesignerCommand/ViewCommands/SolidRenderBackendSwitchCommand.h b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidRenderBackendSwitchCommand.h new file mode 100644 index 00000000..e803ab94 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidRenderBackendSwitchCommand.h @@ -0,0 +1,24 @@ +#pragma once + +#include "SolidBaseCommand.h" +#include "AliceRenderBackendId.h" + +namespace sdr +{ + class SolidRenderBackendSwitchCommand final : public AppCommandBase + { + public: + SolidRenderBackendSwitchCommand(std::string commandId, alice::RenderBackendId backendId) noexcept; + ~SolidRenderBackendSwitchCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + bool IsChecked() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + + private: + alice::RenderBackendId m_backendId = alice::RenderBackendId::Invalid; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewCubeCommand.cpp b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewCubeCommand.cpp new file mode 100644 index 00000000..f059098f --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewCubeCommand.cpp @@ -0,0 +1,50 @@ +#include "SolidViewCubeCommand.h" + +#include "SolidViewNavigationOperation.h" +#include "AliceIOperation.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" + +using namespace sdr; +using namespace alice; + +namespace +{ + static bool HasActiveDocument_() + { + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return pSession && pSession->GetActiveDocument(); + } +} + +SolidViewCubeCommand::SolidViewCubeCommand() noexcept + : AppCommandBase("view.viewCube") +{ +} + +SolidViewCubeCommand::~SolidViewCubeCommand() = default; + +bool SolidViewCubeCommand::IsSupported() const +{ + return HasActiveDocument_(); +} + +bool SolidViewCubeCommand::IsVisible() const +{ + return IsSupported(); +} + +bool SolidViewCubeCommand::IsEnabled() const +{ + return IsSupported(); +} + +std::string SolidViewCubeCommand::DisabledReason() const +{ + return IsSupported() ? std::string{} : std::string("No active document is available."); +} + +std::unique_ptr SolidViewCubeCommand::Execute(const alice::CommandParameter&) +{ + return std::make_unique(SolidViewNavigationAction::ToggleViewCube); +} diff --git a/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewCubeCommand.h b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewCubeCommand.h new file mode 100644 index 00000000..1f61a0c4 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewCubeCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace sdr +{ + class SolidViewCubeCommand final : public AppCommandBase + { + public: + SolidViewCubeCommand() noexcept; + ~SolidViewCubeCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewFitAllCommand.cpp b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewFitAllCommand.cpp new file mode 100644 index 00000000..c78ace29 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewFitAllCommand.cpp @@ -0,0 +1,50 @@ +#include "SolidViewFitAllCommand.h" + +#include "SolidViewNavigationOperation.h" +#include "AliceIOperation.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" + +using namespace sdr; +using namespace alice; + +namespace +{ + static bool HasActiveDocument_() + { + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return pSession && pSession->GetActiveDocument(); + } +} + +SolidViewFitAllCommand::SolidViewFitAllCommand() noexcept + : AppCommandBase("view.fitAll") +{ +} + +SolidViewFitAllCommand::~SolidViewFitAllCommand() = default; + +bool SolidViewFitAllCommand::IsSupported() const +{ + return HasActiveDocument_(); +} + +bool SolidViewFitAllCommand::IsVisible() const +{ + return IsSupported(); +} + +bool SolidViewFitAllCommand::IsEnabled() const +{ + return IsSupported(); +} + +std::string SolidViewFitAllCommand::DisabledReason() const +{ + return IsSupported() ? std::string{} : std::string("No active document is available."); +} + +std::unique_ptr SolidViewFitAllCommand::Execute(const alice::CommandParameter&) +{ + return std::make_unique(SolidViewNavigationAction::FitAll); +} diff --git a/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewFitAllCommand.h b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewFitAllCommand.h new file mode 100644 index 00000000..e7e2bcff --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewFitAllCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace sdr +{ + class SolidViewFitAllCommand final : public AppCommandBase + { + public: + SolidViewFitAllCommand() noexcept; + ~SolidViewFitAllCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewFrontCommand.cpp b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewFrontCommand.cpp new file mode 100644 index 00000000..489ab19f --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewFrontCommand.cpp @@ -0,0 +1,51 @@ +#include "SolidViewFrontCommand.h" + +#include "SolidDesignerCommands.h" +#include "SolidViewNavigationOperation.h" +#include "AliceIOperation.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" + +using namespace sdr; +using namespace alice; + +namespace +{ + static bool HasActiveDocument_() + { + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return pSession && pSession->GetActiveDocument(); + } +} + +SolidViewFrontCommand::SolidViewFrontCommand() noexcept + : AppCommandBase(std::string(Cmd::VIEW_FRONT)) +{ +} + +SolidViewFrontCommand::~SolidViewFrontCommand() = default; + +bool SolidViewFrontCommand::IsSupported() const +{ + return HasActiveDocument_(); +} + +bool SolidViewFrontCommand::IsVisible() const +{ + return IsSupported(); +} + +bool SolidViewFrontCommand::IsEnabled() const +{ + return IsSupported(); +} + +std::string SolidViewFrontCommand::DisabledReason() const +{ + return IsSupported() ? std::string{} : std::string("No active document is available."); +} + +std::unique_ptr SolidViewFrontCommand::Execute(const alice::CommandParameter&) +{ + return std::make_unique(alice::ModelViewStandardOrientation::Front, false); +} diff --git a/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewFrontCommand.h b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewFrontCommand.h new file mode 100644 index 00000000..0a4cc196 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewFrontCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace sdr +{ + class SolidViewFrontCommand final : public AppCommandBase + { + public: + SolidViewFrontCommand() noexcept; + ~SolidViewFrontCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewLookNormalToSketchPlaneCommand.cpp b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewLookNormalToSketchPlaneCommand.cpp new file mode 100644 index 00000000..489a3a7c --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewLookNormalToSketchPlaneCommand.cpp @@ -0,0 +1,67 @@ +#include "SolidViewLookNormalToSketchPlaneCommand.h" + +#include "SolidActiveSketchPlaneContext.h" +#include "SolidViewNavigationOperation.h" +#include "AliceCoreAppUtil.h" +#include "AliceIOperation.h" +#include "AliceIOperationManager.h" +#include "AliceISession.h" + +using namespace sdr; +using namespace alice; + +namespace +{ + static bool HasLookNormalContext_() + { + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + if (!pSession || !pSession->GetActiveDocument()) + { + return false; + } + + if (!pSession->GetOperationManagerFw()) + { + return false; + } + + SolidActiveSketchPlaneContext context; + return context.IsAvailable(); + } +} + +SolidViewLookNormalToSketchPlaneCommand::SolidViewLookNormalToSketchPlaneCommand() noexcept + : AppCommandBase("view.lookNormalToSketchPlane") +{ +} + +SolidViewLookNormalToSketchPlaneCommand::~SolidViewLookNormalToSketchPlaneCommand() = default; + +bool SolidViewLookNormalToSketchPlaneCommand::IsSupported() const +{ + return HasLookNormalContext_(); +} + +bool SolidViewLookNormalToSketchPlaneCommand::IsVisible() const +{ + return IsSupported(); +} + +bool SolidViewLookNormalToSketchPlaneCommand::IsEnabled() const +{ + return IsSupported(); +} + +std::string SolidViewLookNormalToSketchPlaneCommand::DisabledReason() const +{ + return IsSupported() ? std::string{} : std::string("No active sketch/work plane context is available."); +} + +std::unique_ptr SolidViewLookNormalToSketchPlaneCommand::Execute(const alice::CommandParameter&) +{ + if (!IsEnabled()) + { + return nullptr; + } + return std::make_unique(SolidViewNavigationAction::LookNormalToWorkPlane); +} diff --git a/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewLookNormalToSketchPlaneCommand.h b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewLookNormalToSketchPlaneCommand.h new file mode 100644 index 00000000..f6820193 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewLookNormalToSketchPlaneCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace sdr +{ + class SolidViewLookNormalToSketchPlaneCommand final : public AppCommandBase + { + public: + SolidViewLookNormalToSketchPlaneCommand() noexcept; + ~SolidViewLookNormalToSketchPlaneCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewRightCommand.cpp b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewRightCommand.cpp new file mode 100644 index 00000000..357c990a --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewRightCommand.cpp @@ -0,0 +1,51 @@ +#include "SolidViewRightCommand.h" + +#include "SolidDesignerCommands.h" +#include "SolidViewNavigationOperation.h" +#include "AliceIOperation.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" + +using namespace sdr; +using namespace alice; + +namespace +{ + static bool HasActiveDocument_() + { + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return pSession && pSession->GetActiveDocument(); + } +} + +SolidViewRightCommand::SolidViewRightCommand() noexcept + : AppCommandBase(std::string(Cmd::VIEW_RIGHT)) +{ +} + +SolidViewRightCommand::~SolidViewRightCommand() = default; + +bool SolidViewRightCommand::IsSupported() const +{ + return HasActiveDocument_(); +} + +bool SolidViewRightCommand::IsVisible() const +{ + return IsSupported(); +} + +bool SolidViewRightCommand::IsEnabled() const +{ + return IsSupported(); +} + +std::string SolidViewRightCommand::DisabledReason() const +{ + return IsSupported() ? std::string{} : std::string("No active document is available."); +} + +std::unique_ptr SolidViewRightCommand::Execute(const alice::CommandParameter&) +{ + return std::make_unique(alice::ModelViewStandardOrientation::Right, false); +} diff --git a/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewRightCommand.h b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewRightCommand.h new file mode 100644 index 00000000..72e98376 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewRightCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace sdr +{ + class SolidViewRightCommand final : public AppCommandBase + { + public: + SolidViewRightCommand() noexcept; + ~SolidViewRightCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewTopCommand.cpp b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewTopCommand.cpp new file mode 100644 index 00000000..0aab7c0c --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewTopCommand.cpp @@ -0,0 +1,51 @@ +#include "SolidViewTopCommand.h" + +#include "SolidDesignerCommands.h" +#include "SolidViewNavigationOperation.h" +#include "AliceIOperation.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" + +using namespace sdr; +using namespace alice; + +namespace +{ + static bool HasActiveDocument_() + { + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return pSession && pSession->GetActiveDocument(); + } +} + +SolidViewTopCommand::SolidViewTopCommand() noexcept + : AppCommandBase(std::string(Cmd::VIEW_TOP)) +{ +} + +SolidViewTopCommand::~SolidViewTopCommand() = default; + +bool SolidViewTopCommand::IsSupported() const +{ + return HasActiveDocument_(); +} + +bool SolidViewTopCommand::IsVisible() const +{ + return IsSupported(); +} + +bool SolidViewTopCommand::IsEnabled() const +{ + return IsSupported(); +} + +std::string SolidViewTopCommand::DisabledReason() const +{ + return IsSupported() ? std::string{} : std::string("No active document is available."); +} + +std::unique_ptr SolidViewTopCommand::Execute(const alice::CommandParameter&) +{ + return std::make_unique(alice::ModelViewStandardOrientation::Top, false); +} diff --git a/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewTopCommand.h b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewTopCommand.h new file mode 100644 index 00000000..4cee0f9c --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewTopCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace sdr +{ + class SolidViewTopCommand final : public AppCommandBase + { + public: + SolidViewTopCommand() noexcept; + ~SolidViewTopCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +} diff --git a/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewTrimetricCommand.cpp b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewTrimetricCommand.cpp new file mode 100644 index 00000000..cd8b3686 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewTrimetricCommand.cpp @@ -0,0 +1,51 @@ +#include "SolidViewTrimetricCommand.h" + +#include "SolidDesignerCommands.h" +#include "SolidViewNavigationOperation.h" +#include "AliceIOperation.h" +#include "AliceCoreAppUtil.h" +#include "AliceISession.h" + +using namespace sdr; +using namespace alice; + +namespace +{ + static bool HasActiveDocument_() + { + ISession* const pSession = CoreAppUtil::GetCurrentSession(); + return pSession && pSession->GetActiveDocument(); + } +} + +SolidViewTrimetricCommand::SolidViewTrimetricCommand() noexcept + : AppCommandBase(std::string(Cmd::VIEW_TRIMETRIC)) +{ +} + +SolidViewTrimetricCommand::~SolidViewTrimetricCommand() = default; + +bool SolidViewTrimetricCommand::IsSupported() const +{ + return HasActiveDocument_(); +} + +bool SolidViewTrimetricCommand::IsVisible() const +{ + return IsSupported(); +} + +bool SolidViewTrimetricCommand::IsEnabled() const +{ + return IsSupported(); +} + +std::string SolidViewTrimetricCommand::DisabledReason() const +{ + return IsSupported() ? std::string{} : std::string("No active document is available."); +} + +std::unique_ptr SolidViewTrimetricCommand::Execute(const alice::CommandParameter&) +{ + return std::make_unique(alice::ModelViewStandardOrientation::Isometric, false); +} diff --git a/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewTrimetricCommand.h b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewTrimetricCommand.h new file mode 100644 index 00000000..6e5023b9 --- /dev/null +++ b/Designer/UI/SolidDesignerCommand/ViewCommands/SolidViewTrimetricCommand.h @@ -0,0 +1,18 @@ +#pragma once +#include "SolidBaseCommand.h" + +namespace sdr +{ + class SolidViewTrimetricCommand final : public AppCommandBase + { + public: + SolidViewTrimetricCommand() noexcept; + ~SolidViewTrimetricCommand() override; + + bool IsSupported() const override; + bool IsVisible() const override; + bool IsEnabled() const override; + std::string DisabledReason() const override; + std::unique_ptr Execute(const alice::CommandParameter& param) override; + }; +}