#include "StdAfx.h" #include "CurveEditorSpline.h" #include "SigmaDoc.h" #include "ActionCurveEdit.h" namespace NItem { CurveEditorSpline::~CurveEditorSpline(void) { } void CurveEditorSpline::OnModeInitialize() { GetMarkCurve(); } void CurveEditorSpline::OnDragMove(int nIndex, CPoint2D pt) { TRACE("nIndex = %d, %lf, %lf\n", nIndex, pt.x0, pt.y0); if (m_pControlCurve == nullptr || nIndex < 0 || nIndex >= m_pControlCurve->num) { return; } CPoint2D realPoint = GetDoc()->GetDC().GetReal(pt); // ???????????? m_pControlCurve->x[nIndex] = pt.x0; m_pControlCurve->y[nIndex] = pt.y0; } void CurveEditorSpline::DrawAssistant(CDC* pDC, int mouseX, int mouseY) { if (m_pControlCurve == nullptr) { return; } TRACE("num = %d\n", m_pControlCurve->num); m_handleDrawer->Init(m_pControlCurve.get()); m_handleDrawer->DrawAll(pDC); } void CurveEditorSpline::OnDrawDragPreview() { if (NewPointList.IsEmpty()) { return; } CXyDC* pDC = GetDC(); CPen pen(PS_SOLID, 0, DRAG_LINE_COLOR); CPen* op = m_pScreenDC->SelectObject(&pen); int od = m_pScreenDC->SetROP2(R2_NOTXORPEN); dfPoint dp1, dp2; POSITION pos; dp1 = NewPointList.GetHead(); pos = NewPointList.GetHeadPosition(); if (pos) NewPointList.GetNext(pos); while (pos) { dp2 = NewPointList.GetNext(pos); CPoint ptS1 = pDC->GetScreen(dp1); m_pScreenDC->MoveTo(ptS1); CPoint ptS2 = pDC->GetScreen(dp2); m_pScreenDC->LineTo(ptS2); dp1 = dp2; } m_pScreenDC->SetROP2(od); m_pScreenDC->SelectObject(op); } void CurveEditorSpline::OnCalculateDragEffect(CPointList* pList) { BOOL bRedraw = TRUE; BOOL bAttachProcess = TRUE; CCurveEx* pValue = (CCurveEx*)GetDoc()->GetDraw()->GetAtValue(GetPos()); if (pList) { CCurveEx* pc = new CCurveEx; *pc = *pValue; pValue = pc; bRedraw = FALSE; bAttachProcess = FALSE; } CPointList oldPoints; CPointList newPoints; dfPoint pt; int i = GetHandleIndex(); if (i < 0 || m_pMarkCurve == nullptr) { if (pList) { pValue->GetPoint(*pList); delete pValue; } return; } int begin, end; GetDragSplinePoint(c_last, NewPointList, begin, end); if (bAttachProcess) { for (int j = begin; j <= end; j++) { pValue->GetPoint(j, pt); oldPoints.AddTail(pt); } } PointList.RemoveAll(); // 1. ????????????0 ?? begin-1?? for (int j = 0; j < begin; j++) { pValue->GetPoint(j, pt); PointList.AddTail(pt); } // 2. ???????????????????I begin ?? end ?????? POSITION pos = NewPointList.GetHeadPosition(); while (pos) { pt = NewPointList.GetNext(pos); PointList.AddTail(pt); // ??????????????????? if (bAttachProcess) newPoints.AddTail(pt); } // 3. ????????????? end ????? // ???????????????? end ??????? if (end < pValue->num - 1) { for (int j = end; j < pValue->num; j++) { pValue->GetPoint(j, pt); PointList.AddTail(pt); } } if (bRedraw) Invalidate(); // ??????????????????????? if (pValue->nPoint == 4) pValue->nPoint = 3; if (!pValue->bAutoLocation) pValue->bAutoLocation = TRUE; // ?I???????? pValue->SetPoints(PointList, pValue->nPoint, pValue->bAutoLocation); PointList.RemoveAll(); if (bRedraw && m_pMarkCurve) { // ??????????????????????????? int oldMarkCount = m_pMarkCurve->num; // ???????????????? GetMarkCurve(); Invalidate(); } // ?????? if (bAttachProcess) { if (oldPoints.GetCount() > 0) AttachProcess(oldPoints, newPoints); } if (pList) { pValue->GetPoint(*pList); delete pValue; } } CCurveEx* CurveEditorSpline::GetControlCurve(void) { // ????????????????????HitTest??Add??Delete??Draw??????????????????? return m_pControlCurve ? m_pControlCurve.get() : nullptr; } int CurveEditorSpline::AddHandle(double l0) { // ????????????????????????????????????? CCurveEx* pValue = (CCurveEx*)GetDoc()->GetDraw()->GetAtValue(GetPos()); if (pValue == nullptr || m_pMarkCurve == nullptr) { return -1; } dfPoint add; add.l = l0; pValue->GetCoordinate(add.l, add.x0, add.y0, add.z0); // ?????????????? // ?????????????m_pMarkCurve?? return CurveEditorBase::AddHandle(m_pMarkCurve.get(), add); } void CurveEditorSpline::GetMarkCurve() { // ????????????????????????????????? if (GetPos() == nullptr) { return; } // ??1????????????? COne* pOne = GetDoc()->GetDraw()->GetAt(GetPos()); CCurveEx* pOriginalCurve = (CCurveEx*)pOne->GetValue(); if (!m_pMarkCurve) m_pMarkCurve = std::make_unique(); int oldHandleCount = m_pMarkCurve->num; // ??2????????????????????????? CCurveRedundant redundant; redundant.SetCurve(*pOriginalCurve); double baseErr = GetDC()->GetMiniSmoothStep() * 3; double errorThreshold = baseErr; // ??3?????????????????? bool isFirstGeneration = (oldHandleCount == 0); if (isFirstGeneration) { // ????????????????????? redundant.Execute(errorThreshold); redundant.GetRedundantCurve(*m_pMarkCurve); } else { // ????????????????????????????????? // 3.1 ????????????????? redundant.Execute(errorThreshold); CCurveEx tempCurve; redundant.GetRedundantCurve(tempCurve); // 3.2 ????????????????????? double maxGrowthRatio = 1.2; // ????20%?????? bool isTooManyHandles = (tempCurve.num > oldHandleCount * maxGrowthRatio); if (isTooManyHandles) { // 3.3 ?????????????????????????? double actualGrowthRatio = (double)tempCurve.num / oldHandleCount; errorThreshold = baseErr * actualGrowthRatio; // 3.4 ???????????????? redundant.Execute(errorThreshold); redundant.GetRedundantCurve(*m_pMarkCurve); TRACE("???????????????????????? %d ?? %d (??????? %d)\n", oldHandleCount, m_pMarkCurve->num, tempCurve.num); } else { // 3.5 ??????????????????? *m_pMarkCurve = tempCurve; } } // ??4???????????????????? m_pMarkCurve->nPoint = 4; m_pMarkCurve->bAutoLocation = FALSE; if (m_pControlCurve == nullptr) { m_pControlCurve = std::make_unique(); *m_pControlCurve = *m_pMarkCurve; } } void CurveEditorSpline::GetDragSplinePoint(CPoint2D& dp, CPointList& NewPointList, int& begin, int& end) { // ????????????????????????????????????? int handleIndex = GetHandleIndex(); if (handleIndex < 0 || m_pMarkCurve == nullptr) { return; } CCurveEx* pOriginalCurve = (CCurveEx*)GetDoc()->GetDraw()->GetAtValue(GetPos()); if (pOriginalCurve == nullptr) { return; } // ??1?????????????????????????????????? - ????? - ????????????? int prevHandleIndex = max(0, handleIndex - 1); int nextHandleIndex = min(m_pControlCurve->num -1, handleIndex + 1); // ??2?????????????????????????????? // ??????????????I???????????????????I????????begin ?? end ????????????????????? begin = GetOriginalIndex(prevHandleIndex); end = GetOriginalIndex(nextHandleIndex); // ??3?????????????????????? // ???????????????????????????????? // ???? begin ?? end ????????????????????????????? pOriginalCurve->GetLocation(); // ?????????????????? int currentOriginalIndex = GetOriginalIndex(handleIndex); double lBegin = pOriginalCurve->l[begin]; // ?????????????? double lEnd = pOriginalCurve->l[end]; // ?????????????? double lCurrent = pOriginalCurve->l[currentOriginalIndex]; // ????????????????????????? const double SMOOTH_FACTOR = 0.001; // ????????0.1% lBegin += (lCurrent - lBegin) * SMOOTH_FACTOR; lEnd -= (lEnd - lCurrent) * SMOOTH_FACTOR; // ??4??????????????????????? NewPointList.RemoveAll(); bool isFirstHandle = (handleIndex == 0); bool isLastHandle = (handleIndex == m_pControlCurve->num - 1); if (isFirstHandle) { BuildFirstHandlePoints(dp, lEnd, nextHandleIndex, NewPointList); } else if (isLastHandle) { BuildLastHandlePoints(dp, lBegin, prevHandleIndex, NewPointList); } else { BuildMiddleHandlePoints(dp, lBegin, lEnd, prevHandleIndex, nextHandleIndex, NewPointList); } // ??5?????????????????????????????????? CCurveEx splineCurve; splineCurve.SetPoints(NewPointList, 2); NewPointList.RemoveAll(); double splineStep = GetDC()->GetMiniSmoothStep() * 3; splineCurve.CurveToSpline(NewPointList, splineStep, 0); } void CurveEditorSpline::BuildFirstHandlePoints(const CPoint2D& dp, double lEnd, int nextHandleIndex, CPointList& list) { // ??????3???????????????? + ????? + ?????????? dfPoint draggedPoint; draggedPoint.x0 = dp.x0; draggedPoint.y0 = dp.y0; list.AddTail(draggedPoint); CCurveEx* pOriginalCurve = (CCurveEx*)GetDoc()->GetDraw()->GetAtValue(GetPos()); pOriginalCurve->GetCoordinate(lEnd, draggedPoint.x0, draggedPoint.y0, draggedPoint.z0); list.AddTail(draggedPoint); draggedPoint.x0 = m_pControlCurve->x[nextHandleIndex]; draggedPoint.y0 = m_pControlCurve->y[nextHandleIndex]; list.AddTail(draggedPoint); } void CurveEditorSpline::BuildLastHandlePoints(const CPoint2D& dp, double lBegin, int prveHandleInex, CPointList& list) { dfPoint draggedPoint; CCurveEx* pOriginalCurve = (CCurveEx*)GetDoc()->GetDraw()->GetAtValue(GetPos()); // 1. ???????????? draggedPoint.x0 = m_pControlCurve->x[prveHandleInex]; draggedPoint.y0 = m_pControlCurve->y[prveHandleInex]; list.AddTail(draggedPoint); // 2. ??????????? pOriginalCurve->GetCoordinate(lBegin, draggedPoint.x0, draggedPoint.y0, draggedPoint.z0); list.AddTail(draggedPoint); // 3. ????????? draggedPoint.x0 = dp.x0; draggedPoint.y0 = dp.y0; list.AddTail(draggedPoint); } void CurveEditorSpline::BuildMiddleHandlePoints(const CPoint2D& dp, double lBegin, double lEnd, int prveHandleIndex, int nextHandleIndex, CPointList& list) { dfPoint draggedPoint; CCurveEx* pOriginalCurve = (CCurveEx*)GetDoc()->GetDraw()->GetAtValue(GetPos()); // 1. ?????? draggedPoint.x0 = m_pControlCurve->x[prveHandleIndex]; draggedPoint.y0 = m_pControlCurve->y[prveHandleIndex]; list.AddTail(draggedPoint); // 2. ?????? pOriginalCurve->GetCoordinate(lBegin, draggedPoint.x0, draggedPoint.y0, draggedPoint.z0); list.AddTail(draggedPoint); // 3. ???????????? draggedPoint.x0 = dp.x0; draggedPoint.y0 = dp.y0; list.AddTail(draggedPoint); // 4. ?????? pOriginalCurve->GetCoordinate(lEnd, draggedPoint.x0, draggedPoint.y0, draggedPoint.z0); list.AddTail(draggedPoint); // 5. ?????? draggedPoint.x0 = m_pControlCurve->x[nextHandleIndex]; draggedPoint.y0 = m_pControlCurve->y[nextHandleIndex]; list.AddTail(draggedPoint); } int CurveEditorSpline::GetOriginalIndex(int handleIndex) { CCurveEx* pOriginalCurve = (CCurveEx*)GetDoc()->GetDraw()->GetAtValue(GetPos()); assert(pOriginalCurve != nullptr); // 1. ??_??????? handleIndex ????? int clampedIndex = std::clamp(handleIndex, 0, m_pControlCurve->num - 1); // 2. ???????????????????????????????????????????????????? if (clampedIndex == 0) { return 0; } if (clampedIndex == m_pControlCurve->num - 1) { return pOriginalCurve->num - 1; } // 3. ????????????? return pOriginalCurve->FindIndex( m_pControlCurve->x[clampedIndex], m_pControlCurve->y[clampedIndex], -1 ); } }; // namespace