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

452 lines
11 KiB
C++

#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. ???????????????????<3F>I begin ?? end ??????
POSITION pos = NewPointList.GetHeadPosition();
while (pos)
{
pt = NewPointList.GetNext(pos);
PointList.AddTail(pt);
// ???????????????????
if (bAttachProcess)
newPoints.AddTail(pt);
}
// 3. ????????????? end ?????
// ?????????????<3F><>??? 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;
// ?<3F>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)
{
// ???????????<3F><>?????????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<CCurveEx>();
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 ??????????<3F><>?????????
*m_pMarkCurve = tempCurve;
}
}
// ??4????????????????????
m_pMarkCurve->nPoint = 4;
m_pMarkCurve->bAutoLocation = FALSE;
if (m_pControlCurve == nullptr)
{
m_pControlCurve = std::make_unique<CCurveEx>();
*m_pControlCurve = *m_pMarkCurve;
}
}
void CurveEditorSpline::GetDragSplinePoint(CPoint2D& dp, CPointList& NewPointList, int& begin, int& end)
{
// ????????????????????????????????<3F><>?????<3F><>
int handleIndex = GetHandleIndex();
if (handleIndex < 0 || m_pMarkCurve == nullptr)
{
return;
}
CCurveEx* pOriginalCurve = (CCurveEx*)GetDoc()->GetDraw()->GetAtValue(GetPos());
if (pOriginalCurve == nullptr)
{
return;
}
// ??1???????????????????<3F><>??????????????? - ????? - ?????????????
int prevHandleIndex = max(0, handleIndex - 1);
int nextHandleIndex = min(m_pControlCurve->num -1, handleIndex + 1);
// ??2??????????????????????????????
// ??????????????<3F>I???????????????????<3F>I?????<3F><>???begin ?? end ???????????????????<3F><>??
begin = GetOriginalIndex(prevHandleIndex);
end = GetOriginalIndex(nextHandleIndex);
// ??3?????????????????<3F><>?????
// ?????????????<3F><>???????????????????
// ???? 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??????????????????????<3F><>?
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?????????????????????????????????<3F><>?
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. ??<3F>_??????? 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. ?<3F><>????????????
return pOriginalCurve->FindIndex(
m_pControlCurve->x[clampedIndex],
m_pControlCurve->y[clampedIndex],
-1
);
}
}; // namespace