#pragma once #include "CurveEditorBase.h" #include "HandleDrawer.h" #include "SplineCurveModel.h" #include "SplineDragPipeline.h" #include "SplineEditorRenderer.h" #include #include /** * @brief 三次样条曲线编辑模式 * * 使用 Centripetal Catmull-Rom 算法,以控制点为唯一数据源, * 支持拖拽控制点、点击曲线添加节点、双击删除节点。 */ class CurveEditorSpline : public CurveEditorBase, public ISplineDragPipelineContext { public: CurveEditorSpline(CSigmaDoc* pDoc); virtual ~CurveEditorSpline(void); // Mouse event handlers void OnDraw(CXyDC* pDC) override; void OnLButtonDblClk(UINT nFlags, CPoint point) override; void OnLButtonDown(CDC* pDC, UINT nFlags, CPoint point, int vk) override; int OnMouseMove(CDC* pDC, UINT nFlags, CPoint point) override; void OnLButtonUp(CDC* pDC, UINT nFlags, CPoint point, int vk) override; BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) override; BOOL OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) override; BOOL OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) override; int GetSubMenu() override; void SetPos(POSITION pos) override; void Clear(void) override; void Draw(CDC* pDC) override; void DrawAssistant(CDC* pDC, int mouseX, int mouseY) override; int GetNumberOfNode() override; void EreaseHandles(CDC* pDC) override; void EndEdit(void) override; void CancelAll(void) override; BOOL IsCanCancelAll(void) override; // ========================= // 核心操作:控制点管理 // ========================= /** * @brief 初始化控制点 */ void InitializeHandles(CCurveEx* pCurve); /** * @brief 测试是否是控制点 */ int HitTestHandle(CPoint point) override; /** * @brief 删除控制点 */ void DeleteHandle(int nIndex) override; /** * @brief 添加控制点 */ int AddHandle(CPoint point) override; /** * @brief 判断是否可以添加控制点 */ BOOL IsCanAddHandle(CPoint point, double* pl0 = nullptr) override; /** * @brief 获取当前控制点曲线,指针仅在本次调用链内有效 */ CCurveEx* GetControlCurve(void) override; void GetXY(CCurveEx* pValue, int nIndex, dfPoint& point) override; void AttachProcess(CPointList& oldPoints, CPointList& newPoints) override; void DrawMoveLine(void) override; void GetMarkCurve(void) override; CPoint2D GetCDown() const override; CPoint2D GetCLast() const override; protected: void OnDrawDragPreview(); void OnCalculateDragEffect(CPointList* pList); void OnDragMove(int nIndex, CPoint2D pt); int AddHandle(double l0); private: SplineCurveModel m_splineCurveModel; SplineDragState m_dragState; std::unique_ptr m_dragPipeline; std::unique_ptr m_pBakOne; std::unique_ptr m_handleDrawer; std::unique_ptr m_renderer; DWORD m_nHandleDrawMode; std::unique_ptr m_tempControlCurve; void DrawHandle(CXyDC* pDC, CCurveEx* pCurve); void DrawHandlesByCDC(CDC* pDC, CCurveEx* pCurve); void DrawSelectHandle(int nHandle); CRect GetRangeWidthIndex(int nIndex); CRect GetFirstNodeHandleRectFocus(CPoint point); int HitTestHandle(CCurveEx* pValue, CPoint point); // ========================= // 核心操作:鼠标交互 // ========================= /** * @brief 是否是拖动状态 */ bool IsDragging(int nFlags) const; /** * @brief 处理拖动 */ int HandleMouseDrag(CXyDC* pXyDC, CPoint point); /** * @brief 处理 Hover */ int HandleMouseHover(CXyDC* pXyDC, CPoint point); int AcquireDragHandle(CPoint point); void ApplyDragAndRelease(); void RemoveCurrentHandle(); CSigmaDoc* GetDoc() override; POSITION GetPos() override; int GetHandleIndex() override; void WriteModelToDocCurve() override; void Invalidate() override; /** * @brief 在渲染点中找与屏幕点最近的点,返回段索引,可选输出世界坐标 */ int FindSegmentIndexAtScreenPoint(CPoint screenPoint, dfPoint* pOutWorldPoint); };