#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 #include namespace { constexpr double RECT_INFINITE = 1e100; } CurveEditorSpline::CurveEditorSpline(CSigmaDoc* pDoc) : CurveEditorBase(pDoc) , m_handleDrawer(std::make_unique(pDoc)) , m_nHandleDrawMode(TRACKER_CIRCLE) { m_renderer = std::make_unique(GetDoc(), m_handleDrawer.get()); m_dragPipeline = std::make_unique(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 pAction = std::make_unique(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(); *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(); int num = static_cast(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(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(dx) * dx + static_cast(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); }