📄 curvectrl.cpp
字号:
// 功能:connect neighbor points by drawing lines(画所有曲线)
// 参数:无
//-------------------------------------------------------------------------------------------------
void CCurveCtrl::DrawCurve(CDC *pdc)
{
CPen Pen;
CBrush brush;
CPen* pOldPen;
CBrush* pOldBrush;
CCurve* pCurve;
int iPoint;
CRect rect;
int nRadius;
for (int iCurve = 0; iCurve < m_ArrCurve.GetSize(); iCurve++)
{
pCurve = m_ArrCurve[iCurve];
if ((!pCurve->IsVisible()) || (pCurve->m_ArrPoint.GetSize() < 1))
continue;
// create pen using CCurve's member variables
Pen.CreatePen(pCurve->m_iStyle, pCurve->m_nWidth, pCurve->m_crColor);
pOldPen = pdc->SelectObject(&Pen);
brush.CreateSolidBrush(pCurve->m_crColor);
pOldBrush = pdc->SelectObject(&brush);
nRadius = pCurve->m_nWidth + 1;
if ((1 == pCurve->m_ArrPoint.GetSize()) && (pCurve->m_ArrPoint[0] != INVALID_POINT))
{
// if there is only one point in m_ArrPoint, draw it
rect.top = pCurve->m_ArrPoint[0].y - nRadius / 2;
rect.bottom = pCurve->m_ArrPoint[0].y + nRadius / 2;
rect.left = pCurve->m_ArrPoint[0].x - nRadius / 2;
rect.right = pCurve->m_ArrPoint[0].x + nRadius / 2;
pdc->Rectangle(rect);
}
else // draw connected line between neighbor key points in m_ArrPoint
{
// flag for whether already begin draw line
BOOL bStart = FALSE;
// make sure that line get to margin line if there are points outside drawing area
for (iPoint = 0; iPoint < pCurve->m_ArrPoint.GetSize(); iPoint++)
{
// if point in drawing area(INVALID_POINT)
if (pCurve->m_ArrPoint[iPoint] == INVALID_POINT)
{
if (!bStart) // if not begin drawing,then INVALID_PINT is foregoing points, don't draw it
{
continue;
}
else if (iPoint != pCurve->m_ArrPoint.GetUpperBound()) // if already beginning, then INVALID_PINT isback points
{
CPoint ptside;
// using line equation to calculate value , and then point in pixel
// k = (y2 - y1) / (x2 - x1)
float k = float(pCurve->m_fArrVertValue[iPoint] - pCurve->m_fArrVertValue[iPoint + 1])
/ float(pCurve->m_fArrHoriValue[iPoint] - pCurve->m_fArrHoriValue[iPoint + 1]);
//b = (x2 * y1 - x1 * y2) / (x2 - x1)
float b = float(pCurve->m_fArrHoriValue[iPoint] * pCurve->m_fArrVertValue[iPoint + 1]
- pCurve->m_fArrHoriValue[iPoint + 1] * pCurve->m_fArrVertValue[iPoint])
/ float(pCurve->m_fArrHoriValue[iPoint] - pCurve->m_fArrHoriValue[iPoint + 1]);
float fVside = k * m_fHoriEnd + b;
CalculatePoint(m_fHoriEnd, fVside, ptside);
// pdc->LineTo(ptside);
}
break; // return if connect to margin line
}// end INVALID_POINT
if (!bStart) // begin drawing after first validate point
{
bStart = TRUE;
// if the first validate point is out of drawing area, draw line to margin line
if (iPoint > 0)
{
CPoint ptside;
if (fabs(pCurve->m_fArrHoriValue[iPoint] - pCurve->m_fArrHoriValue[iPoint - 1]) > CURVE_EPSILON)
{
// k = (y2 - y1) / (x2 - x1)
float k = float(pCurve->m_fArrVertValue[iPoint] - pCurve->m_fArrVertValue[iPoint - 1])
/ float(pCurve->m_fArrHoriValue[iPoint] - pCurve->m_fArrHoriValue[iPoint - 1]);
//b = (x2 * y1 - x1 * y2) / (x2 - x1)
float b = float(pCurve->m_fArrHoriValue[iPoint] * pCurve->m_fArrVertValue[iPoint - 1]
- pCurve->m_fArrHoriValue[iPoint - 1] * pCurve->m_fArrVertValue[iPoint])
/ float(pCurve->m_fArrHoriValue[iPoint] - pCurve->m_fArrHoriValue[iPoint - 1]);
float fVside = k * m_fHoriBegin + b;
CalculatePoint(m_fHoriBegin, fVside, ptside);
}
else
{
ptside = CPoint(m_RectCoord.left, pCurve->m_ArrPoint[iPoint-1].y);
}
pdc->MoveTo(ptside);
}
else
pdc->MoveTo(pCurve->m_ArrPoint[iPoint]);
} // end first validate point
// connect line between neighbor points
pdc->LineTo(pCurve->m_ArrPoint[iPoint]);
if (pCurve->m_bSelected)
{
rect.top = pCurve->m_ArrPoint[iPoint].y - nRadius;
rect.bottom = pCurve->m_ArrPoint[iPoint].y + nRadius;
rect.left = pCurve->m_ArrPoint[iPoint].x - nRadius;
rect.right = pCurve->m_ArrPoint[iPoint].x + nRadius;
pdc->Ellipse(rect);
}
} //end for pCurve->m_ArrPoint
}
pdc->SelectObject(pOldBrush);
pdc->SelectObject(pOldPen);
brush.DeleteObject();
Pen.DeleteObject();
} // end for m_ArrCurve
}
//-------------------------------------------------------------------------------------------------
// 功能:add a curve
// 参数:strName -- curve name, must not empty
// color -- curve line color
// iStyle -- curve line style
// nWidth -- curve line width
// 返回:index of the added curve in CCurveCtrl
//-------------------------------------------------------------------------------------------------
int CCurveCtrl::AddCurve(const CString& strName, COLORREF color, int iStyle, int nWidth)
{
if (strName.IsEmpty())
return -1;
for (int iCurve = 0; iCurve < m_ArrCurve.GetSize(); iCurve++)
{
if (strName == m_ArrCurve[iCurve]->m_strName)
return -1;
}
CCurve* pCurve = new CCurve;
pCurve->m_strName = strName;
pCurve->m_crColor = color;
pCurve->m_iStyle = iStyle;
pCurve->m_nWidth = nWidth;
// restore zoom
m_iZoom = 0;
return m_ArrCurve.Add(pCurve);
}
//-------------------------------------------------------------------------------------------------
// 功能:add data to an exist curve
// 参数:strName -- curve name
// fHoriValue -- horizontal value
// fVertValue -- vertical value
// 返回:TRUE: data added to curve; FALSE: curve is empty or there are no curve named as strName
//-------------------------------------------------------------------------------------------------
BOOL CCurveCtrl::AddData(const CString& strName, float fHoriValue, float fVertValue)
{
if (strName.IsEmpty())
return FALSE;
CCurve* pCurve = NULL;
for (int iCurve = 0; iCurve < m_ArrCurve.GetSize(); iCurve++)
{
if (strName == m_ArrCurve[iCurve]->m_strName)
{
pCurve = m_ArrCurve[iCurve];
break;
}
}
// following AddData(...) will check whether pCurve is NULL
return AddData(pCurve, fHoriValue, fVertValue);
}
// description : add data to an exist curve
// in parameter : pCurve -- curve pointer in this CCurveCtrl
// fHoriValue -- horizontal value
// fVertValue -- vertical value
// return value : TRUE: data added to curve; FALSE: pointer of curve invalidate
BOOL CCurveCtrl::AddData(CCurve* pCurve, float fHori, float fVert)
{
if (!pCurve)
return FALSE;
// ad data to array, inserted position decided by horizontal value
ASSERT(pCurve->m_fArrHoriValue.GetSize() == pCurve->m_fArrVertValue.GetSize());
InsertDataToCurve(pCurve, fHori, fVert);
// save max and min values in horizontal
// m_fHoriMax = max(m_fHoriMax, fHori);
// m_fHoriMin = min(m_fHoriMin, fHori);
CalculateVertRange(fVert, TRUE);
CalculateVertRange(fVert, FALSE);
// m_fHoriBegin = m_fHoriMin;
// m_fHoriEnd = m_fHoriMax;
return TRUE;
}
// decription : insert data to data array which already sorted by horizontal value
// in parameter: pCurve -- Curve object pointer
// fHori -- horizontal value
// fVert -- vertical value
// point -- corresponding point in pixel
// return value: index of the added data in data array
int CCurveCtrl::InsertDataToCurve(CCurve* pCurve, float fHori, float fVert, CPoint point)
{
if (!pCurve)
return -1;
ASSERT(pCurve->m_fArrHoriValue.GetSize() == pCurve->m_fArrVertValue.GetSize());
ASSERT(pCurve->m_fArrHoriValue.GetSize() == pCurve->m_ArrPoint.GetSize());
for (int iIndex = pCurve->m_fArrHoriValue.GetUpperBound(); iIndex >= 0; iIndex--)
{
if (pCurve->m_fArrHoriValue[iIndex] < fHori)
{
break;
}
}
if (iIndex == pCurve->m_fArrHoriValue.GetUpperBound())
{
pCurve->m_ArrPoint.Add(point);
pCurve->m_fArrHoriValue.Add(fHori);
pCurve->m_fArrVertValue.Add(fVert);
}
else
{
pCurve->m_ArrPoint.InsertAt(iIndex + 1, point);
pCurve->m_fArrHoriValue.InsertAt(iIndex + 1, fHori);
pCurve->m_fArrVertValue.InsertAt(iIndex + 1, fVert);
}
return iIndex + 1;
}
// decription : add one curve and copy it's data to data array
// in parameter: strName -- curve name
// ArrHori -- data array of horizontal value
// ArrVert -- data array of vertical value
// return value: TRUE if success
BOOL CCurveCtrl::AddCurveData(const CString& strName, const CArray< float, float >& ArrHori, const CArray< float, float >& ArrVert)
{
int iCurve = AddCurve(strName);
if (iCurve < 0 || (ArrHori.GetSize() != ArrVert.GetSize()))
return FALSE;
// copy data
m_ArrCurve[iCurve]->m_fArrHoriValue.Copy(ArrHori);
m_ArrCurve[iCurve]->m_fArrVertValue.Copy(ArrVert);
// make sure point array has the same size as the data arrays
m_ArrCurve[iCurve]->m_ArrPoint.SetSize(ArrHori.GetSize());
// remember the max and min value
int iIndex;
for (iIndex = 0; iIndex < ArrHori.GetSize(); iIndex++)
{
m_fHoriMax = max(m_fHoriMax, ArrHori[iIndex]);
m_fHoriMin = min(m_fHoriMin, ArrHori[iIndex]);
}
// to adjust max and min value in vertical for mouse editing
float fVMax = -FLT_MAX / 2;
float fVMin = FLT_MAX / 2;
for (iIndex = 0; iIndex < ArrVert.GetSize(); iIndex++)
{
fVMax = max(fVMax, ArrVert[iIndex]);
fVMin = min(fVMin, ArrVert[iIndex]);
}
SortCurveData(m_ArrCurve[iCurve]);
CalculateVertRange(fVMax, TRUE);
CalculateVertRange(fVMin, FALSE);
m_fHoriBegin = m_fHoriMin;
m_fHoriEnd = m_fHoriMax;
return TRUE;
}
// decription : sort data to make sure all arrays order by horizontal value
void CCurveCtrl::SortCurveData(CCurve* pCurve)
{
int nCount = pCurve->m_fArrHoriValue.GetSize();
ASSERT(nCount == pCurve->m_fArrVertValue.GetSize());
ASSERT(nCount == pCurve->m_ArrPoint.GetSize());
int iPos;
float fTemp;
CPoint PtTemp;
for (int iPre = 0; iPre < nCount - 1; iPre++)
{
iPos = iPre;
for (int iAft = iPre + 1; iAft < nCount; iAft++)
{
if (pCurve->m_fArrHoriValue[iPre] > pCurve->m_fArrHoriValue[iAft])
{
iPos = iAft;
}
}
// exchange
if (iPos != iPre)
{
// horizontal value
fTemp = pCurve->m_fArrHoriValue[iPre];
pCurve->m_fArrHoriValue[iPre] = pCurve->m_fArrHoriValue[iPos];
pCurve->m_fArrHoriValue[iPos] = fTemp;
// vertical value
fTemp = pCurve->m_fArrVertValue[iPre];
pCurve->m_fArrVertValue[iPre] = pCurve->m_fArrVertValue[iPos];
pCurve->m_fArrVertValue[iPos] = fTemp;
// point
PtTemp = pCurve->m_ArrPoint[iPre];
pCurve->m_ArrPoint[iPre] = pCurve->m_ArrPoint[iPos];
pCurve->m_ArrPoint[iPos] = PtTemp;
}
}
}
// decription : get CCurve object pointer by its index in this CCurveCtrl
CCurve* CCurveCtrl::GetCurve(int iIndex)
{
if (iIndex > m_ArrCurve.GetUpperBound() || iIndex < 0)
return NULL;
return m_ArrCurve[iIndex];
}
// decription : get CCurve object pointer by its name
CCurve* CCurveCtrl::GetCurve(const CString& strName)
{
CCurve* pCurve = NULL;
for (int iCurve = 0; iCurve < m_ArrCurve.GetSize(); iCurve++)
{
if (strName == m_ArrCurve[iCurve]->m_strName)
{
pCurve = m_ArrCurve[iCurve];
break;
}
}
return pCurve;
}
// decription : get index in this CCurveCtrl by CCurve object pointer
int CCurveCtrl::GetIndex(const CCurve* pCurve)
{
int iPos = -1;
for (int iCur = 0; iCur < m_ArrCurve.GetSize(); iCur++)
{
if (pCurve == m_ArrCurve[iCur])
{
iPos = iCur;
break;
}
}
return iPos;
}
// decription : remove one curve by its index
BOOL CCurveCtrl::Remove(int index)
{
if (index < 0 || index > m_ArrCurve.GetUpperBound())
return FALSE;
delete m_ArrCurve[index];
m_ArrCurve[index] = NULL;
m_ArrCurve.RemoveAt(index);
// disable edit mode if no curve selected
if (GetSelectedCount() < 1)
m_bEdit = FALSE;
return TRUE;
}
// decription : remove one curve by its name
BOOL CCurveCtrl::Remove(const CString& strName)
{
for (int iCurve = 0; iCurve < m_ArrCurve.GetSize(); iCurve++)
{
if (strName == m_ArrCurve[iCurve]->m_strName)
{
delete m_ArrCurve[iCurve];
m_ArrCurve[iCurve] = NULL;
m_ArrCurve.RemoveAt(iCurve);
return TRUE;
}
}
return FALSE;
}
// decription : remove all curve object in this CCurveCtrl
void CCurveCtrl::RemoveAll()
{
for (int iC = 0; iC < m_ArrCurve.GetSize(); iC++)
{
delete m_ArrCurve[iC];
m_ArrCurve[iC] = NULL;
}
m_ArrCurve.RemoveAll();
// there are no curve, so disable edit
m_bEdit = FALSE;
}
// decription : get curve count in this CCurveCtrl
int CCurveCtrl::GetCurveCount()
{
return m_ArrCurve.GetSize();
}
// decription : get selected curve count
int CCurveCtrl::GetSelectedCount()
{
int nSelected = 0;
for (int iCurve = 0; iCurve < m_ArrCurve.GetSize(); iCurve++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -