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++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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