You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kev/Drawer/Module/GeoSigmaDraw/CurveEditorSpline.h

145 lines
3.9 KiB
C++

#pragma once
#include "CurveEditorBase.h"
#include "HandleDrawer.h"
#include "SplineCurveModel.h"
#include "SplineDragPipeline.h"
#include "SplineEditorRenderer.h"
#include <memory>
#include <vector>
/**
* @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<SplineDragPipeline> m_dragPipeline;
std::unique_ptr<COne> m_pBakOne;
std::unique_ptr<HandleDrawer> m_handleDrawer;
std::unique_ptr<SplineEditorRenderer> m_renderer;
DWORD m_nHandleDrawMode;
std::unique_ptr<CCurveEx> 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);
};