/PGLCore/pglbar.cpp
C++ | 542 lines | 407 code | 89 blank | 46 comment | 56 complexity | 645998b68dfd0087445626fec9f08431 MD5 | raw file
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Microsoft Public License. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Microsoft Public License, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Microsoft Public License.
- *
- * You must not remove this notice, or any other, from this software.
- *
- * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
- * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
- * PARTICULAR PURPOSE.
- * ***************************************************************************/
-
-
- #include "stdafx.h"
- #include <pgl/core/PGLBar.h>
- #include <pgl/core/PGLDataVectors.h>
- #include <pgl/core/DataRegistry.h>
-
- PGL_IMPLEMENT_DYNCREATE(CPGLBar, CPGLObject);
-
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
-
- //! Save settings
- void CPGLBar::SerializeXML(CPGLArchive& ar)
- {
- static const TCHAR szTag[] = _T("CPGLBar");
- std::_tstring str;
- CString strPos; strPos.Format(_T("%u"),(DWORD)this);
- CPGLLine1DPtr pLine;
-
- markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup());
- if(ar.IsStoring())
- {
- xml.AddChildElem(szTag);
- xml.AddChildAttrib(_T("Name"),GetName());
- xml.IntoElem();
-
- /////////////////////////////////////////////////////////
- // Adding base class
- CPGLObject::SerializeXML(ar);
-
- xml.AddChildElemEx(_T("PixelInter"), m_dPixelInter);
-
- xml.AddChildElem(_T("Series"));
- xml.IntoElem();
- // savings lines
- CPGLLine1DList::iterator il;
- for (il= m_lSeries.begin(); il!= m_lSeries.end();il++)
- {
- pLine = *il;
- pLine->SerializeXML(ar);
- }
- xml.OutOfElem();
-
- xml.OutOfElem();
- }
- else
- {
- Clear();
-
- if (!xml.FindChildElem(szTag))
- return;
-
- xml.IntoElem();
- /////////////////////////////////////////////////////////
- // Adding base class
- CPGLObject::SerializeXML(ar);
-
- xml.FindGetChildData(_T("PixelInter"), m_dPixelInter);
-
- xml.ResetChildPos();
- if (xml.FindChildElem(_T("Series")))
- {
- xml.IntoElem();
- // saving position
- xml.SavePos(strPos);
- while (xml.FindChildElem(_T("CPGLLine1D")))
- {
- pLine = CPGLLine1DPtr(new CPGLLine1D);
-
- xml.RestorePos(strPos);
-
- pLine->SerializeXML(ar);
- PushFront(pLine);
-
- // saving position
- xml.SavePos(strPos);
- }
- xml.OutOfElem();
- }
-
- xml.OutOfElem();
- }
-
- }
-
-
- #ifdef _DEBUG
- void CPGLBar::Dump( CDumpContext& dc ) const
- {
- // call base class function first
- CPGLObject::Dump( dc );
-
- // now do the stuff for our specific class
- dc << _T("CPGLBar ID ") << GetID() << "\n";
- }
- void CPGLBar::AssertValid() const
- {
- // call inherited AssertValid first
- CPGLObject::AssertValid();
-
- // check members...
- }
- #endif
-
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
-
- CPGLBar::CPGLBar(EType eType)
- : m_eType(eType), m_dPixelInter(10)
- {
-
- }
-
- CPGLBar& CPGLBar::operator= (const CPGLBar& b)
- {
- if (&b != this)
- {
- Clear();
-
- if (b.m_pX)
- m_pX = CPGLDataPtr(b.m_pX->Clone());
-
- m_dPixelInter = b.m_dPixelInter;
-
- m_vXLabels = b.m_vXLabels;
-
- CPGLLine1DList::const_iterator il;
- CPGLLine1DPtr pLine1D;
- for (il = b.m_lSeries.begin(); il != b.m_lSeries.end(); ++il)
- {
- if (!*il)
- continue;
-
- pLine1D = boost::shared_polymorphic_cast<CPGLLine1D, CPGLNode>((*il)->MakeCopy() );
- m_lSeries.push_back(pLine1D);
- }
- }
- return *this;
- }
-
- CPGLBar::~CPGLBar()
- {
- Clear();
- }
-
- void CPGLBar::Clear()
- {
- m_lSeries.clear();
-
- m_pX.reset();
- }
-
- void CPGLBar::PlotGfx(gfxinterface::CGfxInterface& gfx)
- {
- if (!IsVisible())
- return;
- if (!IsInLayer(gfx.GetLayer()))
- return;
- if (m_lSeries.empty())
- return;
-
- size_t i;
- CPGLVectorF vX0,vY0,vWidth,vHeight;
- CPGLLine1DPtr pLine;
- CPGLLine1DList::iterator il;
- CPGLDataPtr pData;
-
- size_t nBars = GetMinimumDataLength();
- if (!nBars)
- return;
- vX0.resize(nBars);
- vY0.resize(nBars);
- vWidth.resize(nBars);
- vHeight.resize(nBars);
-
- // preparing vectors
- // computing bar with...
- float dBarWidthPx, dXStart, dWidth, dWidth1;
- il = m_lSeries.begin();
- pLine = *il;
- pData = pLine->GetValues();
- ASSERT(pData);
-
- dBarWidthPx = GetBarWidth(gfx, nBars);
-
- if (m_pX)
- {
- switch (m_eType)
- {
- case ETypeSideBySide:
- for (i = 0; i<nBars;++i)
- {
- vX0[i]=static_cast<float>(gfx.WorldToBBx( m_pX->at(i) ) - m_lSeries.size()/2.0*dBarWidthPx);
- }
- break;
- case ETypeStacked:
- // first run, get X positions
- for (i = 0; i<nBars;++i)
- {
- vX0[i]=static_cast<float>(gfx.WorldToBBx( m_pX->at(i) ));
- vY0[i]=static_cast<float>(gfx.WorldToBBy(0));
- }
- break;
- }
-
- // second run, get width...
- if (nBars == 1)
- {
- vWidth[0]=dBarWidthPx;
- }
- else
- {
- dWidth1=static_cast<float>((fabs(vX0[1] - vX0[0]) - m_dPixelInter)/2.0);
- vWidth[0] = static_cast<float>(__min( dBarWidthPx, dWidth1));
- vX0[0]-=static_cast<float>(vWidth[0]/2.0);
- for (i = 1; i<nBars-1;i++)
- {
- dWidth = dWidth1;
- dWidth1 = static_cast<float>((fabs(vX0[i+1] - vX0[i]) - m_dPixelInter)/2.0);
-
- vWidth[i]=static_cast<float>(__min( dBarWidthPx, __min( dWidth, dWidth1 )));
-
- // update vX
- vX0[i]-=static_cast<float>(vWidth[i]/2.0);
- }
- vWidth[nBars-1] = __min( dBarWidthPx, dWidth1);
- vX0[nBars-1]-=static_cast<float>(vWidth[nBars-1]/2.0);
- }
- }
- else // generating positions
- {
- dXStart = GetBarXStart(gfx, nBars, dBarWidthPx);
-
- switch (m_eType)
- {
- case ETypeSideBySide:
- vX0[0]=dXStart;
- vWidth[0]=dBarWidthPx;
- for (i = 1; i<nBars;++i)
- {
- vX0[i]=static_cast<float>(vX0[i-1]+m_lSeries.size()*dBarWidthPx + m_dPixelInter);
- vWidth[i]=dBarWidthPx;
- }
- break;
- case ETypeStacked:
- for (i = 0; i<nBars;++i)
- {
- vX0[i]=static_cast<float>(dXStart+i*(dBarWidthPx + m_dPixelInter));
- vY0[i]=static_cast<float>(gfx.WorldToBBy(0));
- vWidth[i]=dBarWidthPx;
- }
- break;
- }
- }
-
- // drawing...
- for (; il != m_lSeries.end(); il++)
- {
- pLine = *il;
- if (!pLine)
- continue;
-
- pData = pLine->GetValues();
- ASSERT(pData);
-
- // setting pen and brush
- pLine->SetExtent( GetExtent() );
- pLine->CPGLObject::PlotGfx( gfx );
-
- // update vY if stacked...
- // updating vX...
- switch(m_eType)
- {
- case ETypeSideBySide:
- for (i=0;i<nBars;++i)
- {
- vX0[i]+=dBarWidthPx;
- vHeight[i]=static_cast<float>(gfx.WorldToBBAbsy( pData->at(i) ));
- vY0[i]= static_cast<float>(gfx.WorldToBBy(0)+gfx.GetYDirectionUp()*vHeight[i]) ;
- }
- break;
- case ETypeStacked:
- for (i = 0; i<nBars;++i)
- {
- vHeight[i]=static_cast<float>(gfx.WorldToBBAbsy( pData->at(i) ));
- vY0[i] += static_cast<float>(gfx.GetYDirectionUp()*vHeight[i]);
- }
- break;
- }
-
- // drawing
- gfx.DrawRectStrip( vX0, vY0, vWidth, vHeight, pLine->GetERectType());
- }
- }
-
- void CPGLBar::GetUnionExtent(gfxinterface::CGfxInterface& gfx, CPGLRectD& rExtent)
- {
- CPGLObject::GetUnionExtent(gfx, rExtent);
-
- GetExtent().SetUnion(rExtent);
-
- if (m_pX)
- rExtent.xValid=true;
- else
- rExtent.xValid=false;
-
- if (m_lSeries.empty())
- rExtent.yValid=false;
- else
- rExtent.yValid=true;
- }
-
- void CPGLBar::UpdateExtent(gfxinterface::CGfxInterface& gfx)
- {
- using namespace std;
- // Calling base class function
- CPGLObject::UpdateExtent(gfx);
-
- if (m_lSeries.size()==0)
- return;
-
- CPGLRectD rExtent;
- CPGLLine1DPtr pLine;
- vector<float> vYSum;
- CPGLLine1DList::iterator il;
- double dMax, dMin;
- CPGLDataPtr pData;
- size_t uMin, uMax, n, i;
-
- if (m_pX)
- {
- m_pX->GetMinMaxIndex(uMin, uMax);
- rExtent.left = (*m_pX)[ uMin ];
- rExtent.right = (*m_pX)[ uMax ];
- }
- else
- {
- rExtent.left=0;
- rExtent.right=1;
- }
-
- switch(m_eType)
- {
- case ETypeSideBySide:
- il = m_lSeries.begin();
- pLine = *il;
-
- pData=pLine->GetValues();
- ASSERT(pData);
-
- rExtent.bottom = (*pData)[pData->GetMinIndex()];
- rExtent.top = (*pData)[pData->GetMaxIndex()];
-
- for (; il != m_lSeries.end(); ++il)
- {
- pLine = *il;
- if (!pLine)
- continue;
-
- pData=pLine->GetValues();
- ASSERT(pData);
-
- pData->GetMinMaxIndex(uMin, uMax);
- dMin = (*pData)[uMin];
- dMax = (*pData)[uMax];
- rExtent.bottom = __min( dMin, rExtent.bottom);
- rExtent.top = __max( dMax, rExtent.top);
- }
-
- rExtent.bottom=__min(0, rExtent.bottom);
- break;
- case ETypeStacked:
- n=GetMinimumDataLength();
- vYSum.resize(n);
-
- il = m_lSeries.begin();
- pLine = *il;
-
- pData=pLine->GetValues();
- ASSERT(pData);
- for (i=0;i<n;i++)
- vYSum[i] = (*pData)[i];
-
- il++;
- for (; il != m_lSeries.end(); ++il)
- {
- pLine = *il;
- if (!pLine)
- continue;
- pData=pLine->GetValues();
- ASSERT(pData);
-
- for (i=0;i<n;i++)
- vYSum[i] += (*pData)[i];
- }
-
- rExtent.bottom = rExtent.top = vYSum[0];
- rExtent.bottom = __min(rExtent.bottom, 0);
- for (i=1;i<n;i++)
- {
- rExtent.bottom = __min( vYSum[i], rExtent.bottom);
- rExtent.top = __max( vYSum[i], rExtent.top);
- }
-
- break;
- }
-
- SetExtent(rExtent);
- }
-
- size_t CPGLBar::GetMinimumDataLength() const
- {
- if (m_lSeries.empty())
- return 0;
-
- CPGLLine1DPtr pLine;
- CPGLLine1DList::const_iterator il;
-
- il = m_lSeries.begin();
- pLine = *il;
- ASSERT(pLine);
- size_t nBars=pLine->GetValues()->size();
- il++;
- for (; il != m_lSeries.end(); ++il)
- {
- pLine = *il;
- ASSERT(pLine);
- nBars = __min( nBars, pLine->GetValues()->size());
- }
-
- return nBars;
- }
-
-
- void CPGLBar::PushLinesTop(CPGLLegendPtr pLegend)
- {
- if (! pLegend)
- return;
-
- CPGLLine1DList::iterator il;
- for (il = m_lSeries.begin(); il != m_lSeries.end(); ++il)
- {
- pLegend->PushTop( *il );
- }
- }
-
- float CPGLBar::GetBarWidth(const gfxinterface::CGfxInterface& gfx, size_t nBars) const
- {
- double dPixelWidth;
-
- if (m_pX)
- {
- dPixelWidth = gfx.WorldToBBAbsx( GetExtent().GetWidth() );
- }
- else
- {
- dPixelWidth=gfx.GetBBClipWidth();
- }
-
- switch (m_eType)
- {
- case ETypeSideBySide:
- return static_cast<float>(( dPixelWidth - (nBars-1)*m_dPixelInter ) / (m_lSeries.size()*nBars));
- case ETypeStacked:
- return static_cast<float>(( dPixelWidth - (nBars-1)*m_dPixelInter)/ (nBars));
- default:
- ASSERT(false);
- return 0;
- }
- }
-
- float CPGLBar::GetBarXStart(const gfxinterface::CGfxInterface& gfx, size_t nBars, double dBarWidthPixel) const
- {
- double dPixelStart, dOffset;
-
- if (m_pX)
- {
- dPixelStart = gfx.WorldToBBx( GetExtent().left );
- dOffset = 0.5;
- }
- else
- {
- dPixelStart = gfx.GetBBClipLeft();
- dOffset = 0;
- }
-
- switch (m_eType)
- {
- case ETypeSideBySide:
- return static_cast<float>(dPixelStart - dBarWidthPixel*(1 + dOffset));
- case ETypeStacked:
- return static_cast<float>(dPixelStart - dBarWidthPixel*dOffset);
- default:
- ASSERT(false);
- return 0;
- }
- }
-
- void CPGLBar::SetXPositions( CPGLDataPtr pXs)
- {
- m_pX = pXs;
- PostUpdateExtent();
- };
-
- void CPGLBar::PushFront( CPGLLine1DPtr pSerie )
- {
- if (!pSerie)
- return ;
-
- pSerie->SetFilled(true);
- pSerie->SetOpen(false);
- m_lSeries.push_front( pSerie );
- };
-
- void CPGLBar::PushTail( CPGLLine1DPtr pSerie )
- {
- if (!pSerie)
- return ;
- pSerie->SetFilled(true);
- pSerie->SetOpen(false);
- m_lSeries.push_back( pSerie );
- };