PageRenderTime 739ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/PGLCore/pglbar.cpp

#
C++ | 542 lines | 407 code | 89 blank | 46 comment | 56 complexity | 645998b68dfd0087445626fec9f08431 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  14. * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  15. * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  16. * PARTICULAR PURPOSE.
  17. * ***************************************************************************/
  18. #include "stdafx.h"
  19. #include <pgl/core/PGLBar.h>
  20. #include <pgl/core/PGLDataVectors.h>
  21. #include <pgl/core/DataRegistry.h>
  22. PGL_IMPLEMENT_DYNCREATE(CPGLBar, CPGLObject);
  23. //////////////////////////////////////////////////////////////////////
  24. // Construction/Destruction
  25. //////////////////////////////////////////////////////////////////////
  26. //! Save settings
  27. void CPGLBar::SerializeXML(CPGLArchive& ar)
  28. {
  29. static const TCHAR szTag[] = _T("CPGLBar");
  30. std::_tstring str;
  31. CString strPos; strPos.Format(_T("%u"),(DWORD)this);
  32. CPGLLine1DPtr pLine;
  33. markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup());
  34. if(ar.IsStoring())
  35. {
  36. xml.AddChildElem(szTag);
  37. xml.AddChildAttrib(_T("Name"),GetName());
  38. xml.IntoElem();
  39. /////////////////////////////////////////////////////////
  40. // Adding base class
  41. CPGLObject::SerializeXML(ar);
  42. xml.AddChildElemEx(_T("PixelInter"), m_dPixelInter);
  43. xml.AddChildElem(_T("Series"));
  44. xml.IntoElem();
  45. // savings lines
  46. CPGLLine1DList::iterator il;
  47. for (il= m_lSeries.begin(); il!= m_lSeries.end();il++)
  48. {
  49. pLine = *il;
  50. pLine->SerializeXML(ar);
  51. }
  52. xml.OutOfElem();
  53. xml.OutOfElem();
  54. }
  55. else
  56. {
  57. Clear();
  58. if (!xml.FindChildElem(szTag))
  59. return;
  60. xml.IntoElem();
  61. /////////////////////////////////////////////////////////
  62. // Adding base class
  63. CPGLObject::SerializeXML(ar);
  64. xml.FindGetChildData(_T("PixelInter"), m_dPixelInter);
  65. xml.ResetChildPos();
  66. if (xml.FindChildElem(_T("Series")))
  67. {
  68. xml.IntoElem();
  69. // saving position
  70. xml.SavePos(strPos);
  71. while (xml.FindChildElem(_T("CPGLLine1D")))
  72. {
  73. pLine = CPGLLine1DPtr(new CPGLLine1D);
  74. xml.RestorePos(strPos);
  75. pLine->SerializeXML(ar);
  76. PushFront(pLine);
  77. // saving position
  78. xml.SavePos(strPos);
  79. }
  80. xml.OutOfElem();
  81. }
  82. xml.OutOfElem();
  83. }
  84. }
  85. #ifdef _DEBUG
  86. void CPGLBar::Dump( CDumpContext& dc ) const
  87. {
  88. // call base class function first
  89. CPGLObject::Dump( dc );
  90. // now do the stuff for our specific class
  91. dc << _T("CPGLBar ID ") << GetID() << "\n";
  92. }
  93. void CPGLBar::AssertValid() const
  94. {
  95. // call inherited AssertValid first
  96. CPGLObject::AssertValid();
  97. // check members...
  98. }
  99. #endif
  100. //////////////////////////////////////////////////////////////////////
  101. // Construction/Destruction
  102. //////////////////////////////////////////////////////////////////////
  103. CPGLBar::CPGLBar(EType eType)
  104. : m_eType(eType), m_dPixelInter(10)
  105. {
  106. }
  107. CPGLBar& CPGLBar::operator= (const CPGLBar& b)
  108. {
  109. if (&b != this)
  110. {
  111. Clear();
  112. if (b.m_pX)
  113. m_pX = CPGLDataPtr(b.m_pX->Clone());
  114. m_dPixelInter = b.m_dPixelInter;
  115. m_vXLabels = b.m_vXLabels;
  116. CPGLLine1DList::const_iterator il;
  117. CPGLLine1DPtr pLine1D;
  118. for (il = b.m_lSeries.begin(); il != b.m_lSeries.end(); ++il)
  119. {
  120. if (!*il)
  121. continue;
  122. pLine1D = boost::shared_polymorphic_cast<CPGLLine1D, CPGLNode>((*il)->MakeCopy() );
  123. m_lSeries.push_back(pLine1D);
  124. }
  125. }
  126. return *this;
  127. }
  128. CPGLBar::~CPGLBar()
  129. {
  130. Clear();
  131. }
  132. void CPGLBar::Clear()
  133. {
  134. m_lSeries.clear();
  135. m_pX.reset();
  136. }
  137. void CPGLBar::PlotGfx(gfxinterface::CGfxInterface& gfx)
  138. {
  139. if (!IsVisible())
  140. return;
  141. if (!IsInLayer(gfx.GetLayer()))
  142. return;
  143. if (m_lSeries.empty())
  144. return;
  145. size_t i;
  146. CPGLVectorF vX0,vY0,vWidth,vHeight;
  147. CPGLLine1DPtr pLine;
  148. CPGLLine1DList::iterator il;
  149. CPGLDataPtr pData;
  150. size_t nBars = GetMinimumDataLength();
  151. if (!nBars)
  152. return;
  153. vX0.resize(nBars);
  154. vY0.resize(nBars);
  155. vWidth.resize(nBars);
  156. vHeight.resize(nBars);
  157. // preparing vectors
  158. // computing bar with...
  159. float dBarWidthPx, dXStart, dWidth, dWidth1;
  160. il = m_lSeries.begin();
  161. pLine = *il;
  162. pData = pLine->GetValues();
  163. ASSERT(pData);
  164. dBarWidthPx = GetBarWidth(gfx, nBars);
  165. if (m_pX)
  166. {
  167. switch (m_eType)
  168. {
  169. case ETypeSideBySide:
  170. for (i = 0; i<nBars;++i)
  171. {
  172. vX0[i]=static_cast<float>(gfx.WorldToBBx( m_pX->at(i) ) - m_lSeries.size()/2.0*dBarWidthPx);
  173. }
  174. break;
  175. case ETypeStacked:
  176. // first run, get X positions
  177. for (i = 0; i<nBars;++i)
  178. {
  179. vX0[i]=static_cast<float>(gfx.WorldToBBx( m_pX->at(i) ));
  180. vY0[i]=static_cast<float>(gfx.WorldToBBy(0));
  181. }
  182. break;
  183. }
  184. // second run, get width...
  185. if (nBars == 1)
  186. {
  187. vWidth[0]=dBarWidthPx;
  188. }
  189. else
  190. {
  191. dWidth1=static_cast<float>((fabs(vX0[1] - vX0[0]) - m_dPixelInter)/2.0);
  192. vWidth[0] = static_cast<float>(__min( dBarWidthPx, dWidth1));
  193. vX0[0]-=static_cast<float>(vWidth[0]/2.0);
  194. for (i = 1; i<nBars-1;i++)
  195. {
  196. dWidth = dWidth1;
  197. dWidth1 = static_cast<float>((fabs(vX0[i+1] - vX0[i]) - m_dPixelInter)/2.0);
  198. vWidth[i]=static_cast<float>(__min( dBarWidthPx, __min( dWidth, dWidth1 )));
  199. // update vX
  200. vX0[i]-=static_cast<float>(vWidth[i]/2.0);
  201. }
  202. vWidth[nBars-1] = __min( dBarWidthPx, dWidth1);
  203. vX0[nBars-1]-=static_cast<float>(vWidth[nBars-1]/2.0);
  204. }
  205. }
  206. else // generating positions
  207. {
  208. dXStart = GetBarXStart(gfx, nBars, dBarWidthPx);
  209. switch (m_eType)
  210. {
  211. case ETypeSideBySide:
  212. vX0[0]=dXStart;
  213. vWidth[0]=dBarWidthPx;
  214. for (i = 1; i<nBars;++i)
  215. {
  216. vX0[i]=static_cast<float>(vX0[i-1]+m_lSeries.size()*dBarWidthPx + m_dPixelInter);
  217. vWidth[i]=dBarWidthPx;
  218. }
  219. break;
  220. case ETypeStacked:
  221. for (i = 0; i<nBars;++i)
  222. {
  223. vX0[i]=static_cast<float>(dXStart+i*(dBarWidthPx + m_dPixelInter));
  224. vY0[i]=static_cast<float>(gfx.WorldToBBy(0));
  225. vWidth[i]=dBarWidthPx;
  226. }
  227. break;
  228. }
  229. }
  230. // drawing...
  231. for (; il != m_lSeries.end(); il++)
  232. {
  233. pLine = *il;
  234. if (!pLine)
  235. continue;
  236. pData = pLine->GetValues();
  237. ASSERT(pData);
  238. // setting pen and brush
  239. pLine->SetExtent( GetExtent() );
  240. pLine->CPGLObject::PlotGfx( gfx );
  241. // update vY if stacked...
  242. // updating vX...
  243. switch(m_eType)
  244. {
  245. case ETypeSideBySide:
  246. for (i=0;i<nBars;++i)
  247. {
  248. vX0[i]+=dBarWidthPx;
  249. vHeight[i]=static_cast<float>(gfx.WorldToBBAbsy( pData->at(i) ));
  250. vY0[i]= static_cast<float>(gfx.WorldToBBy(0)+gfx.GetYDirectionUp()*vHeight[i]) ;
  251. }
  252. break;
  253. case ETypeStacked:
  254. for (i = 0; i<nBars;++i)
  255. {
  256. vHeight[i]=static_cast<float>(gfx.WorldToBBAbsy( pData->at(i) ));
  257. vY0[i] += static_cast<float>(gfx.GetYDirectionUp()*vHeight[i]);
  258. }
  259. break;
  260. }
  261. // drawing
  262. gfx.DrawRectStrip( vX0, vY0, vWidth, vHeight, pLine->GetERectType());
  263. }
  264. }
  265. void CPGLBar::GetUnionExtent(gfxinterface::CGfxInterface& gfx, CPGLRectD& rExtent)
  266. {
  267. CPGLObject::GetUnionExtent(gfx, rExtent);
  268. GetExtent().SetUnion(rExtent);
  269. if (m_pX)
  270. rExtent.xValid=true;
  271. else
  272. rExtent.xValid=false;
  273. if (m_lSeries.empty())
  274. rExtent.yValid=false;
  275. else
  276. rExtent.yValid=true;
  277. }
  278. void CPGLBar::UpdateExtent(gfxinterface::CGfxInterface& gfx)
  279. {
  280. using namespace std;
  281. // Calling base class function
  282. CPGLObject::UpdateExtent(gfx);
  283. if (m_lSeries.size()==0)
  284. return;
  285. CPGLRectD rExtent;
  286. CPGLLine1DPtr pLine;
  287. vector<float> vYSum;
  288. CPGLLine1DList::iterator il;
  289. double dMax, dMin;
  290. CPGLDataPtr pData;
  291. size_t uMin, uMax, n, i;
  292. if (m_pX)
  293. {
  294. m_pX->GetMinMaxIndex(uMin, uMax);
  295. rExtent.left = (*m_pX)[ uMin ];
  296. rExtent.right = (*m_pX)[ uMax ];
  297. }
  298. else
  299. {
  300. rExtent.left=0;
  301. rExtent.right=1;
  302. }
  303. switch(m_eType)
  304. {
  305. case ETypeSideBySide:
  306. il = m_lSeries.begin();
  307. pLine = *il;
  308. pData=pLine->GetValues();
  309. ASSERT(pData);
  310. rExtent.bottom = (*pData)[pData->GetMinIndex()];
  311. rExtent.top = (*pData)[pData->GetMaxIndex()];
  312. for (; il != m_lSeries.end(); ++il)
  313. {
  314. pLine = *il;
  315. if (!pLine)
  316. continue;
  317. pData=pLine->GetValues();
  318. ASSERT(pData);
  319. pData->GetMinMaxIndex(uMin, uMax);
  320. dMin = (*pData)[uMin];
  321. dMax = (*pData)[uMax];
  322. rExtent.bottom = __min( dMin, rExtent.bottom);
  323. rExtent.top = __max( dMax, rExtent.top);
  324. }
  325. rExtent.bottom=__min(0, rExtent.bottom);
  326. break;
  327. case ETypeStacked:
  328. n=GetMinimumDataLength();
  329. vYSum.resize(n);
  330. il = m_lSeries.begin();
  331. pLine = *il;
  332. pData=pLine->GetValues();
  333. ASSERT(pData);
  334. for (i=0;i<n;i++)
  335. vYSum[i] = (*pData)[i];
  336. il++;
  337. for (; il != m_lSeries.end(); ++il)
  338. {
  339. pLine = *il;
  340. if (!pLine)
  341. continue;
  342. pData=pLine->GetValues();
  343. ASSERT(pData);
  344. for (i=0;i<n;i++)
  345. vYSum[i] += (*pData)[i];
  346. }
  347. rExtent.bottom = rExtent.top = vYSum[0];
  348. rExtent.bottom = __min(rExtent.bottom, 0);
  349. for (i=1;i<n;i++)
  350. {
  351. rExtent.bottom = __min( vYSum[i], rExtent.bottom);
  352. rExtent.top = __max( vYSum[i], rExtent.top);
  353. }
  354. break;
  355. }
  356. SetExtent(rExtent);
  357. }
  358. size_t CPGLBar::GetMinimumDataLength() const
  359. {
  360. if (m_lSeries.empty())
  361. return 0;
  362. CPGLLine1DPtr pLine;
  363. CPGLLine1DList::const_iterator il;
  364. il = m_lSeries.begin();
  365. pLine = *il;
  366. ASSERT(pLine);
  367. size_t nBars=pLine->GetValues()->size();
  368. il++;
  369. for (; il != m_lSeries.end(); ++il)
  370. {
  371. pLine = *il;
  372. ASSERT(pLine);
  373. nBars = __min( nBars, pLine->GetValues()->size());
  374. }
  375. return nBars;
  376. }
  377. void CPGLBar::PushLinesTop(CPGLLegendPtr pLegend)
  378. {
  379. if (! pLegend)
  380. return;
  381. CPGLLine1DList::iterator il;
  382. for (il = m_lSeries.begin(); il != m_lSeries.end(); ++il)
  383. {
  384. pLegend->PushTop( *il );
  385. }
  386. }
  387. float CPGLBar::GetBarWidth(const gfxinterface::CGfxInterface& gfx, size_t nBars) const
  388. {
  389. double dPixelWidth;
  390. if (m_pX)
  391. {
  392. dPixelWidth = gfx.WorldToBBAbsx( GetExtent().GetWidth() );
  393. }
  394. else
  395. {
  396. dPixelWidth=gfx.GetBBClipWidth();
  397. }
  398. switch (m_eType)
  399. {
  400. case ETypeSideBySide:
  401. return static_cast<float>(( dPixelWidth - (nBars-1)*m_dPixelInter ) / (m_lSeries.size()*nBars));
  402. case ETypeStacked:
  403. return static_cast<float>(( dPixelWidth - (nBars-1)*m_dPixelInter)/ (nBars));
  404. default:
  405. ASSERT(false);
  406. return 0;
  407. }
  408. }
  409. float CPGLBar::GetBarXStart(const gfxinterface::CGfxInterface& gfx, size_t nBars, double dBarWidthPixel) const
  410. {
  411. double dPixelStart, dOffset;
  412. if (m_pX)
  413. {
  414. dPixelStart = gfx.WorldToBBx( GetExtent().left );
  415. dOffset = 0.5;
  416. }
  417. else
  418. {
  419. dPixelStart = gfx.GetBBClipLeft();
  420. dOffset = 0;
  421. }
  422. switch (m_eType)
  423. {
  424. case ETypeSideBySide:
  425. return static_cast<float>(dPixelStart - dBarWidthPixel*(1 + dOffset));
  426. case ETypeStacked:
  427. return static_cast<float>(dPixelStart - dBarWidthPixel*dOffset);
  428. default:
  429. ASSERT(false);
  430. return 0;
  431. }
  432. }
  433. void CPGLBar::SetXPositions( CPGLDataPtr pXs)
  434. {
  435. m_pX = pXs;
  436. PostUpdateExtent();
  437. };
  438. void CPGLBar::PushFront( CPGLLine1DPtr pSerie )
  439. {
  440. if (!pSerie)
  441. return ;
  442. pSerie->SetFilled(true);
  443. pSerie->SetOpen(false);
  444. m_lSeries.push_front( pSerie );
  445. };
  446. void CPGLBar::PushTail( CPGLLine1DPtr pSerie )
  447. {
  448. if (!pSerie)
  449. return ;
  450. pSerie->SetFilled(true);
  451. pSerie->SetOpen(false);
  452. m_lSeries.push_back( pSerie );
  453. };