PageRenderTime 1ms CodeModel.GetById 34ms app.highlight 26ms RepoModel.GetById 0ms 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
 19
 20#include "stdafx.h"
 21#include <pgl/core/PGLBar.h>
 22#include <pgl/core/PGLDataVectors.h>
 23#include <pgl/core/DataRegistry.h>
 24
 25PGL_IMPLEMENT_DYNCREATE(CPGLBar, CPGLObject);
 26
 27//////////////////////////////////////////////////////////////////////
 28// Construction/Destruction
 29//////////////////////////////////////////////////////////////////////
 30
 31//! Save settings
 32void CPGLBar::SerializeXML(CPGLArchive& ar)
 33{
 34	static const TCHAR szTag[] = _T("CPGLBar");
 35	std::_tstring str;
 36	CString strPos;	strPos.Format(_T("%u"),(DWORD)this);
 37	CPGLLine1DPtr pLine;
 38
 39	markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup());
 40	if(ar.IsStoring())
 41	{
 42		xml.AddChildElem(szTag);
 43		xml.AddChildAttrib(_T("Name"),GetName());
 44		xml.IntoElem();
 45
 46			/////////////////////////////////////////////////////////
 47			// Adding base class
 48			CPGLObject::SerializeXML(ar);
 49
 50			xml.AddChildElemEx(_T("PixelInter"), m_dPixelInter);
 51
 52			xml.AddChildElem(_T("Series"));
 53			xml.IntoElem();
 54				// savings lines
 55				CPGLLine1DList::iterator il;
 56				for (il= m_lSeries.begin(); il!= m_lSeries.end();il++)
 57				{
 58					pLine = *il;					
 59					pLine->SerializeXML(ar);
 60				}
 61			xml.OutOfElem();
 62			
 63		xml.OutOfElem();
 64	}
 65	else
 66	{
 67		Clear();
 68
 69		if  (!xml.FindChildElem(szTag))
 70				return;
 71
 72		xml.IntoElem();
 73			/////////////////////////////////////////////////////////
 74			// Adding base class
 75			CPGLObject::SerializeXML(ar);
 76
 77			xml.FindGetChildData(_T("PixelInter"), m_dPixelInter);
 78			
 79			xml.ResetChildPos();
 80			if (xml.FindChildElem(_T("Series")))
 81			{
 82				xml.IntoElem();
 83					// saving position
 84					xml.SavePos(strPos);
 85					while (xml.FindChildElem(_T("CPGLLine1D")))
 86					{
 87						pLine = CPGLLine1DPtr(new CPGLLine1D);	
 88
 89						xml.RestorePos(strPos);
 90
 91						pLine->SerializeXML(ar);
 92						PushFront(pLine);
 93
 94						// saving position
 95						xml.SavePos(strPos);
 96					}
 97				xml.OutOfElem();
 98			}
 99
100		xml.OutOfElem();
101	}
102
103}
104
105
106#ifdef _DEBUG
107void CPGLBar::Dump( CDumpContext& dc ) const
108{
109    // call base class function first
110    CPGLObject::Dump( dc );
111
112    // now do the stuff for our specific class
113	dc << _T("CPGLBar ID ") << GetID() << "\n";
114}
115void CPGLBar::AssertValid() const
116{
117    // call inherited AssertValid first
118    CPGLObject::AssertValid();
119
120    // check members...
121} 
122#endif
123
124//////////////////////////////////////////////////////////////////////
125// Construction/Destruction
126//////////////////////////////////////////////////////////////////////
127
128CPGLBar::CPGLBar(EType eType)
129: m_eType(eType), m_dPixelInter(10)
130{
131
132}
133
134CPGLBar& CPGLBar::operator= (const CPGLBar& b)
135{
136	if (&b != this)
137	{
138		Clear();
139		
140		if (b.m_pX)
141			m_pX = CPGLDataPtr(b.m_pX->Clone());
142
143		m_dPixelInter = b.m_dPixelInter;
144
145		m_vXLabels = b.m_vXLabels;
146
147		CPGLLine1DList::const_iterator il;
148		CPGLLine1DPtr pLine1D;
149		for (il = b.m_lSeries.begin(); il != b.m_lSeries.end(); ++il)
150		{
151			if (!*il)
152				continue;
153
154			pLine1D = boost::shared_polymorphic_cast<CPGLLine1D, CPGLNode>((*il)->MakeCopy() );
155			m_lSeries.push_back(pLine1D);
156		}	
157	}
158	return *this;
159}
160
161CPGLBar::~CPGLBar()
162{
163	Clear();
164}
165
166void CPGLBar::Clear()
167{
168	m_lSeries.clear();
169
170	m_pX.reset();
171}
172
173void CPGLBar::PlotGfx(gfxinterface::CGfxInterface& gfx)
174{
175	if (!IsVisible())
176		return;
177	if (!IsInLayer(gfx.GetLayer()))
178		return;
179	if (m_lSeries.empty())	
180		return;
181
182	size_t i;
183	CPGLVectorF vX0,vY0,vWidth,vHeight;
184	CPGLLine1DPtr pLine;
185	CPGLLine1DList::iterator il;
186	CPGLDataPtr pData;
187
188	size_t nBars = GetMinimumDataLength();
189	if (!nBars)
190		return;
191	vX0.resize(nBars);
192	vY0.resize(nBars);
193	vWidth.resize(nBars);
194	vHeight.resize(nBars);
195
196	// preparing vectors
197	// computing bar with...
198	float dBarWidthPx, dXStart, dWidth, dWidth1;
199	il = m_lSeries.begin();
200	pLine = *il;
201	pData = pLine->GetValues();
202	ASSERT(pData);
203
204	dBarWidthPx = GetBarWidth(gfx, nBars);
205
206	if (m_pX)
207	{
208		switch (m_eType)
209		{
210		case ETypeSideBySide:
211			for (i = 0; i<nBars;++i)
212			{
213				vX0[i]=static_cast<float>(gfx.WorldToBBx( m_pX->at(i) ) - m_lSeries.size()/2.0*dBarWidthPx);
214			}
215			break;
216		case ETypeStacked:
217			// first run, get X positions
218			for (i = 0; i<nBars;++i)
219			{
220				vX0[i]=static_cast<float>(gfx.WorldToBBx( m_pX->at(i) ));
221				vY0[i]=static_cast<float>(gfx.WorldToBBy(0));
222			}
223			break;
224		}
225
226		// second run, get width...
227		if (nBars == 1)
228		{
229			vWidth[0]=dBarWidthPx;
230		}
231		else
232		{
233			dWidth1=static_cast<float>((fabs(vX0[1] - vX0[0]) - m_dPixelInter)/2.0);
234			vWidth[0] = static_cast<float>(__min( dBarWidthPx, dWidth1)); 
235			vX0[0]-=static_cast<float>(vWidth[0]/2.0);
236			for (i = 1; i<nBars-1;i++)
237			{
238				dWidth = dWidth1;
239				dWidth1 = static_cast<float>((fabs(vX0[i+1] - vX0[i]) - m_dPixelInter)/2.0);
240
241				vWidth[i]=static_cast<float>(__min( dBarWidthPx,  __min( dWidth, dWidth1 )));
242
243				// update vX
244				vX0[i]-=static_cast<float>(vWidth[i]/2.0);
245			}
246			vWidth[nBars-1] = __min( dBarWidthPx, dWidth1);
247			vX0[nBars-1]-=static_cast<float>(vWidth[nBars-1]/2.0);
248		}
249	}
250	else // generating positions
251	{
252		dXStart = GetBarXStart(gfx, nBars, dBarWidthPx);
253
254		switch (m_eType)
255		{
256		case ETypeSideBySide:
257			vX0[0]=dXStart;
258			vWidth[0]=dBarWidthPx;
259			for (i = 1; i<nBars;++i)
260			{
261				vX0[i]=static_cast<float>(vX0[i-1]+m_lSeries.size()*dBarWidthPx + m_dPixelInter);
262				vWidth[i]=dBarWidthPx;
263			}
264			break;
265		case ETypeStacked:
266			for (i = 0; i<nBars;++i)
267			{
268				vX0[i]=static_cast<float>(dXStart+i*(dBarWidthPx + m_dPixelInter));
269				vY0[i]=static_cast<float>(gfx.WorldToBBy(0));
270				vWidth[i]=dBarWidthPx;
271			}
272			break;
273		}
274	}
275
276	// drawing...
277	for (; il != m_lSeries.end(); il++)
278	{		
279		pLine = *il;
280		if (!pLine)
281			continue;
282
283		pData = pLine->GetValues();
284		ASSERT(pData);
285
286		// setting pen and brush
287		pLine->SetExtent( GetExtent() );
288		pLine->CPGLObject::PlotGfx( gfx );	
289
290		// update vY if stacked...
291		// updating vX...
292		switch(m_eType)
293		{
294		case ETypeSideBySide:
295			for (i=0;i<nBars;++i)
296			{
297				vX0[i]+=dBarWidthPx;
298				vHeight[i]=static_cast<float>(gfx.WorldToBBAbsy( pData->at(i) ));
299				vY0[i]= static_cast<float>(gfx.WorldToBBy(0)+gfx.GetYDirectionUp()*vHeight[i]) ;
300			}
301			break;
302		case ETypeStacked:
303			for (i = 0; i<nBars;++i)
304			{
305				vHeight[i]=static_cast<float>(gfx.WorldToBBAbsy( pData->at(i) ));
306				vY0[i] += static_cast<float>(gfx.GetYDirectionUp()*vHeight[i]);
307			}
308			break;
309		}
310
311		// drawing
312		gfx.DrawRectStrip( vX0, vY0, vWidth, vHeight, pLine->GetERectType());
313	}
314}
315
316void CPGLBar::GetUnionExtent(gfxinterface::CGfxInterface& gfx, CPGLRectD& rExtent)
317{
318	CPGLObject::GetUnionExtent(gfx, rExtent);
319
320	GetExtent().SetUnion(rExtent);
321	
322	if (m_pX)
323		rExtent.xValid=true;
324	else
325		rExtent.xValid=false;
326
327	if (m_lSeries.empty())
328		rExtent.yValid=false;
329	else
330		rExtent.yValid=true;
331}
332
333void CPGLBar::UpdateExtent(gfxinterface::CGfxInterface& gfx)
334{
335	using namespace std;
336	// Calling base class function
337	CPGLObject::UpdateExtent(gfx);
338
339	if (m_lSeries.size()==0)
340		return;
341
342	CPGLRectD rExtent;
343	CPGLLine1DPtr pLine;
344	vector<float> vYSum;
345	CPGLLine1DList::iterator il;
346	double dMax, dMin;
347	CPGLDataPtr pData;
348	size_t uMin, uMax, n, i;
349
350	if (m_pX)
351	{
352		m_pX->GetMinMaxIndex(uMin, uMax);
353		rExtent.left = (*m_pX)[ uMin ];
354		rExtent.right = (*m_pX)[ uMax ];
355	}
356	else
357	{
358		rExtent.left=0;
359		rExtent.right=1;
360	}
361
362	switch(m_eType)
363	{
364	case ETypeSideBySide:
365		il = m_lSeries.begin();
366		pLine = *il;
367	
368		pData=pLine->GetValues();
369		ASSERT(pData);
370	
371		rExtent.bottom = (*pData)[pData->GetMinIndex()];
372		rExtent.top = (*pData)[pData->GetMaxIndex()];
373
374		for (; il != m_lSeries.end(); ++il)
375		{
376			pLine = *il;
377			if (!pLine)
378				continue;
379
380			pData=pLine->GetValues();	
381			ASSERT(pData);
382
383			pData->GetMinMaxIndex(uMin, uMax);
384			dMin = (*pData)[uMin];
385			dMax = (*pData)[uMax];
386			rExtent.bottom = __min( dMin, rExtent.bottom);
387			rExtent.top = __max( dMax, rExtent.top);
388		}
389
390		rExtent.bottom=__min(0, rExtent.bottom);
391		break;
392	case ETypeStacked:
393		n=GetMinimumDataLength();
394		vYSum.resize(n);
395		
396		il = m_lSeries.begin();
397		pLine = *il;
398	
399		pData=pLine->GetValues();
400		ASSERT(pData);
401		for (i=0;i<n;i++)
402			vYSum[i] = (*pData)[i];
403
404		il++;
405		for (; il != m_lSeries.end(); ++il)
406		{
407			pLine = *il;
408			if (!pLine)
409				continue;
410			pData=pLine->GetValues();	
411			ASSERT(pData);
412
413			for (i=0;i<n;i++)
414				vYSum[i] += (*pData)[i];
415		}
416
417		rExtent.bottom = rExtent.top = vYSum[0];
418		rExtent.bottom = __min(rExtent.bottom, 0);
419		for (i=1;i<n;i++)
420		{
421			rExtent.bottom = __min( vYSum[i], rExtent.bottom);
422			rExtent.top = __max( vYSum[i], rExtent.top);
423		}
424
425		break;
426	}
427
428	SetExtent(rExtent);
429}
430
431size_t CPGLBar::GetMinimumDataLength() const
432{
433	if (m_lSeries.empty())
434		return 0;
435
436	CPGLLine1DPtr pLine;
437	CPGLLine1DList::const_iterator il;
438
439	il = m_lSeries.begin();
440	pLine = *il;
441	ASSERT(pLine);
442	size_t nBars=pLine->GetValues()->size();
443	il++;
444	for (; il != m_lSeries.end(); ++il)
445	{
446		pLine = *il;
447		ASSERT(pLine);
448		nBars = __min( nBars, pLine->GetValues()->size());
449	}
450
451	return nBars;
452}
453
454
455void CPGLBar::PushLinesTop(CPGLLegendPtr pLegend)
456{
457	if (! pLegend)
458		return;
459
460	CPGLLine1DList::iterator il;
461	for (il = m_lSeries.begin(); il != m_lSeries.end(); ++il)
462	{
463		pLegend->PushTop( *il );
464	}
465}
466
467float CPGLBar::GetBarWidth(const gfxinterface::CGfxInterface& gfx, size_t nBars) const
468{
469	double dPixelWidth;
470
471	if (m_pX)
472	{
473		dPixelWidth = gfx.WorldToBBAbsx( GetExtent().GetWidth() );
474	}
475	else
476	{
477		dPixelWidth=gfx.GetBBClipWidth();
478	}
479
480	switch (m_eType)
481	{
482	case ETypeSideBySide:
483		return static_cast<float>(( dPixelWidth - (nBars-1)*m_dPixelInter ) / (m_lSeries.size()*nBars));
484	case ETypeStacked:
485		return static_cast<float>(( dPixelWidth - (nBars-1)*m_dPixelInter)/ (nBars));
486	default:
487		ASSERT(false);
488		return 0;
489	}
490}
491
492float CPGLBar::GetBarXStart(const gfxinterface::CGfxInterface& gfx, size_t nBars, double dBarWidthPixel) const
493{
494	double dPixelStart, dOffset;
495
496	if (m_pX)
497	{
498		dPixelStart = gfx.WorldToBBx( GetExtent().left );
499		dOffset = 0.5;
500	}
501	else
502	{
503		dPixelStart = gfx.GetBBClipLeft();
504		dOffset = 0;
505	}
506
507	switch (m_eType)
508	{
509	case ETypeSideBySide:
510		return static_cast<float>(dPixelStart - dBarWidthPixel*(1 + dOffset));
511	case ETypeStacked:
512		return static_cast<float>(dPixelStart - dBarWidthPixel*dOffset);
513	default:
514		ASSERT(false);
515		return 0;
516	}	
517}
518
519void CPGLBar::SetXPositions( CPGLDataPtr pXs)
520{	
521	m_pX = pXs; 
522	PostUpdateExtent();
523};
524
525void CPGLBar::PushFront( CPGLLine1DPtr pSerie )		
526{	
527	if (!pSerie)
528		return ;
529
530	pSerie->SetFilled(true); 
531	pSerie->SetOpen(false); 
532	m_lSeries.push_front( pSerie );
533};
534
535void CPGLBar::PushTail( CPGLLine1DPtr pSerie )
536{	
537	if (!pSerie)
538		return ;
539	pSerie->SetFilled(true); 
540	pSerie->SetOpen(false); 
541	m_lSeries.push_back( pSerie );
542};