352 lines
8.1 KiB
C++
352 lines
8.1 KiB
C++
/*
|
|
*
|
|
* ChartPointsArray.cpp
|
|
*
|
|
* Written by Cédric Moonen (cedric_moonen@hotmail.com)
|
|
*
|
|
*
|
|
*
|
|
* This code may be used for any non-commercial and commercial purposes in a compiled form.
|
|
* The code may be redistributed as long as it remains unmodified and providing that the
|
|
* author name and this disclaimer remain intact. The sources can be modified WITH the author
|
|
* consent only.
|
|
*
|
|
* This code is provided without any garanties. I cannot be held responsible for the damage or
|
|
* the loss of time it causes. Use it at your own risks
|
|
*
|
|
* An e-mail to notify me that you are using this code is appreciated also.
|
|
*
|
|
*/
|
|
|
|
#include "ChartPointsArray.h"
|
|
|
|
template <class T>
|
|
CChartPointsArray<T>::CChartPointsArray(unsigned iResize)
|
|
: m_pPoints(NULL), m_iMaxPoints(iResize), m_iCurrentPoints(0),
|
|
m_iResize(iResize), m_Ordering(poXOrdering)
|
|
{
|
|
m_pPoints = new T[iResize];
|
|
}
|
|
|
|
template <class T>
|
|
CChartPointsArray<T>::~CChartPointsArray()
|
|
{
|
|
if (m_pPoints)
|
|
{
|
|
delete[] m_pPoints;
|
|
m_pPoints = NULL;
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
void CChartPointsArray<T>::AddPoint(const T& newPoint)
|
|
{
|
|
if (m_iCurrentPoints == m_iMaxPoints)
|
|
{
|
|
m_iMaxPoints += m_iResize;
|
|
T* pOldPoints = m_pPoints;
|
|
m_pPoints = new T[m_iMaxPoints];
|
|
memcpy(m_pPoints,pOldPoints,m_iCurrentPoints*sizeof(T));
|
|
delete[] pOldPoints;
|
|
}
|
|
|
|
if (m_iCurrentPoints == 0)
|
|
{
|
|
m_dXMinVal = newPoint.GetXMin();
|
|
m_dXMaxVal = newPoint.GetXMax();
|
|
m_dYMinVal = newPoint.GetYMin();
|
|
m_dYMaxVal = newPoint.GetYMax();
|
|
}
|
|
else
|
|
{
|
|
if (newPoint.GetXMax() > m_dXMaxVal) m_dXMaxVal = newPoint.GetXMax();
|
|
if (newPoint.GetXMin() < m_dXMinVal) m_dXMinVal = newPoint.GetXMin();
|
|
if (newPoint.GetYMax() > m_dYMaxVal) m_dYMaxVal = newPoint.GetYMax();
|
|
if (newPoint.GetYMin() < m_dYMinVal) m_dYMinVal = newPoint.GetYMin();
|
|
}
|
|
|
|
if (m_Ordering==poNoOrdering)
|
|
{
|
|
m_pPoints[m_iCurrentPoints] = newPoint;
|
|
m_iCurrentPoints++;
|
|
}
|
|
else
|
|
{
|
|
InsertNewPoint(newPoint);
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
void CChartPointsArray<T>::AddPoints(T* pPoints,
|
|
unsigned uCount)
|
|
{
|
|
if (m_iCurrentPoints+uCount > m_iMaxPoints)
|
|
{
|
|
m_iMaxPoints = m_iCurrentPoints+uCount;
|
|
T* pOldPoints = m_pPoints;
|
|
m_pPoints = new T[m_iMaxPoints];
|
|
memcpy(m_pPoints,pOldPoints,m_iCurrentPoints*sizeof(T));
|
|
delete[] pOldPoints;
|
|
}
|
|
for (unsigned i=0; i<uCount; i++)
|
|
AddPoint(pPoints[i]);
|
|
}
|
|
|
|
template<class T>
|
|
void CChartPointsArray<T>::SetPoints(T* pPoints,
|
|
unsigned uCount)
|
|
{
|
|
if (uCount > m_iMaxPoints)
|
|
{
|
|
if (m_pPoints)
|
|
delete[] m_pPoints;
|
|
m_pPoints = new T[uCount];
|
|
m_iMaxPoints = uCount;
|
|
}
|
|
m_iCurrentPoints = uCount;
|
|
|
|
for (unsigned i=0;i<uCount;i++)
|
|
{
|
|
m_pPoints[i] = pPoints[i];
|
|
}
|
|
|
|
ReorderPoints();
|
|
RefreshMinMax();
|
|
}
|
|
|
|
template <class T>
|
|
void CChartPointsArray<T>::Clear()
|
|
{
|
|
if (m_pPoints)
|
|
delete[] m_pPoints;
|
|
m_pPoints = new T[m_iResize];
|
|
m_iMaxPoints = m_iResize;
|
|
m_iCurrentPoints = 0;
|
|
}
|
|
|
|
template <class T>
|
|
void CChartPointsArray<T>::RemovePointsFromBegin(unsigned Count)
|
|
{
|
|
ASSERT (Count < m_iCurrentPoints);
|
|
T* pSource = m_pPoints + Count;
|
|
memmove(m_pPoints, pSource, sizeof(T) * (m_iCurrentPoints-Count));
|
|
m_iCurrentPoints -= Count;
|
|
RefreshMinMax();
|
|
}
|
|
|
|
template <class T>
|
|
void CChartPointsArray<T>::RemovePointsFromEnd(unsigned Count)
|
|
{
|
|
ASSERT (Count < m_iCurrentPoints);
|
|
m_iCurrentPoints -= Count;
|
|
RefreshMinMax();
|
|
}
|
|
|
|
template <class T>
|
|
T& CChartPointsArray<T>::operator[](unsigned Index)
|
|
{
|
|
ASSERT(Index < m_iCurrentPoints);
|
|
return m_pPoints[Index];
|
|
}
|
|
|
|
template <class T>
|
|
const T& CChartPointsArray<T>::operator[](unsigned Index) const
|
|
{
|
|
ASSERT(Index < m_iCurrentPoints);
|
|
return m_pPoints[Index];
|
|
}
|
|
|
|
template <class T>
|
|
bool CChartPointsArray<T>::GetSerieXMinMax(double& Min, double& Max) const
|
|
{
|
|
if (m_iCurrentPoints==0)
|
|
return false;
|
|
|
|
Min = m_dXMinVal;
|
|
Max = m_dXMaxVal;
|
|
return true;
|
|
}
|
|
|
|
template <class T>
|
|
bool CChartPointsArray<T>::GetSerieYMinMax(double& Min, double& Max) const
|
|
{
|
|
if (m_iCurrentPoints==0)
|
|
return false;
|
|
|
|
Min = m_dYMinVal;
|
|
Max = m_dYMaxVal;
|
|
return true;
|
|
}
|
|
|
|
template <class T>
|
|
void CChartPointsArray<T>::SetOrdering(PointsOrdering newOrdering)
|
|
{
|
|
m_Ordering = newOrdering;
|
|
ReorderPoints();
|
|
}
|
|
|
|
template <class T>
|
|
bool CChartPointsArray<T>::GetVisiblePoints(double dAxisMin,
|
|
double dAxisMax,
|
|
unsigned& uFirstPt,
|
|
unsigned& uLastPt) const
|
|
{
|
|
if (m_iCurrentPoints == 0)
|
|
return false;
|
|
|
|
if (m_Ordering == poNoOrdering)
|
|
{
|
|
uFirstPt = 0;
|
|
uLastPt = m_iCurrentPoints - 1;
|
|
return true;
|
|
}
|
|
|
|
uFirstPt = BinarySearch(0,m_iCurrentPoints-1,dAxisMin);
|
|
uLastPt = BinarySearch(uFirstPt,m_iCurrentPoints-1,dAxisMax);
|
|
return true;
|
|
}
|
|
|
|
template <class T>
|
|
void CChartPointsArray<T>::ReorderPoints()
|
|
{
|
|
switch (m_Ordering)
|
|
{
|
|
case poNoOrdering:
|
|
break;
|
|
case poXOrdering:
|
|
qsort(m_pPoints, m_iCurrentPoints, sizeof(T),
|
|
CChartPointsArray::ComparePointsOnX);
|
|
break;
|
|
case poYOrdering:
|
|
qsort(m_pPoints, m_iCurrentPoints, sizeof(T),
|
|
CChartPointsArray::ComparePointsOnY);
|
|
break;
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
void CChartPointsArray<T>::InsertNewPoint(const T& newPoint)
|
|
{
|
|
if (m_iCurrentPoints == 0)
|
|
{
|
|
m_pPoints[0] = newPoint;
|
|
m_iCurrentPoints++;
|
|
return;
|
|
}
|
|
|
|
if (m_Ordering == poXOrdering)
|
|
{
|
|
if (newPoint.GetX() >= m_pPoints[m_iCurrentPoints-1].GetX())
|
|
m_pPoints[m_iCurrentPoints] = newPoint;
|
|
else
|
|
{
|
|
for (unsigned i=0; i<m_iCurrentPoints; i++)
|
|
{
|
|
if (newPoint.GetX() < m_pPoints[i].GetX())
|
|
{
|
|
InsertPointAtPos(newPoint,i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (m_Ordering == poYOrdering)
|
|
{
|
|
if (newPoint.GetY() >= m_pPoints[m_iCurrentPoints-1].GetY())
|
|
m_pPoints[m_iCurrentPoints] = newPoint;
|
|
else
|
|
{
|
|
for (unsigned i=0; i<m_iCurrentPoints; i++)
|
|
{
|
|
if (newPoint.GetY() < m_pPoints[i].GetY())
|
|
{
|
|
InsertPointAtPos(newPoint,i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
m_iCurrentPoints++;
|
|
}
|
|
|
|
template <class T>
|
|
void CChartPointsArray<T>::InsertPointAtPos(const T& newPoint, int iPos)
|
|
{
|
|
// Find the address of the insert point
|
|
T* pPointPos = m_pPoints + iPos;
|
|
// Move all remaining points one place to the right.
|
|
memmove(pPointPos+1,pPointPos,(m_iCurrentPoints-iPos)*sizeof(T));
|
|
// Store the new point
|
|
*pPointPos = newPoint;
|
|
}
|
|
|
|
template <class T>
|
|
int CChartPointsArray<T>::ComparePointsOnX(void const* pA, void const* pB)
|
|
{
|
|
T* pPointA = (T *) pA;
|
|
T* pPointB = (T *) pB;
|
|
|
|
if (pPointA->GetX() < pPointB->GetX()) return -1;
|
|
if (pPointA->GetX() > pPointB->GetX()) return 1;
|
|
return 0;
|
|
}
|
|
|
|
template <class T>
|
|
int CChartPointsArray<T>::ComparePointsOnY(void const* pA, void const* pB)
|
|
{
|
|
T* pPointA = (T *) pA;
|
|
T* pPointB = (T *) pB;
|
|
|
|
if (pPointA->GetY() < pPointB->GetY()) return -1;
|
|
if (pPointA->GetY() > pPointB->GetY()) return 1;
|
|
return 0;
|
|
}
|
|
|
|
template <class T>
|
|
void CChartPointsArray<T>::RefreshMinMax()
|
|
{
|
|
m_dXMinVal = m_pPoints[0].GetXMin();
|
|
m_dXMaxVal = m_pPoints[0].GetXMax();
|
|
m_dYMinVal = m_pPoints[0].GetYMin();
|
|
m_dYMaxVal = m_pPoints[0].GetYMax();
|
|
for (unsigned uIndex=0; uIndex<m_iCurrentPoints; uIndex++)
|
|
{
|
|
if (m_pPoints[uIndex].GetXMax() > m_dXMaxVal)
|
|
m_dXMaxVal = m_pPoints[uIndex].GetXMax();
|
|
if (m_pPoints[uIndex].GetXMin() < m_dXMinVal)
|
|
m_dXMinVal = m_pPoints[uIndex].GetXMin();
|
|
if (m_pPoints[uIndex].GetYMax() > m_dYMaxVal)
|
|
m_dYMaxVal = m_pPoints[uIndex].GetYMax();
|
|
if (m_pPoints[uIndex].GetYMin() < m_dYMinVal)
|
|
m_dYMinVal = m_pPoints[uIndex].GetYMin();
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
int CChartPointsArray<T>::BinarySearch(unsigned uLeft,
|
|
unsigned uRight,
|
|
double dFind) const
|
|
{
|
|
unsigned middle = uLeft + ((uRight - uLeft) /2);
|
|
double midVal = 0;
|
|
if (m_Ordering == poXOrdering)
|
|
midVal = m_pPoints[middle].GetX();
|
|
if (m_Ordering == poYOrdering)
|
|
midVal = m_pPoints[middle].GetY();
|
|
|
|
if(midVal > dFind)
|
|
{
|
|
if(uLeft < middle)
|
|
return BinarySearch(uLeft,middle-1,dFind);
|
|
else
|
|
return uLeft;
|
|
}
|
|
else if(middle < uRight)
|
|
return BinarySearch(middle+1,uRight,dFind);
|
|
else
|
|
return uRight;
|
|
}
|
|
|
|
|