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.cpp

621 lines
13 KiB
C++

1 month ago
#include "StdAfx.h"
1 month ago
#include "CurveEditorSpline.h"
#include "SigmaDoc.h"
1 month ago
#include "SigmaView.h"
#include "ActionModifiedItem.h"
#include "ActionBackupItem.h"
#include "DrawOperator/TypeDefine.h"
1 month ago
#include "ActionCurveEdit.h"
1 month ago
#include "ActionCurveEditAddPoint.h"
#include "ActionCurveEditDeletePoint.h"
#include "HandleDrawer.h"
#include "Util.h"
#include <vector>
#include <algorithm>
namespace {
constexpr double RECT_INFINITE = 1e100;
}
1 month ago
1 month ago
CurveEditorSpline::CurveEditorSpline(CSigmaDoc* pDoc)
: CurveEditorBase(pDoc)
, m_handleDrawer(std::make_unique<HandleDrawer>(pDoc))
, m_nHandleDrawMode(TRACKER_CIRCLE)
1 month ago
{
1 month ago
m_renderer = std::make_unique<SplineEditorRenderer>(GetDoc(), m_handleDrawer.get());
m_dragPipeline = std::make_unique<SplineDragPipeline>(m_splineCurveModel, m_dragState, this);
}
1 month ago
CurveEditorSpline::~CurveEditorSpline(void)
{
}
1 month ago
void CurveEditorSpline::OnDraw(CXyDC* pDC)
1 month ago
{
1 month ago
POSITION pos = GetPos();
if (!pos)
return;
(void)pDC;
1 month ago
}
1 month ago
void CurveEditorSpline::DrawAssistant(CDC* pDC, int mouseX, int mouseY)
1 month ago
{
1 month ago
CCurveEx* pControlCurve = GetControlCurve();
if (pControlCurve == nullptr)
1 month ago
{
return;
}
1 month ago
m_handleDrawer->Init(pControlCurve);
m_handleDrawer->DrawAll(pDC);
1 month ago
}
1 month ago
void CurveEditorSpline::OnLButtonDown(CDC* pDC, UINT nFlags, CPoint point, int vk)
1 month ago
{
1 month ago
SetScreenDC(pDC);
int hitIndex = HitTestHandle(point);
// 场景1点击到了handle选中并开始拖拽
if (hitIndex >= 0)
1 month ago
{
1 month ago
SetHandleIndex(hitIndex);
m_dragState.StartDrag(point, GetDC()->GetReal(point));
OnDrawDragPreview();
1 month ago
return;
}
1 month ago
// 场景2没点到handle检查是否在曲线上可延迟创建handle
if (IsCanAddHandle(point))
1 month ago
{
1 month ago
SetHandleIndex(-1);
m_dragState.StartDrag(point, GetDC()->GetReal(point));
OnDrawDragPreview();
1 month ago
return;
}
1 month ago
// 场景3既没点到handle也没点到曲线取消选中
SetHandleIndex(-1);
}
1 month ago
1 month ago
int CurveEditorSpline::OnMouseMove(CDC* dc, UINT nFlags, CPoint point)
{
SetScreenDC(dc);
1 month ago
1 month ago
POSITION pos = GetPos();
if (!pos)
return 1;
1 month ago
1 month ago
CXyDC* pDC = GetDC();
if (IsDragging(nFlags))
1 month ago
{
1 month ago
HandleMouseDrag(pDC, point);
}
else
{
HandleMouseHover(pDC, point);
}
1 month ago
1 month ago
m_handleDrawer->DrawFocusHandle(dc, GetHandleIndex());
1 month ago
1 month ago
return 1;
1 month ago
}
1 month ago
void CurveEditorSpline::ApplyDragAndRelease()
1 month ago
{
1 month ago
if (!m_dragState.HasMoved())
1 month ago
{
1 month ago
SetHandleIndex(-1);
ReleaseCapture();
return;
1 month ago
}
1 month ago
OnDrawDragPreview();
m_dragPipeline->ProcessDragStep(false, nullptr);
SetModifiedFlag(TRUE);
GetDoc()->Modified();
SetHandleIndex(-1);
ReleaseCapture();
}
1 month ago
1 month ago
void CurveEditorSpline::OnLButtonUp(CDC* pDC, UINT nFlags, CPoint point, int vk)
{
SetScreenDC(pDC);
if (!m_dragState.isLeftButtonDownDuringMove)
1 month ago
return;
1 month ago
m_dragState.isLeftButtonDownDuringMove = false;
1 month ago
1 month ago
if (GetHandleIndex() < 0)
1 month ago
{
1 month ago
CPoint2D pt = GetDC()->GetReal(point);
POSITION pos = GetDoc()->GetSelectedItem(pt);
if (pos == GetPos())
return;
1 month ago
1 month ago
EndEdit();
return;
1 month ago
}
1 month ago
m_dragState.UpdateLast(GetDC()->GetReal(point));
ApplyDragAndRelease();
}
void CurveEditorSpline::RemoveCurrentHandle()
{
if (IsCaptureState())
ReleaseCapture();
CCurveEx* pCurve = GetControlCurve();
if (pCurve == nullptr)
return;
DeleteHandle(GetHandleIndex());
SetHandleIndex(-1);
Invalidate();
}
void CurveEditorSpline::OnLButtonDblClk(UINT nFlags, CPoint point)
{
POSITION pos = GetPos();
if (!pos)
return;
COne* pOne = GetDoc()->GetDraw()->GetAt(pos);
if (pOne == nullptr)
return;
std::unique_ptr<CActionModifiedItem> pAction = std::make_unique<CActionModifiedItem>(GetDoc(), 0);
pAction->BackupOldItem(pos, pOne);
if (GetHandleIndex() >= 0) // 如果当前存在控制点,删除它
1 month ago
{
1 month ago
RemoveCurrentHandle();
1 month ago
}
1 month ago
else // 否则尝试添加控制点
1 month ago
{
1 month ago
int ret = AddHandle(point);
if (ret < 0)
1 month ago
{
1 month ago
return;
1 month ago
}
}
1 month ago
pAction->BackupNewItem();
GetDoc()->SetActionItem(pAction.release());
GetDoc()->Modified();
1 month ago
1 month ago
if (GetDoc()->GetItem()->GetType() == ITEM_CURVE_EDIT)
EndEdit();
}
1 month ago
1 month ago
BOOL CurveEditorSpline::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
return TRUE;
}
1 month ago
1 month ago
BOOL CurveEditorSpline::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
switch (nChar)
1 month ago
{
1 month ago
case VK_ESCAPE:
if (!IsCaptureState()) break;
OnDrawDragPreview();
DrawSelectHandle(GetHandleIndex());
SetHandleIndex(-1);
ReleaseCapture();
return TRUE;
1 month ago
}
1 month ago
return FALSE;
}
1 month ago
1 month ago
BOOL CurveEditorSpline::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
switch (nChar)
1 month ago
{
1 month ago
case VK_ESCAPE:
EndEdit();
return TRUE;
1 month ago
}
1 month ago
return FALSE;
}
1 month ago
1 month ago
int CurveEditorSpline::GetSubMenu()
{
return 6;
}
void CurveEditorSpline::SetPos(POSITION pos)
{
CItem::SetPos(pos);
m_pBakOne.reset();
m_dragState.Reset();
if (pos)
1 month ago
{
1 month ago
COne* pOne = GetDoc()->GetDraw()->GetAt(GetPos());
m_pBakOne = std::make_unique<COne>();
*m_pBakOne = *pOne;
CCurveEx* pCurve = (CCurveEx*)pOne->GetValue();
InitializeHandles(pCurve);
1 month ago
}
}
1 month ago
void CurveEditorSpline::Clear(void)
1 month ago
{
1 month ago
m_pBakOne.reset(); // 清除备份
1 month ago
}
1 month ago
void CurveEditorSpline::Draw(CDC* pDC)
1 month ago
{
1 month ago
POSITION pos = GetPos();
if (!pos)
return;
CCurveEx* pValue = GetControlCurve();
DrawHandlesByCDC(pDC, pValue);
}
int CurveEditorSpline::GetNumberOfNode()
{
CCurveEx* pc = GetControlCurve();
if (pc == nullptr)
1 month ago
return -1;
1 month ago
return pc->num;
}
void CurveEditorSpline::EreaseHandles(CDC* pDC)
{
m_handleDrawer->ClearAll(pDC);
1 month ago
}
1 month ago
void CurveEditorSpline::EndEdit(void)
1 month ago
{
if (GetPos() == nullptr)
return;
COne* pOne = GetDoc()->GetDraw()->GetAt(GetPos());
1 month ago
CRect8 range(RECT_INFINITE, -RECT_INFINITE, -RECT_INFINITE, RECT_INFINITE);
pOne->GetRange(range);
CRect rt = GetDC()->GetScreen(range);
rt.NormalizeRect();
rt.InflateRect(GetDoc()->GetHandleSize());
rt.InflateRect(1, 1);
if (((CCurveEx*)pOne->GetValue())->num < 2)
1 month ago
{
1 month ago
if (::AfxMessageBox(IDS_STRING_CURVE_ONLY_ONE_POINT, MB_YESNO | MB_ICONQUESTION) == IDYES)
1 month ago
{
1 month ago
*pOne = *m_pBakOne;
CPositionList list;
list.AddTail(GetPos());
CItem::SetPos(nullptr);
GetDoc()->InvalidateDelete(list);
return;
1 month ago
}
}
1 month ago
if (IsModified())
1 month ago
{
1 month ago
CActionItem* pAction = new CActionModifiedItem(GetDoc(), IDS_STRING_TOOLBAR_EDIT);
((CActionModifiedItem*)pAction)->BackupOldItem(GetPos(), m_pBakOne.get());
GetDoc()->SetActionItem(pAction);
1 month ago
}
}
1 month ago
void CurveEditorSpline::CancelAll(void)
1 month ago
{
1 month ago
if (m_pBakOne)
1 month ago
{
1 month ago
COne* pOne = GetDoc()->GetDraw()->GetAt(GetPos());
*pOne = *m_pBakOne;
CCurveEx* pCurve = (CCurveEx*)pOne->GetValue();
InitializeHandles(pCurve);
1 month ago
}
1 month ago
}
BOOL CurveEditorSpline::IsCanCancelAll(void)
{
return (m_pBakOne != nullptr);
}
void CurveEditorSpline::GetXY(CCurveEx* pValue, int nIndex, dfPoint& point)
{
pValue->GetPoint(nIndex, point);
}
CCurveEx* CurveEditorSpline::GetControlCurve(void)
{
const auto& controlPoints = m_splineCurveModel.GetControlPoints();
if (controlPoints.empty())
return nullptr;
m_tempControlCurve = std::make_unique<CCurveEx>();
int num = static_cast<int>(controlPoints.size());
m_tempControlCurve->Create(num);
for (int i = 0; i < num; ++i)
1 month ago
{
1 month ago
m_tempControlCurve->x[i] = controlPoints[i].x0;
m_tempControlCurve->y[i] = controlPoints[i].y0;
1 month ago
}
1 month ago
return m_tempControlCurve.get();
}
int CurveEditorSpline::HitTestHandle(CPoint point)
{
return HitTestHandle(GetControlCurve(), point);
}
int CurveEditorSpline::HitTestHandle(CCurveEx* pValue, CPoint point)
{
if (pValue == nullptr)
return -1;
CRect rt;
for (int i = 0; i < pValue->num; i++)
1 month ago
{
1 month ago
CPoint ptScreen(GetDC()->GetSX(pValue->x[i]), GetDC()->GetSY(pValue->y[i]));
if (i == 0 || i == pValue->num - 1)
rt = GetFirstNodeHandleRectFocus(ptScreen);
else
rt = GetDoc()->m_itemTracker.GetHandleRect(ptScreen);
if (rt.PtInRect(point))
return i;
1 month ago
}
1 month ago
return -1;
}
bool CurveEditorSpline::IsDragging(int nFlags) const
{
return (nFlags & MK_LBUTTON) != 0;
}
int CurveEditorSpline::AcquireDragHandle(CPoint point)
{
int i = GetHandleIndex();
if (i >= 0)
return i;
CSize8 selectSize = GetDoc()->GetSelectSize();
if (AfxGetPublicFunction()->Distance(m_dragState.screenDownPoint.x, m_dragState.screenDownPoint.y, point.x, point.y) <= selectSize.cx)
return -1;
i = AddHandle(m_dragState.screenDownPoint);
if (i < 0)
return -1;
SetHandleIndex(i);
m_dragState.StartDrag(m_dragState.screenDownPoint, GetDC()->GetReal(m_dragState.screenDownPoint));
OnDrawDragPreview();
return i;
}
int CurveEditorSpline::HandleMouseDrag(CXyDC* pXyDC, CPoint point)
{
m_dragState.isLeftButtonDownDuringMove = true;
int i = AcquireDragHandle(point);
if (i < 0)
return 1;
OnDrawDragPreview();
m_dragState.UpdateLast(pXyDC->GetReal(point));
CPointList list;
m_dragPipeline->ProcessDragStep(true, &list);
OnDrawDragPreview();
OnDragMove(GetHandleIndex(), m_dragState.worldLastPoint);
return 1;
}
int CurveEditorSpline::HandleMouseHover(CXyDC* pXyDC, CPoint point)
{
CDC* dc = pXyDC->GetDC();
CCurveEx* pValue = GetControlCurve();
if (pValue == nullptr)
1 month ago
{
1 month ago
SetHandleIndex(-1);
int handleIndex = m_handleDrawer->EreaseFocusHandle(dc);
m_handleDrawer->DrawOneHandle(dc, handleIndex);
1 month ago
}
else
{
1 month ago
int i = HitTestHandle(pValue, point);
if (i >= 0)
{
SetHandleIndex(i);
}
else
{
SetHandleIndex(-1);
int handleIndex = m_handleDrawer->EreaseFocusHandle(dc);
m_handleDrawer->DrawOneHandle(dc, handleIndex);
}
1 month ago
}
1 month ago
return 1;
}
void CurveEditorSpline::DeleteHandle(int nIndex)
{
if (nIndex < 0 || nIndex >= m_splineCurveModel.GetControlPointCount())
return;
if (!m_splineCurveModel.RemoveControlPoint(nIndex))
return;
WriteModelToDocCurve();
SetModifiedFlag(TRUE);
SetHandleIndex(-1);
}
int CurveEditorSpline::AddHandle(double l0)
{
(void)l0;
return -1;
}
int CurveEditorSpline::AddHandle(CPoint point)
{
dfPoint worldPoint;
int segmentIndex = FindSegmentIndexAtScreenPoint(point, &worldPoint);
if (segmentIndex < 0)
return -1;
int insertIndex = segmentIndex + 1;
int ret = m_splineCurveModel.InsertControlPoint(insertIndex, worldPoint);
if (ret < 0)
return -1;
WriteModelToDocCurve();
GetDoc()->Modified();
SetModifiedFlag(TRUE);
return ret;
}
BOOL CurveEditorSpline::IsCanAddHandle(CPoint point, double* pl0)
{
dfPoint worldPoint;
int segmentIndex = FindSegmentIndexAtScreenPoint(point, &worldPoint);
if (pl0)
*pl0 = worldPoint.l;
return segmentIndex >= 0;
1 month ago
}
1 month ago
int CurveEditorSpline::FindSegmentIndexAtScreenPoint(CPoint screenPoint, dfPoint* pOutWorldPoint)
1 month ago
{
1 month ago
const auto& renderPoints = m_splineCurveModel.GetRenderPoints();
if (renderPoints.empty())
return -1;
1 month ago
1 month ago
CXyDC* pDC = GetDC();
CSize8 selectSize = GetDoc()->GetSelectSize();
int maxDistSq = (int)(selectSize.cx * selectSize.cx + selectSize.cy * selectSize.cy);
int bestSegmentIndex = -1;
double bestDistSq = static_cast<double>(maxDistSq) + 1;
1 month ago
1 month ago
for (const auto& renderPoint : renderPoints)
{
CPoint ptScreen(pDC->GetSX(renderPoint.point.x0), pDC->GetSY(renderPoint.point.y0));
int dx = ptScreen.x - screenPoint.x;
int dy = ptScreen.y - screenPoint.y;
double distSq = static_cast<double>(dx) * dx + static_cast<double>(dy) * dy;
if (distSq < bestDistSq)
{
bestDistSq = distSq;
bestSegmentIndex = renderPoint.segIndex;
if (pOutWorldPoint)
*pOutWorldPoint = renderPoint.point;
}
}
if (bestSegmentIndex < 0 || bestDistSq > maxDistSq)
return -1;
return bestSegmentIndex;
}
void CurveEditorSpline::AttachProcess(CPointList& oldPoints, CPointList& newPoints)
{
}
1 month ago
1 month ago
void CurveEditorSpline::DrawMoveLine(void)
{
OnDrawDragPreview();
1 month ago
}
1 month ago
void CurveEditorSpline::GetMarkCurve(void)
1 month ago
{
1 month ago
}
1 month ago
1 month ago
CPoint2D CurveEditorSpline::GetCDown() const
{
return m_dragState.worldDownPoint;
}
1 month ago
1 month ago
CPoint2D CurveEditorSpline::GetCLast() const
{
return m_dragState.worldLastPoint;
}
1 month ago
1 month ago
void CurveEditorSpline::DrawHandle(CXyDC* pDC, CCurveEx* pCurve)
{
m_renderer->DrawHandle(pDC, m_pScreenDC, pCurve, GetHandleIndex());
1 month ago
}
1 month ago
void CurveEditorSpline::DrawHandlesByCDC(CDC* pDC, CCurveEx* pCurve)
1 month ago
{
1 month ago
m_renderer->DrawHandlesByCDC(pDC, pCurve);
}
1 month ago
1 month ago
void CurveEditorSpline::DrawSelectHandle(int nHandle)
{
CCurveEx* pValue = GetControlCurve();
if (pValue == nullptr)
return;
m_renderer->DrawSelectHandle(m_pScreenDC, GetDC(), pValue, nHandle, m_nHandleDrawMode);
}
1 month ago
1 month ago
CRect CurveEditorSpline::GetRangeWidthIndex(int nIndex)
{
CCurveEx* pValue = GetControlCurve();
if (pValue == nullptr)
return CRect(0, 0, 0, 0);
return m_renderer->GetRangeWidthIndex(pValue, nIndex, GetDC(), GetDoc()->GetHandleSize());
}
1 month ago
1 month ago
CRect CurveEditorSpline::GetFirstNodeHandleRectFocus(CPoint point)
{
return m_renderer->GetFirstNodeHandleRectFocus(point);
}
1 month ago
1 month ago
void CurveEditorSpline::OnDragMove(int nIndex, CPoint2D pt)
{
m_splineCurveModel.UpdateControlPoint(nIndex, pt.x0, pt.y0);
}
1 month ago
1 month ago
void CurveEditorSpline::OnDrawDragPreview()
{
m_renderer->DrawDragPreview(m_pScreenDC, GetDC(), m_dragState.previewPoints);
1 month ago
}
1 month ago
CSigmaDoc* CurveEditorSpline::GetDoc()
1 month ago
{
1 month ago
return CItemCurve::GetDoc();
}
1 month ago
1 month ago
POSITION CurveEditorSpline::GetPos()
{
return CItemCurve::GetPos();
}
1 month ago
1 month ago
int CurveEditorSpline::GetHandleIndex()
{
return CItemCurve::GetHandleIndex();
}
1 month ago
1 month ago
void CurveEditorSpline::Invalidate()
{
CItemCurve::Invalidate();
}
1 month ago
1 month ago
void CurveEditorSpline::WriteModelToDocCurve()
{
CCurveEx* pDocCurve = (CCurveEx*)GetDoc()->GetDraw()->GetAtValue(GetPos());
if (pDocCurve == nullptr)
return;
m_splineCurveModel.ToCCurveEx(*pDocCurve);
1 month ago
}
1 month ago
void CurveEditorSpline::InitializeHandles(CCurveEx* pCurve)
{
if (pCurve == nullptr || pCurve->num < 2)
return;
double splineStep = GetDC()->GetMiniSmoothStep() * 3;
m_splineCurveModel.InitFromCCurveEx(*pCurve, splineStep);
}
1 month ago
1 month ago
void CurveEditorSpline::OnCalculateDragEffect(CPointList* pList)
{
m_dragPipeline->ProcessDragStep(pList != nullptr, pList);
}