diff options
author | Pixel <pixel@nobis-crew.org> | 2009-11-04 11:56:41 -0800 |
---|---|---|
committer | Pixel <pixel@nobis-crew.org> | 2009-11-04 11:59:33 -0800 |
commit | d577d991b97ae2b5ee1af23641bcffc3f83af5b2 (patch) | |
tree | 590639d50205d1bcfaff2a7d2dc6ebf3f373c7ed /iup/srcpplot/iupPPlot.cpp |
Initial import. Contains the im, cd and iup librairies, and a "working" Makefile for them under linux.
Diffstat (limited to 'iup/srcpplot/iupPPlot.cpp')
-rwxr-xr-x | iup/srcpplot/iupPPlot.cpp | 2470 |
1 files changed, 2470 insertions, 0 deletions
diff --git a/iup/srcpplot/iupPPlot.cpp b/iup/srcpplot/iupPPlot.cpp new file mode 100755 index 0000000..c0d07c9 --- /dev/null +++ b/iup/srcpplot/iupPPlot.cpp @@ -0,0 +1,2470 @@ +/*************************************************************************** + * * + * Copyright notice: * + * * + * This is free Pier ware. You may do whatever you want with this code, * + * except that you should not remove this copyright notice. * + * * + ***************************************************************************/ + +#ifdef _MSC_VER +#pragma warning(disable: 4100) +#pragma warning(disable: 4512) +#endif + +#include <stdio.h> +#include <math.h> +#include <assert.h> + +#include "iupPPlot.h" + +const float kFloatSmall = 1e-20f; +const float kLogMin = 1e-10f;// min argument for log10 function +const float kExpMax = 1e10f;// max argument for pow10 function +const float kLogMinClipValue = 1e-10f;// pragmatism to avoid problems with small values in log plot +const float kEps = 1e-4f; +const float kRelMajorTickSize = 0.02f; +const float kRelMinorTickSize = 0.01f; +const int kMinMinorTickScreenSize = 1;// minor ticks should not become smaller than this +const float kMaxMajorTickSizeInFontHeight = 0.5f;// not larger than half the font height +const float kLittleIncrease = 1.0001f; +const float kLittleDecrease = 0.9999f; +const float kTickValueVeryBig = 1.0e4;// switch to scientific format +const float kTickValueVerySmall = (float)1.0e-3; +const float kMajorTickXInitialFac = 2.0f; +const float kMajorTickYInitialFac = 3.0f; +const PMargins kDefaultMargins = PMargins (40,20,5,42); + +const float PPlot::kRangeVerySmall = (float)1.0e-3; // also in ZoomInteraction + +template <class T> const T & PMax (const T &a, const T &b) { + return b> a ? b: a; +} + +inline float SafeLog (float inFloat, float inBase, float inFac) { + if (inFloat<kLogMin) { + inFloat = kLogMin; + } + return inFac*log10 (inFloat)/log10(inBase); +} + +inline float SafeExp (float inFloat, float inBase, float inFac) { + if (inFloat>kExpMax) { + inFloat = kExpMax; + } + return pow(inBase, inFloat/inFac); +} + +long PlotDataBase::GetSize () const { + if (GetRealPlotData ()) { + return GetRealPlotData ()->size (); + } + if (GetCalculatedData ()) { + return GetCalculatedData ()->GetSize (); + } + return 0; +} + +float PlotDataBase::GetValue (long inIndex) const { + if (GetRealPlotData ()) { + return (*GetRealPlotData ())[inIndex]; + } + if (GetCalculatedData ()) { + return GetCalculatedData ()->GetValue (inIndex); + } + return 0; +} + +bool PlotDataBase::CalculateRange (float &outXMin, float &outXMax) { + const RealData *theData = GetRealPlotData (); + if (theData && theData->size () >0) { + vector<float>::const_iterator imin = min_element (theData->begin (), theData->end ()); + vector<float>::const_iterator imax = max_element (theData->begin (), theData->end ()); + outXMin = *imin; + outXMax = *imax; + return true; + } + else { + const CalculatedDataBase *theCalculated = GetCalculatedData (); + if (theCalculated) { + outXMin = theCalculated->GetValue (0); + outXMax = theCalculated->GetValue (theCalculated->GetSize () - 1); + return true; + } + } + + return false; +} + +DummyPlotData::DummyPlotData (long inSize) { + for (int theI=0;theI<inSize;theI++) { + mRealPlotData.push_back (theI);// simple ascending data + } +} + +void StringPlotData::AddItem (const char *inString) { + mStringPlotData.push_back (inString); + mRealPlotData.push_back (mStringPlotData.size ()-1); +} + +void StringPlotData::InsertItem (int inIndex, const char *inString) { + mStringPlotData.insert(mStringPlotData.begin()+inIndex, inString); + mRealPlotData.insert(mRealPlotData.begin()+inIndex, (float)inIndex); +} + + +void LegendData::SetDefaultColor (int inPlotIndex) { + mColor = GetDefaultColor (inPlotIndex); +} + +void LegendData::SetDefaultValues (int inPlotIndex) { + SetDefaultColor (inPlotIndex); + char theBuf[32]; + sprintf (theBuf, "plot %d", inPlotIndex); + mName = theBuf; +} + + +bool PlotDataSelection::IsSelected (long inIndex) const { + if (size ()<=inIndex) { + return false; + } + return (*this)[inIndex]>0; +} + +long PlotDataSelection::GetSelectedCount () const { + long theCount = 0; + for (int theI=0;theI<size (); theI++) { + if (IsSelected (theI)) { + theCount++; + } + } + return theCount; +} + +int PPlot::Round (float inFloat) { +#ifdef _IUP_PPLOT_ + return ((int)(inFloat < 0? (inFloat-0.5f): (inFloat+0.5f))); +#else + return (int)floor (inFloat+0.5f); +#endif +} + +PColor LegendData::GetDefaultColor (int inPlotIndex) { + + PColor theC; + switch (inPlotIndex%7) { + case 0: + theC.mR = 255; + theC.mG = 0; + theC.mB = 0; + break; + case 1: + theC.mR = 0; + theC.mG = 0; + theC.mB = 255; + break; + case 2: + theC.mR = 0; + theC.mG = 255; + theC.mB = 0; + break; + case 3: + theC.mR = 0; + theC.mG = 255; + theC.mB = 255; + break; + case 4: + theC.mR = 255; + theC.mG = 0; + theC.mB = 255; + break; + case 5: + theC.mR = 255; + theC.mG = 255; + theC.mB = 0; + break; + default: + // black + break; + } + return theC; +} + + + +float TickInfo::RoundSpan (float inSpan) { + // round it to something producing readable tick labels + // write it in the form inSpan = a*SafeExp10 (b) + + if (inSpan<=0) { + // error + return (float)-1.234567; + } + + int thePow = 0; + float theSpan = inSpan; + if (inSpan>1) { + while (theSpan>10) { + theSpan/=10; + if (theSpan == inSpan) { // not a number + return (float)-1.234567; + } + thePow++; + } + } + else { + while (theSpan<1) { + theSpan*=10; + thePow--; + } + } + int theRoundedFirstDigit = PPlot::Round (theSpan); + int thePreferredFirstDigit = 1; + switch (theRoundedFirstDigit) { + case 1: + thePreferredFirstDigit = 1; + break; + case 2: + case 3: + case 4: + thePreferredFirstDigit = 2; + break; + case 5: + case 6: + case 7: + case 8: + case 9: + thePreferredFirstDigit = 5; + break; + case 10: + thePreferredFirstDigit = 1; + thePow++; + break; + default: + // error + return (float)-1.234567; + break; + } + float theRes = thePreferredFirstDigit*pow (10., thePow); /* M.T. changed to force a double cast */ + return theRes; +} + +void TickInfo::MakeFormatString (float inValue, string &outFormatString) { + if (inValue<0) { + inValue = - inValue; + } + if (inValue > kTickValueVeryBig || inValue < kTickValueVerySmall) { + outFormatString = "%.1e"; + } + else { + + int thePrecision = 0; + if (inValue<1) { + float theSpan = inValue; + while (theSpan<1) { + thePrecision++; + theSpan *=10; + } + } + + char theBuf[128] = "%.0f"; + theBuf[2] = '0'+thePrecision; + + outFormatString = theBuf; + } +} + + +PlotDataBase::~PlotDataBase (){ +}; + + +PlotDataContainer::PlotDataContainer (){ +} +PlotDataContainer::~PlotDataContainer (){ + ClearData (); +} + +PlotDataBase * PlotDataContainer::GetXData (int inIndex) { + if (inIndex < 0 || inIndex >= mXDataList.size ()) { + return 0; + } + return mXDataList[inIndex]; +} + +PlotDataBase * PlotDataContainer::GetYData (int inIndex) { + if (inIndex < 0 || inIndex >= mYDataList.size ()) { + return 0; + } + return mYDataList[inIndex]; +} + +LegendData * PlotDataContainer::GetLegendData (int inIndex) { + if (inIndex < 0 || inIndex >= mLegendDataList.size ()) { + return 0; + } + return mLegendDataList[inIndex]; +} + +DataDrawerBase * PlotDataContainer::GetDataDrawer (int inIndex) { + if (inIndex < 0 || inIndex >= mDataDrawerList.size ()) { + return 0; + } + return mDataDrawerList[inIndex]; +} + +PlotDataSelection * PlotDataContainer::GetPlotDataSelection (int inIndex) { + if (inIndex < 0 || inIndex >= mPlotDataSelectionList.size ()) { + return 0; + } + return mPlotDataSelectionList[inIndex]; +} + +const PlotDataBase * PlotDataContainer::GetConstXData (int inIndex) const { + if (inIndex < 0 || inIndex >= mXDataList.size ()) { + return 0; + } + return mXDataList[inIndex]; +} + +const PlotDataBase * PlotDataContainer::GetConstYData (int inIndex) const { + if (inIndex < 0 || inIndex >= mYDataList.size ()) { + return 0; + } + return mYDataList[inIndex]; +} + +const LegendData * PlotDataContainer::GetConstLegendData (int inIndex) const { + if (inIndex < 0 || inIndex >= mLegendDataList.size ()) { + return 0; + } + return mLegendDataList[inIndex]; +} + +const DataDrawerBase * PlotDataContainer::GetConstDataDrawer (int inIndex) const { + if (inIndex < 0 || inIndex >= mDataDrawerList.size ()) { + return 0; + } + return mDataDrawerList[inIndex]; +} + +const PlotDataSelection * PlotDataContainer::GetConstPlotDataSelection (int inIndex) const { + if (inIndex < 0 || inIndex >= mPlotDataSelectionList.size ()) { + return 0; + } + return mPlotDataSelectionList[inIndex]; +} + +void PlotDataContainer::RemoveElement (int inIndex) { + if (!(inIndex < mXDataList.size () && inIndex < mYDataList.size () && + inIndex < mLegendDataList.size () && inIndex < mDataDrawerList.size ())) { + // Invalid index + return; + } + + PlotDataList::iterator theXI = mXDataList.begin () + inIndex; + PlotDataList::iterator theYI = mYDataList.begin () + inIndex; + LegendDataList::iterator theLI = mLegendDataList.begin () + inIndex; + DataDrawerList::iterator theDI = mDataDrawerList.begin () + inIndex; + PlotDataSelectionList::iterator thePI = mPlotDataSelectionList.begin () + inIndex; + + delete *theXI; + delete *theYI; + delete *theLI; + delete *theDI; + delete *thePI; + + mXDataList.erase (theXI); + mYDataList.erase (theYI); + mLegendDataList.erase (theLI); + mDataDrawerList.erase (theDI); + mPlotDataSelectionList.erase (thePI); +} + +void PlotDataContainer::ClearData () { + PlotDataList::iterator theXI = mXDataList.begin (); + PlotDataList::iterator theYI = mYDataList.begin (); + LegendDataList::iterator theLI = mLegendDataList.begin (); + DataDrawerList::iterator theDI = mDataDrawerList.begin (); + PlotDataSelectionList::iterator thePI = mPlotDataSelectionList.begin (); + + for (;theXI!=mXDataList.end () && theYI!=mYDataList.end () && theLI!=mLegendDataList.end () && theDI != mDataDrawerList.end () && thePI != mPlotDataSelectionList.end ();) { + PlotDataBase *theX = *theXI; + PlotDataBase *theY = *theYI; + LegendData *theL = *theLI; + DataDrawerBase *theD = *theDI; + PlotDataSelection *theP = *thePI; + + delete theX; + delete theY; + delete theL; + delete theD; + delete theP; + + theXI++; + theYI++; + theLI++; + theDI++; + thePI++; + } + mXDataList.clear (); + mYDataList.clear (); + mLegendDataList.clear (); + mDataDrawerList.clear (); + mPlotDataSelectionList.clear (); +} + +/* M.T. - changed to return the index of the added plot; returns -1 on error */ +int PlotDataContainer::AddXYPlot (PlotDataBase *inXData, PlotDataBase *inYData, LegendData *inLegendData, DataDrawerBase *inDataDrawer, PlotDataSelection *inPlotDataSelection) { + if (!inYData || (!inYData->GetRealPlotData () && !inYData->GetCalculatedData ())) { + return -1; + } + PlotDataBase *theXData = inXData; + if (!theXData) { + theXData = new DummyPlotData (inYData->GetSize ()); + } + mXDataList.push_back (theXData); + mYDataList.push_back (inYData); + + LegendData *theLegendData = inLegendData; + if (!theLegendData) { + theLegendData = new LegendData (); + theLegendData->SetDefaultValues (mLegendDataList.size ()); + } + mLegendDataList.push_back (theLegendData); + + DataDrawerBase *theDataDrawer = inDataDrawer; + if (!theDataDrawer) { + theDataDrawer = new LineDataDrawer (); + } + mDataDrawerList.push_back (theDataDrawer); + + PlotDataSelection *thePlotDataSelection = inPlotDataSelection; + if (!thePlotDataSelection) { + thePlotDataSelection = new PlotDataSelection (); + } + else { + thePlotDataSelection->resize (inYData->GetSize ()); + } + mPlotDataSelectionList.push_back (thePlotDataSelection); + return ( mYDataList.size() - 1 ); +} + +void PlotDataContainer::SetXYPlot (int inIndex, PlotDataBase *inXData, PlotDataBase *inYData, LegendData *inLegendData, DataDrawerBase *inDataDrawer, PlotDataSelection *inPlotDataSelection) { + if (!inYData || !inYData->GetRealPlotData ()) { + return; + } + if (!CheckState ()) { + return; + } + long thePlotCount = GetPlotCount (); + if (inIndex<0||inIndex>thePlotCount) { + return; + } + PlotDataBase *theXData = inXData; + + if (!theXData) { + theXData = new DummyPlotData (inYData->GetRealPlotData ()->size ()); + } + LegendData *theLegendData = inLegendData; + DataDrawerBase *theDataDrawer = inDataDrawer; + if (!theLegendData) { + theLegendData = new LegendData (); + if (inIndex >= 0 && inIndex < mYDataList.size () ) { + *theLegendData = *mLegendDataList[inIndex]; // copy old values... + } else { + theLegendData->SetDefaultValues (mLegendDataList.size ()); + } + } + if (!theDataDrawer) { + theDataDrawer = new LineDataDrawer (); + } + PlotDataSelection *thePlotDataSelection = inPlotDataSelection; + if (!thePlotDataSelection) { + thePlotDataSelection = new PlotDataSelection (inYData->GetSize ()); + // thePlotDataSelection = new PlotDataSelection (); + } + if (inIndex >= 0 && inIndex < mYDataList.size () ) { + delete mXDataList[inIndex]; + delete mYDataList[inIndex]; + delete mLegendDataList[inIndex]; + delete mDataDrawerList[inIndex]; + delete mPlotDataSelectionList[inIndex]; + + mXDataList[inIndex] = theXData; + mYDataList[inIndex] = inYData; + mLegendDataList[inIndex] = theLegendData; + mDataDrawerList[inIndex] = theDataDrawer; + mPlotDataSelectionList[inIndex] = thePlotDataSelection; + } else { // add at end + mXDataList.push_back (theXData); + mYDataList.push_back (inYData); + mLegendDataList.push_back (theLegendData); + mDataDrawerList.push_back (theDataDrawer); + mPlotDataSelectionList.push_back (thePlotDataSelection); + } +} + +bool PlotDataContainer::SetDataDrawer (int inIndex, DataDrawerBase* inDataDrawer) { + if (inIndex < 0 || inIndex >= mYDataList.size () ) { + return false; + } + DataDrawerBase* theDataDrawer = inDataDrawer; + if (!inDataDrawer) { + theDataDrawer = new LineDataDrawer; + } + delete mDataDrawerList[inIndex]; + mDataDrawerList[inIndex] = theDataDrawer; + return true; +} + +int PlotDataContainer::GetPlotIndexByName (const string &inName) const { + + if (CheckState ()) { + for (int theI=0;theI<mLegendDataList.size ();theI++) { + LegendData *theLegendData = mLegendDataList[theI]; + if (theLegendData->mName == inName) { + return theI; + } + } + } + return -1; +} + + +bool PlotDataContainer::CalculateXRange (float &outXMin, float &outXMax) const { + bool theFirst = true; + outXMin = 0; + outXMax = 0; + for (PlotDataList::const_iterator theI=mXDataList.begin();theI!=mXDataList.end ();theI++) { + PlotDataBase *theXDataBase = *theI; + if (!theXDataBase) { + return false; + } + if (theXDataBase->GetSize () == 0) { + continue; + } + float theXMin; + float theXMax; + if (!theXDataBase->CalculateRange (theXMin, theXMax)) { + return false; + } + if (theXMax < theXMin) { + return false; + } + if (theFirst) { + outXMin = theXMin; + outXMax = theXMax; + theFirst = false; + } + if (theXMax>outXMax) { + outXMax = theXMax; + } + if (theXMin<outXMin) { + outXMin = theXMin; + } + } + if (outXMin == 0 && outXMax == 0) { + return false; + } + return true; +} + +bool PlotDataContainer::CalculateYRange (float inXMin, float inXMax, float &outYMin, float &outYMax) const { + outYMin = 0; + outYMax = 0; + bool theFirst = true; + + for (int theI=0; theI<GetPlotCount (); theI++) { + const PlotDataBase *theXDataBase = GetConstXData (theI); + const PlotDataBase *theYDataBase = GetConstYData (theI); + if (!theXDataBase || !theYDataBase) { + return false; + } + float theYMin; + float theYMax; + if (!CalculateYRangePlot (inXMin, inXMax, *theXDataBase, *theYDataBase, theYMin,theYMax)) { + return false; + } + if (theFirst) { + outYMin = theYMin; + outYMax = theYMax; + theFirst = false; + } + if (theYMin<outYMin) { + outYMin = theYMin; + } + if (theYMax>outYMax) { + outYMax = theYMax; + } + + } + return true; +} + +bool PlotDataContainer::CalculateYRangePlot (float inXMin, float inXMax, const PlotDataBase &inXData, const PlotDataBase &inYData, float &outYMin, float &outYMax) const { + outYMin = 0; + outYMax = 0; + bool initialized = false; + + if (inXData.GetSize () != inYData.GetSize ()) { + return false; + } + + for (long theI = 0; theI < inXData.GetSize (); theI++) { + float theX = inXData.GetValue (theI); + float theY = inYData.GetValue (theI); + + if (theX>=inXMin && theX <= inXMax) { + if (!initialized) { + initialized = true; + outYMin = theY; + outYMax = theY; + } else { + if (theY<outYMin) { + outYMin = theY; + } + if (theY>outYMax) { + outYMax = theY; + } + } + } + } + return true; +} + +bool PlotDataContainer::CheckState () const { + long theSize1 = mXDataList.size (); + long theSize2 = mYDataList.size (); + long theSize3 = mLegendDataList.size (); + long theSize4 = mDataDrawerList.size (); + long theSize5 = mPlotDataSelectionList.size (); + if (theSize1!=theSize2 || theSize1!=theSize3 || theSize1!=theSize4 || theSize1!=theSize5) { + return false; + } + return true; +} + +float LinTrafo::Transform (float inValue) const { + return inValue * mSlope + mOffset; +} +float LinTrafo::TransformBack (float inValue) const { + if (mSlope != 0) { + return (inValue - mOffset) / mSlope; + } else { + return 0; + } +} + + +float LogTrafo::Transform (float inValue) const{ + if (inValue<kLogMinClipValue) { + inValue = kLogMinClipValue; + } + return SafeLog (inValue, mBase, mFactor)*mSlope+mOffset; +} +float LogTrafo::TransformBack (float inValue) const { + if (mSlope != 0) { + return SafeExp( (inValue - mOffset)/mSlope, mBase, mFactor); + } else { + return 0; + } +} + + +bool LinTickIterator::Init () { + if (!mAxisSetup) { + return false; + } + + float theMin = mAxisSetup->mMin; + float theMajorTickSpan = mAxisSetup->mTickInfo.mMajorTickSpan; + int theDiv = mAxisSetup->mTickInfo.mTickDivision; + mDelta = theMajorTickSpan/theDiv; + mCount = ceil (theMin/mDelta); + mCurrentTick = mCount*mDelta; + + mFormatString = mAxisSetup->mTickInfo.mFormatString; + + return true; + +} + +bool LinTickIterator::GetNextTick (float &outTick, bool &outIsMajorTick, string &outFormatString) { + if (!mAxisSetup) { + return false; + } + if (mCurrentTick>mAxisSetup->mMax*kLittleIncrease) { + return false; + } + outTick = mCurrentTick; + outIsMajorTick = (mCount%mAxisSetup->mTickInfo.mTickDivision == 0); + outFormatString = mFormatString; + + mCurrentTick += mDelta; + mCount++; + return true; +} + +bool LinTickIterator::InitFromRanges (float inParRange, float inOrthoScreenRange, float inDivGuess, TickInfo &ioTickInfo) const { + if (inDivGuess <= kFloatSmall) { + return false; + } + float thePreferredSpan = TickInfo::RoundSpan (inParRange/inDivGuess); + if (thePreferredSpan < 0) { + return false; + } + + float thePreferredNrOfTicks = inParRange/thePreferredSpan; + if (thePreferredNrOfTicks <1) { + ioTickInfo.mMajorTickSpan = inParRange; + } + else { + ioTickInfo.mMajorTickSpan = thePreferredSpan; + } + + ioTickInfo.mTickDivision = 5; + if (ioTickInfo.mAutoTickSize) { + ioTickInfo.mMinorTickScreenSize = PMax (kMinMinorTickScreenSize, PPlot::Round (inOrthoScreenRange*kRelMinorTickSize)); + ioTickInfo.mMajorTickScreenSize = PMax (ioTickInfo.mMinorTickScreenSize+1, PPlot::Round (inOrthoScreenRange*kRelMajorTickSize)); + } + + TickInfo::MakeFormatString (ioTickInfo.mMajorTickSpan, ioTickInfo.mFormatString); + return true; +} + +bool LogTickIterator::Init () { + if (!mAxisSetup) { + return false; + } + + float theMin = mAxisSetup->mMin; + // float theMax = mAxisSetup->mMax; + float theMajorTickSpan = mAxisSetup->mTickInfo.mMajorTickSpan; + int theDiv = mAxisSetup->mTickInfo.mTickDivision; + mDelta = theMajorTickSpan/theDiv; + float theBase = mAxisSetup->mLogBase; + long theLogFac = 1;//mAxisSetup->mLogFactor; + long thePowMin = (long)floor(SafeLog(theMin, theBase, theLogFac)); + mCurrentTick = SafeExp (thePowMin, theBase, theLogFac); + mCount = 0; + + // walk to the first tick + + if (theMin<=0) { + return false; + // error + } + else { + // walk forward + float theNext = mCurrentTick+mDelta*SafeExp (thePowMin, theBase, theLogFac); + while (theNext<=theMin*kLittleDecrease) { + mCurrentTick = theNext; + theNext += mDelta*SafeExp (thePowMin,theBase, theLogFac); + mCount++; + } + } + return true; +} + +bool LogTickIterator::InitFromRanges (float inParRange, float inOrthoScreenRange, float inDivGuess, TickInfo &ioTickInfo) const { + if (inDivGuess<=kFloatSmall) { + return false; + } + /* + float thePreferredSpan = TickInfo::RoundSpan (inParRange/inDivGuess); + float thePreferredNrOfTicks = inParRange/thePreferredSpan; + if (thePreferredNrOfTicks <1) { + ioTickInfo.mMajorTickSpan = inParRange; + } + else { + ioTickInfo.mMajorTickSpan = thePreferredSpan; + } + */ + float theBase = mAxisSetup->mLogBase; + ioTickInfo.mMajorTickSpan = theBase-1;// relative + + ioTickInfo.mTickDivision = PPlot::Round (ioTickInfo.mMajorTickSpan); + ioTickInfo.mMinorTickScreenSize = PMax (kMinMinorTickScreenSize, PPlot::Round (inOrthoScreenRange*kRelMinorTickSize)); + ioTickInfo.mMajorTickScreenSize = PMax (ioTickInfo.mMinorTickScreenSize+1, PPlot::Round (inOrthoScreenRange*kRelMajorTickSize)); + + ioTickInfo.mFormatString = "%.1e"; + return true; +} + +bool LogTickIterator::GetNextTick (float &outTick, bool &outIsMajorTick, string &outFormatString) { + if (!mAxisSetup) { + return false; + } + if (mCurrentTick>mAxisSetup->mMax*kLittleIncrease) { + return false; + } + outTick = mCurrentTick; + outIsMajorTick = (mCount%mAxisSetup->mTickInfo.mTickDivision == 0); + TickInfo::MakeFormatString (outTick, outFormatString); + float theBase = mAxisSetup->mLogBase; + float theLogFac = 1;//mAxisSetup->mLogFactor; + float theLogNow = SafeLog(mCurrentTick, theBase, theLogFac); + int thePowNow = (int)floor(theLogNow); + outIsMajorTick = false; + if (fabs (theLogNow-thePowNow)<kEps) { + outIsMajorTick = true; + } + + if (mAxisSetup->mLogFactor>1) { + char theBuf[128]; + sprintf (theBuf, "%d", thePowNow*20); + outFormatString = theBuf; + } + + mCurrentTick += mDelta*SafeExp (thePowNow, theBase, theLogFac); + mCount++; + + return true; +} + +bool LogTickIterator::AdjustRange (float &ioMin, float &ioMax) const { + + float theBase = mAxisSetup->mLogBase; + long theLogFac = 1;//mAxisSetup->mLogFactor; + if (mAxisSetup->mMaxDecades > 0) { + ioMin = ioMax/SafeExp (mAxisSetup->mMaxDecades, theBase, theLogFac); + } + if (ioMin == 0 && ioMax == 0) { + ioMin = kLogMinClipValue; + ioMax = 1.0f; + } + if (ioMin <= 0 || ioMax<=0) { + return false; + } + ioMin = RoundDown (ioMin*kLittleIncrease); + ioMax = RoundUp (ioMax*kLittleDecrease); + + if (ioMin<kLogMinClipValue) { + ioMin = kLogMinClipValue; + } + if (mAxisSetup->mMaxDecades > 0) { + ioMin = ioMax/SafeExp (mAxisSetup->mMaxDecades, theBase, theLogFac); + } + return true; +} + +float LogTickIterator::RoundUp (float inFloat) const { + float theBase = mAxisSetup->mLogBase; + float theLogFac = 1;//mAxisSetup->mLogFactor; + int thePow = (int)ceil(SafeLog(inFloat, theBase, theLogFac)); + return pow (theBase, thePow); +} + +float LogTickIterator::RoundDown (float inFloat) const { + float theBase = mAxisSetup->mLogBase; + long theLogFac = 1;//mAxisSetup->mLogFactor; + int thePow = (int)floor(SafeLog(inFloat,theBase, theLogFac)); + return pow (theBase, thePow); +} + +bool NamedTickIterator::GetNextTick (float &outTick, bool &outIsMajorTick, string &outFormatString) { + if (LinTickIterator::GetNextTick (outTick, outIsMajorTick, outFormatString)) { + int theIndex = PPlot::Round (outTick); + + // TO DO: improve this + if (fabs(outTick - (float)theIndex) > 0.1 ) { + outFormatString = ""; + return true; + } + + if (theIndex>=0 && theIndex < (int)mStringList.size ()) { + outFormatString = mStringList[theIndex]; + return true; + } + } + return false; +} + +bool NamedTickIterator::InitFromRanges (float inParRange, float inOrthoScreenRange, float inDivGuess, TickInfo &outTickInfo) const { + if (LinTickIterator::InitFromRanges (inParRange, inOrthoScreenRange, inDivGuess, outTickInfo)) { + outTickInfo.mTickDivision = 1; + return true; + } + return false; +} + +bool PainterTester::Draw (Painter &inPainter) { + + const char * theString = "The quick brown fox..."; + int theWidth = inPainter.CalculateTextDrawSize (theString); + int theOffset = theWidth/10; + + // a horizontal lines + int theHAscent_x = theOffset+2*inPainter.GetFontHeight (); + int theHAscent_y = 10; + int theHAscent_w = theWidth; + inPainter.DrawLine (theHAscent_x, theHAscent_y, theHAscent_x+theHAscent_w, theHAscent_y); + + int theHDescent_x = theHAscent_x; + int theHDescent_y = theHAscent_y+inPainter.GetFontHeight (); + int theHDescent_w = theHAscent_w; + inPainter.DrawLine (theHDescent_x, theHDescent_y, theHDescent_x+theHDescent_w, theHDescent_y); + + // a vertical lines + int theVAscent_x = theOffset; + int theVAscent_y = theHAscent_y+theWidth; + int theVAscent_h = -theWidth; + inPainter.DrawLine (theVAscent_x, theVAscent_y, theVAscent_x, theVAscent_y+theVAscent_h); + + int theVDescent_x = theVAscent_x+inPainter.GetFontHeight (); + int theVDescent_y = theVAscent_y; + int theVDescent_h = theVAscent_h; + inPainter.DrawLine (theVDescent_x, theVDescent_y, theVDescent_x, theVDescent_y+theVDescent_h); + + // Draw vertical text, followed by horizontal. +#ifdef _IUP_PPLOT_ /* M.T. - the alignment of the text is simply requested */ + inPainter.DrawRotatedText (theVDescent_x, theVDescent_y, -90, PPLOT_NORTH_WEST, theString); + inPainter.DrawText (theHDescent_x, theHDescent_y, PPLOT_NORTH_WEST, theString); +#else + inPainter.DrawRotatedText (theVDescent_x, theVDescent_y, -90, theString); + inPainter.DrawText (theHDescent_x, theHDescent_y, theString); +#endif + + return true; +} + +PPlot::PPlot (): + mShowLegend(true), // M.T. - show|hide legend + mLegendPos(PPLOT_TOPRIGHT), + mXTrafo (&mXLinTrafo), + mYTrafo (&mYLinTrafo), + mXTickIterator (&mXLinTickIterator), + mYTickIterator (&mYLinTickIterator), + mPPlotDrawer (0), + mOwnsPPlotDrawer (true), + mHasAnyModifyingCalculatorBeenActive (false) +{ + mMargins = kDefaultMargins; + mYAxisSetup.mAscending = false; +} + +PPlot::~PPlot () { + if (mOwnsPPlotDrawer) { + delete mPPlotDrawer; + } + mPPlotDrawer = 0; +} + +bool PPlot::Draw (Painter &inPainter) { + PRect theRect; + theRect.mX = mMargins.mLeft; + theRect.mY = mMargins.mTop; + theRect.mW = inPainter.GetWidth () - mMargins.mLeft - mMargins.mRight; + theRect.mH = inPainter.GetHeight () - mMargins.mTop - mMargins.mBottom; + + if (mPPlotDrawer) { + mPPlotDrawer->Prepare (inPainter, *this); + return mPPlotDrawer->Draw (inPainter); + } + if (!mPlotDataContainer.GetPlotCount ()) { + return true; + } + + if (!ConfigureSelf ()) { + return false; + } + bool theShouldRepeat = true; + long theRepeatCount = 0; + + while (theShouldRepeat && theRepeatCount<2) { + theRepeatCount++; + + if (!ValidateData ()) { + return false; + } + + if (!CalculateAxisRanges ()) { + return false; + } + + if (!this->CheckRange (mXAxisSetup)) { + return false; + } + + if (!this->CheckRange (mYAxisSetup)) { + return false; + } + + if (!CalculateTickInfo (theRect, inPainter)) { + return false; + } + + if (!CalculateXTransformation (theRect)) { + return false; + } + + if (!CalculateYTransformation (theRect)) { + return false; + } + if (theRepeatCount>1) { + break; + } + // hooks for some final calculations + bool theShouldRepeat = false; + for (PCalculator::tList::iterator theModifyingC=mModifyingCalculatorList.begin ();theModifyingC!=mModifyingCalculatorList.end();theModifyingC++) { + PCalculator *theModifyingCalculator = *theModifyingC; + if (theModifyingCalculator->ShouldCalculate ()) { + theShouldRepeat = true; + theModifyingCalculator->Calculate (inPainter, *this); + mHasAnyModifyingCalculatorBeenActive = true; + } + } +// theShouldRepeat = mModifyingCalculatorList.size ()>0; + } + + // hooks for some final calculations + for (PCalculator::tList::iterator thePostC=mPostCalculatorList.begin ();thePostC!=mPostCalculatorList.end();thePostC++) { + PCalculator *thePostCalculator = *thePostC; + thePostCalculator->Calculate (inPainter, *this); + } + + for (PDrawer::tList::iterator thePre1=mPreDrawerList.begin();thePre1!=mPreDrawerList.end ();thePre1++) { + PDrawer *thePreDrawer = *thePre1; + thePreDrawer->Prepare (inPainter, *this); + } + + // Drawing ! + + inPainter.SetLineColor (0,0,0); + inPainter.SetClipRect (0, 0, inPainter.GetWidth (), inPainter.GetHeight ()); + + // draw entire background, including the margins (for scrolling...) + PRect fullRect; + fullRect.mX = 0; + fullRect.mY = 0; + fullRect.mW = inPainter.GetWidth (); + fullRect.mH = inPainter.GetHeight (); + if (!DrawPlotBackground (fullRect, inPainter)) { + return false; + } + + for (PDrawer::tList::iterator thePre=mPreDrawerList.begin ();thePre!=mPreDrawerList.end();thePre++) { + PDrawer *thePreDrawer = *thePre; + thePreDrawer->Draw (inPainter); + } + + + if (!DrawGridXAxis (theRect, inPainter)) { + return false; + } + + if (!DrawGridYAxis (theRect, inPainter)) { + return false; + } + + if (!DrawXAxis (theRect, inPainter)) { + return false; + } + + if (!DrawYAxis (theRect, inPainter)) { + return false; + } + + // clip the plotregion while drawing plots + inPainter.SetClipRect (theRect.mX, theRect.mY, theRect.mW, theRect.mH); + + for (int theI=0;theI<mPlotDataContainer.GetPlotCount ();theI++) { + if (!DrawPlot (theI, theRect, inPainter)) { + return false; + } + } + + if (mShowLegend) { + if (!DrawLegend (theRect, inPainter)) { + return false; + } + } + + inPainter.SetClipRect (0, 0, inPainter.GetWidth (), inPainter.GetHeight ()); + +#ifdef _IUP_PPLOT_ + if (!DrawPlotTitle (fullRect, inPainter)) { + return false; + } +#endif + + for (PDrawer::tList::iterator thePost=mPostDrawerList.begin ();thePost!=mPostDrawerList.end();thePost++) { + PDrawer *thePostDrawer = *thePost; + thePostDrawer->Draw (inPainter); + } + + return true; +} + +void PPlot::SetPPlotDrawer (PDrawer *inPDrawer) { + if (mOwnsPPlotDrawer) { + delete mPPlotDrawer;// delete (if any) + } + mOwnsPPlotDrawer = true; + mPPlotDrawer = inPDrawer; +} + +void PPlot::SetPPlotDrawer (PDrawer &inPDrawer) { + mOwnsPPlotDrawer = false; + mPPlotDrawer = &inPDrawer; +} + +bool PPlot::DrawPlotBackground (const PRect &inRect, Painter &inPainter) const { + if (!mPlotBackground.mTransparent) { + PColor theC = mPlotBackground.mPlotRegionBackColor; + inPainter.SetFillColor (theC.mR, theC.mG, theC.mB); + inPainter.FillRect (inRect.mX, inRect.mY, inRect.mW, inRect.mH); + } +#ifndef _IUP_PPLOT_ + string theTitle = mPlotBackground.mTitle; + if (theTitle.size ()>0) { + int theW = inPainter.CalculateTextDrawSize (theTitle.c_str()); + int theX = inRect.mX + (inRect.mW-theW)/2; + int theY = inRect.mY + mMargins.mTop; + inPainter.DrawText (theX, theY, theTitle.c_str ()); + } +#endif + return true; +} + +#ifdef _IUP_PPLOT_ +bool PPlot::DrawPlotTitle(const PRect &inRect, Painter &inPainter) const { + if (mPlotBackground.mTitle.size ()>0) { + inPainter.SetStyle (mPlotBackground.mStyle); + int theX = inRect.mX + inRect.mW/2; + int theY = inRect.mY + 5; // do not depend on margin + PColor theC = mPlotBackground.mPlotRegionBackColor; + inPainter.SetFillColor (theC.mR, theC.mG, theC.mB); + int textSize = inPainter.CalculateTextDrawSize(mPlotBackground.mTitle.c_str()); + inPainter.FillRect (theX-textSize/2-3, theY, textSize+6, inPainter.GetFontHeight()+3); + theC = mPlotBackground.mTitleColor; + inPainter.SetFillColor (theC.mR, theC.mG, theC.mB); + inPainter.DrawText (theX, theY, PPLOT_NORTH, mPlotBackground.mTitle.c_str()); + } + return true; +} +#endif + +bool PPlot::DrawGridXAxis (const PRect &inRect, Painter &inPainter) const { + + // ticks + inPainter.SetStyle (mXAxisSetup.mTickInfo.mStyle); + if (!mXTickIterator->Init ()) { + return false; + } + + float theX; + bool theIsMajorTick; + string theFormatString; + +/* M.T. - modified to allow customisation + inPainter.SetFillColor (200,200,200); + inPainter.SetLineColor (200,200,200); +*/ + inPainter.SetLineColor(mGridInfo.mGridColor.mR, + mGridInfo.mGridColor.mG, + mGridInfo.mGridColor.mB); + inPainter.SetStyle (mGridInfo.mStyle); + + // draw gridlines + if (mGridInfo.mXGridOn) { + while (mXTickIterator->GetNextTick (theX, theIsMajorTick, theFormatString)) { + + if (theIsMajorTick && mGridInfo.mXGridOn) { + float theScreenX = mXTrafo->Transform(theX); + inPainter.DrawLine (theScreenX, inRect.mY, theScreenX, inRect.mY + inRect.mH); + } + } + } + + return true; +} + +bool PPlot::DrawGridYAxis (const PRect &inRect, Painter &inPainter) const { + + // ticks + inPainter.SetStyle (mYAxisSetup.mTickInfo.mStyle); + if (!mYTickIterator->Init ()) { + return false; + } + + float theY; + bool theIsMajorTick; + string theFormatString; + PRect theTickRect; + +/* M.T. - modified to allow customisation + inPainter.SetFillColor (200,200,200); + inPainter.SetLineColor (200,200,200); +*/ + inPainter.SetLineColor(mGridInfo.mGridColor.mR, + mGridInfo.mGridColor.mG, + mGridInfo.mGridColor.mB); + inPainter.SetStyle (mGridInfo.mStyle); + + // draw gridlines + if (mYAxisSetup.mTickInfo.mTicksOn) { + while (mYTickIterator->GetNextTick (theY, theIsMajorTick, theFormatString)) { + + if (theIsMajorTick && mGridInfo.mYGridOn) { + float theScreenY = mYTrafo->Transform(theY); + inPainter.DrawLine (inRect.mX, theScreenY, inRect.mX + inRect.mW, theScreenY); + } + } + } + + return true; +} + +#ifdef _IUP_PPLOT_ +static void DrawArrow(Painter &inPainter, float rx, float ry, int vert, int ascen, int size) +{ + int x = (int)(rx + 0.5); + int y = (int)(ry + 0.5); + size += 2; // to avoid too small sizes + int size2 = (int)(size*0.7f + 0.5); + if (vert) + { + y-=ascen*size; + inPainter.DrawLine(x, y, x, y+ascen*size); + + int y2 = y+ascen*size2; + inPainter.FillArrow(x, y, x-size2, y2, x+size2, y2); + } + else + { + x+=ascen*size; + inPainter.DrawLine(x, y, x-ascen*size, y); + + int x2 = x-ascen*size2; + inPainter.FillArrow(x, y, x2, y-size2, x2, y+size2); + } +} +#endif + +bool PPlot::DrawXAxis (const PRect &inRect, Painter &inPainter) const { + inPainter.SetStyle (mXAxisSetup.mStyle); + + float theX1 = inRect.mX; + float theY1; + float theTargetY = 0; + if (!mXAxisSetup.mCrossOrigin) { + if (mYAxisSetup.mAscending) { + theTargetY = mYAxisSetup.mMax; + } else { + theTargetY = mYAxisSetup.mMin; + } + } + theY1 = mYTrafo->Transform (theTargetY); + + inPainter.SetLineColor(mXAxisSetup.mColor.mR, + mXAxisSetup.mColor.mG, + mXAxisSetup.mColor.mB); + + // x-axis + float theX2 = theX1+inRect.mW; + float theY2 = theY1; + inPainter.DrawLine (theX1, theY1, theX2, theY2); + +#ifdef _IUP_PPLOT_ + if (mXAxisSetup.mAscending) + DrawArrow(inPainter, theX2, theY2, 0, 1, mXAxisSetup.mTickInfo.mMinorTickScreenSize); + else + DrawArrow(inPainter, theX1, theY1, 0, -1, mXAxisSetup.mTickInfo.mMinorTickScreenSize); +#endif + + // ticks + inPainter.SetStyle (mXAxisSetup.mTickInfo.mStyle); + if (!mXTickIterator->Init ()) { + return false; + } + + float theX; + bool theIsMajorTick; + string theFormatString; + + int theYMax = 0; + PRect theTickRect; + PRect theRect = inRect; + + if (mXAxisSetup.mTickInfo.mTicksOn) { + while (mXTickIterator->GetNextTick (theX, theIsMajorTick, theFormatString)) { + if (!DrawXTick (theX, theY1, theIsMajorTick, theFormatString, inPainter, theTickRect)) { + return false; + } + + if (theTickRect.mY+theTickRect.mH>theYMax) { + theYMax = theTickRect.mY+theTickRect.mH; + } + } + } + + if (theYMax>theRect.mY+theRect.mH) { + theRect.mH = theYMax-theRect.mY; + } + +#ifdef _IUP_PPLOT_ /* M.T. - the alignment of the text is simply requested */ + if (mXAxisSetup.mLabel.size ()>0) { + inPainter.SetStyle (mXAxisSetup.mStyle); + int theY = theRect.mY + theRect.mH + 3*inPainter.GetFontHeight()/2; + if (mXAxisSetup.mLabelCentered) + { + int theX = theRect.mX + theRect.mW/2; + inPainter.DrawText (theX, theY, PPLOT_NORTH, mXAxisSetup.mLabel.c_str ()); + } + else + { + int theX = theRect.mX + theRect.mW; + inPainter.DrawText (theX, theY, PPLOT_NORTH_EAST, mXAxisSetup.mLabel.c_str ()); + } + } +#else + inPainter.SetStyle (mXAxisSetup.mStyle); + string theLabel = mXAxisSetup.mLabel; + if (theLabel.size ()>0) { + int theW = inPainter.CalculateTextDrawSize (theLabel.c_str ()); + int theX = theRect.mX + (theRect.mW-theW)/2; + int theY = 1 + theRect.mY + theRect.mH + inPainter.GetFontHeight (); // M.T. was too close to ticks + inPainter.DrawText (theX, theY, theLabel.c_str ()); + } +#endif + return true; +} + +bool PPlot::DrawXTick (float inX, int inScreenY, bool inMajor, const string &inFormatString, Painter &inPainter, PRect &outRect) const{ + char theBuf[128]; + int theTickSize; + float theScreenX = mXTrafo->Transform(inX); + outRect.mX = theScreenX; + outRect.mY = inScreenY; + outRect.mW = 0; + if (inMajor) { + theTickSize = mXAxisSetup.mTickInfo.mMajorTickScreenSize; + sprintf (theBuf, inFormatString.c_str (), inX); +#ifdef _IUP_PPLOT_ /* M.T. - the alignment of the text is simply requested */ + outRect.mH = theTickSize + mXAxisSetup.mTickInfo.mMinorTickScreenSize; + inPainter.DrawText (theScreenX, inScreenY+outRect.mH, PPLOT_NORTH, theBuf); +#else + outRect.mH = inPainter.GetFontHeight () + theTickSize + + mXAxisSetup.mTickInfo.mMinorTickScreenSize; + inPainter.DrawText (theScreenX, inScreenY+outRect.mH, theBuf); +#endif + } + else { + theTickSize = mXAxisSetup.mTickInfo.mMinorTickScreenSize; + outRect.mH = theTickSize; + } + + inPainter.DrawLine (theScreenX, inScreenY,theScreenX, inScreenY+theTickSize); + return true; +} + +bool PPlot::DrawYAxis (const PRect &inRect, Painter &inPainter) const { + inPainter.SetStyle (mYAxisSetup.mStyle); + float theX1; + float theTargetX = 0; + if (!mYAxisSetup.mCrossOrigin) { + if (mXAxisSetup.mAscending) { + theTargetX = mXAxisSetup.mMin; + } + else { + theTargetX = mXAxisSetup.mMax; + } + } + if (mXAxisSetup.mDiscrete) + theTargetX -= 0.5; + + theX1 = mXTrafo->Transform (theTargetX); + + int theY1 = inRect.mY; + float theX2 = theX1; + int theY2 = theY1+inRect.mH; + + inPainter.SetLineColor(mYAxisSetup.mColor.mR, + mYAxisSetup.mColor.mG, + mYAxisSetup.mColor.mB); + + // draw y axis + inPainter.DrawLine (theX1, theY1, theX2, theY2); + +#ifdef _IUP_PPLOT_ + if (mYAxisSetup.mAscending) + DrawArrow(inPainter, theX2, theY2, 1, -1, mYAxisSetup.mTickInfo.mMinorTickScreenSize); + else + DrawArrow(inPainter, theX1, theY1, 1, 1, mYAxisSetup.mTickInfo.mMinorTickScreenSize); +#endif + + // ticks + inPainter.SetStyle (mYAxisSetup.mTickInfo.mStyle); + if (!mYTickIterator->Init ()) { + return false; + } + + float theY; + bool theIsMajorTick; + string theFormatString; + PRect theTickRect; + PRect theRect = inRect; + + if (mYAxisSetup.mTickInfo.mTicksOn) { + while (mYTickIterator->GetNextTick (theY, theIsMajorTick, theFormatString)) { + if (!DrawYTick (theY, theX1, theIsMajorTick, theFormatString, inPainter, theTickRect)) { + return false; + } + + if (theTickRect.mX < theRect.mX) { + theRect.mX = theTickRect.mX; + } + } + } + + // draw label +#ifdef _IUP_PPLOT_ /* M.T. - the alignment of the text is simply requested */ + if (mYAxisSetup.mLabel.size ()>0) { + inPainter.SetStyle (mYAxisSetup.mStyle); + int theX = theRect.mX - 3*inPainter.GetFontHeight()/2; + if (mYAxisSetup.mLabelCentered) + { + int theY = theRect.mY + theRect.mH/2; + inPainter.DrawRotatedText (theX, theY, -90, PPLOT_NORTH, mYAxisSetup.mLabel.c_str ()); + } + else + { + int theY = theRect.mY; + inPainter.DrawRotatedText (theX, theY, -90, PPLOT_NORTH_EAST, mYAxisSetup.mLabel.c_str ()); + } + } +#else + inPainter.SetStyle (mYAxisSetup.mStyle); + string theLabel = mYAxisSetup.mLabel; + if (theLabel.size ()>0) { + int theW = inPainter.CalculateTextDrawSize (theLabel.c_str ()); + int theX = theRect.mX - 1; // M.T. - was too close to ticks + int theY = theRect.mY + theRect.mH - (theRect.mH-theW)/2; + inPainter.DrawRotatedText (theX, theY, -90, theLabel.c_str ()); + } +#endif + + return true; +} + +bool PPlot::DrawYTick (float inY, int inScreenX, bool inMajor, const string &inFormatString, Painter &inPainter, PRect &outRect) const { + char theBuf[128]; + int theTickSize; + float theScreenY = mYTrafo->Transform(inY); + outRect.mX = inScreenX; + outRect.mY = theScreenY; + outRect.mW = 0;// not used + outRect.mH = 0;// not used + if (inMajor) { + theTickSize = mYAxisSetup.mTickInfo.mMajorTickScreenSize; + sprintf (theBuf, inFormatString.c_str (), inY); +#ifdef _IUP_PPLOT_ /* M.T. - the alignment of the text is simply requested */ + outRect.mX -= (theTickSize + mYAxisSetup.mTickInfo.mMinorTickScreenSize); + inPainter.DrawText (outRect.mX, theScreenY, PPLOT_EAST, theBuf); + outRect.mX -= inPainter.CalculateTextDrawSize (theBuf); // update the position +#else + int theStringWidth = inPainter.CalculateTextDrawSize (theBuf); + outRect.mX -= (theStringWidth+theTickSize+mYAxisSetup.mTickInfo.mMinorTickScreenSize); + int theHalfFontHeight = inPainter.GetFontHeight ()/2;// for sort of vertical centralizing + inPainter.DrawText (outRect.mX, theScreenY+theHalfFontHeight, theBuf); +#endif + + } + else { + theTickSize = mYAxisSetup.mTickInfo.mMinorTickScreenSize; + outRect.mX -= theTickSize; + } + + inPainter.DrawLine (inScreenX, theScreenY, inScreenX-theTickSize, theScreenY); + return true; +} + +#ifdef _IUP_PPLOT_ +static void DrawRect(Painter &inPainter, int inX, int inY, int inW, int inH) +{ + inPainter.DrawLine(inX, inY, inX+inW-1, inY); + inPainter.DrawLine(inX+inW-1, inY, inX+inW-1, inY+inH-1); + inPainter.DrawLine(inX+inW-1, inY+inH-1, inX, inY+inH-1); + inPainter.DrawLine(inX, inY+inH-1, inX, inY); +} + +bool PPlot::DrawLegend (const PRect &inRect, Painter &inPainter) const { + PColor theC; + int theI; + + int theHeight = inPainter.GetFontHeight(); + int margin = theHeight/2; + int plotCount = mPlotDataContainer.GetPlotCount(); + int totalHeight = plotCount*(1.2*theHeight) - 0.2*theHeight + 2*margin; + + int maxWidth = 0; + for (theI=0; theI<plotCount; theI++) + { + const LegendData *theLegendData = mPlotDataContainer.GetConstLegendData(theI); + if (theLegendData && theLegendData->mShow) { + inPainter.SetStyle (theLegendData->mStyle); + int size = inPainter.CalculateTextDrawSize(theLegendData->mName.c_str()); + + const DataDrawerBase* drawer = mPlotDataContainer.GetConstDataDrawer(theI); + if (drawer->mHasMarks) + { + LineDataDrawer* linedrawer = (LineDataDrawer*)drawer; + if (linedrawer->mDrawPoint) + size += linedrawer->mStyle.mMarkSize+8; + } + + if (size > maxWidth) + maxWidth = size; + } + } + + if (maxWidth == 0) + return false; + + maxWidth += 2*margin; + + int theX = inRect.mX; + int theY = inRect.mY; + + switch (mLegendPos) + { + case PPLOT_TOPLEFT: + theX += 2; + theY += 2; + break; + case PPLOT_BOTTOMLEFT: + theX += 2; + theY += inRect.mH - totalHeight - 2; + break; + case PPLOT_BOTTOMRIGHT: + theX += inRect.mW - maxWidth - 2; + theY += inRect.mH - totalHeight - 2; + break; + default: // PPLOT_TOPRIGHT + theX += inRect.mW - maxWidth - 2; + theY += 2; + break; + } + + theC = mPlotBackground.mPlotRegionBackColor; + inPainter.SetFillColor (theC.mR, theC.mG, theC.mB); + inPainter.FillRect(theX, theY, maxWidth, totalHeight); + inPainter.SetLineColor (theC.mR/1.5, theC.mG/1.5, theC.mB/1.5); + DrawRect(inPainter, theX, theY, maxWidth, totalHeight); + + for (theI=0; theI<plotCount; theI++) { + const LegendData *theLegendData = mPlotDataContainer.GetConstLegendData(theI); + if (theLegendData && theLegendData->mShow) { + theC = theLegendData->mColor; + inPainter.SetLineColor (theC.mR, theC.mG, theC.mB); + + int X = theX + margin; + int Y = theY + theI*(theHeight*1.2) + margin; + + int mark_size = 0; + const DataDrawerBase* drawer = mPlotDataContainer.GetConstDataDrawer(theI); + if (drawer->mHasMarks) + { + LineDataDrawer* linedrawer = (LineDataDrawer*)drawer; + if (linedrawer->mDrawPoint) + { + mark_size = linedrawer->mStyle.mMarkSize+8; + inPainter.SetStyle (linedrawer->mStyle); + linedrawer->DrawPoint(X+mark_size/2, Y+3*inPainter.GetFontHeight()/4, inRect, inPainter); + } + } + + inPainter.SetStyle (theLegendData->mStyle); + inPainter.DrawText (X+mark_size, Y, PPLOT_NORTH_WEST, theLegendData->mName.c_str ()); + } + } + return true; +} +#else +bool PPlot::DrawLegend (const PRect &inRect, Painter &inPainter) const { + const int kXoffsetLegend(20); + + for (int theI=0; theI<mPlotDataContainer.GetPlotCount (); theI++) { + PColor theC; + string theText; + const LegendData *theLegendData = mPlotDataContainer.GetConstLegendData (theI); + if (theLegendData) { + inPainter.SetStyle (theLegendData->mStyle); + theC = theLegendData->mColor; + if (theLegendData->mShow) { + theText = theLegendData->mName; + } + } + inPainter.SetLineColor (theC.mR, theC.mG, theC.mB); + + // cut legend if it doesn't fit in plot + int theSize (0); + if (inPainter.CalculateTextDrawSize (theText.c_str ()) >= inRect.mW - kXoffsetLegend) { + theText.insert(0, "..."); + while (inPainter.CalculateTextDrawSize (theText.c_str ()) >= inRect.mW - kXoffsetLegend) { + theSize = theText.size (); + // display dots and at least 3 characters + if (theSize >= 9) { + theText.erase (3, 3); + } + else if (theSize >= 7) { + theText.erase (3, theSize - 6); + } else { + // keep dots only + theText.erase (3, theSize - 3); + break; + } + } + } + + int theHeight = inPainter.GetFontHeight (); + int theX = inRect.mX + kXoffsetLegend; + int theY = inRect.mY + theI*(theHeight*2)+theHeight; + inPainter.DrawText (theX, theY, theText.c_str ()); + } + return true; +} +#endif + +static float GetMaxFromRange (const PlotDataBase &inData, long inStartIndex, long inEndIndex) { + float max = 0; + float fabsMax = 0; + for (long theI = inStartIndex; theI <= inEndIndex; theI++) { + if (theI == inStartIndex) { + max = inData.GetValue (theI); + fabsMax = fabs (max); + } + else { + float data = inData.GetValue (theI); + if (fabs (data) > fabsMax) { + max = data; + fabsMax = fabs (data); + } + } + } + + return max; +} + +static void FindRange (const PlotDataBase &inData, float inMin, float inMax, long& outStartIndex, long& outEndIndex) { + outStartIndex = 0; + while (outStartIndex < inData.GetSize () && inData.GetValue (outStartIndex) <= inMin) { + outStartIndex++; + } + + if (outStartIndex == inData.GetSize ()) { + outStartIndex = inData.GetSize () - 1; + outEndIndex = outStartIndex; + assert (outStartIndex>-1); + return; + } + + // We want the value at outStartIndex smaller than or equal to inMin + if (outStartIndex > 0) { + outStartIndex--; + } + + outEndIndex = outStartIndex; + while (outEndIndex < inData.GetSize () && inData.GetValue (outEndIndex) < inMax) { + outEndIndex++; + } + + if (outEndIndex == inData.GetSize ()) { + outEndIndex--; + } + assert (outStartIndex>-1); +} + +static void DrawValue(int theTraX, int theTraY, float theX, float theY, const PlotDataBase &inXData, const AxisSetup &inXAxisSetup, Painter &inPainter) +{ + char theBuf[128]; + string FormatString; + if (inXData.IsString()) + { + const StringPlotData *theStringXData = (const StringPlotData *)(&inXData); + FormatString = "(%s, " + inXAxisSetup.mTickInfo.mFormatString + ")"; + const StringData* stdata = theStringXData->GetStringData(); + sprintf (theBuf, FormatString.c_str(), (*stdata)[(int)theX].c_str(), theY); + } + else + { + FormatString = "(" + inXAxisSetup.mTickInfo.mFormatString + ", " + inXAxisSetup.mTickInfo.mFormatString + ")"; + sprintf (theBuf, FormatString.c_str(), theX, theY); + } + inPainter.DrawRotatedText (theTraX, theTraY-10, -45, PPLOT_WEST, theBuf); +} + +bool LineDataDrawer::DrawData (const PlotDataBase &inXData, const PlotDataBase &inYData, const PlotDataSelection &inPlotDataSelection, const AxisSetup &inXAxisSetup, const PRect &inRect, Painter &inPainter) const { + if (!mXTrafo || !mYTrafo) { + return false; + } + if ((inXData.GetSize () == 0) || (inYData.GetSize () == 0)) { + return false; + } + long theXSize = inXData.GetSize (); + long theYSize = inYData.GetSize (); + if (theXSize>theYSize) { + return false; + } + inPainter.SetStyle (mStyle); + float thePrevX = 0; + float thePrevY = 0; + bool theFirst = true; + float theTraX, theTraY; + + long theStart = 0; + long theEnd = inXData.GetSize () - 1; + int theStride = 1; + if (mDrawFast) { + FindRange (inXData, inXAxisSetup.mMin, inXAxisSetup.mMax, theStart, theEnd); + + theStride = (theEnd - theStart + 1) / inPainter.GetWidth (); + if (theStride == 0) { + theStride = 1; + } + } + + for (int theI = theStart; theI <= theEnd; theI+=theStride) { + + float theY; + float theX = inXData.GetValue (theI); + theTraX = mXTrafo->Transform (theX); + if (theStride > 1) { + long theLast = theI + theStride - 1; + if (theLast>theEnd) { + theLast = theEnd; + } + theY = GetMaxFromRange (inYData, theI, theLast); + } + else { + theY = inYData.GetValue (theI); + } + theTraY = mYTrafo->Transform (theY); + + if (!theFirst && mDrawLine) { + inPainter.DrawLine (thePrevX, thePrevY, theTraX, theTraY); + } + else { + theFirst = false; + } + bool theDrawPoint = mDrawPoint; + + if (theDrawPoint && !DrawPoint (theTraX, theTraY, inRect, inPainter)) { + return false; + } + if (inPlotDataSelection.IsSelected (theI) && !DrawSelection (theTraX, theTraY, inRect, inPainter)) { + return false; + } +#ifdef _IUP_PPLOT_ + if (mShowValues) + DrawValue(theTraX, theTraY, theX, theY, inXData, inXAxisSetup, inPainter); +#endif + thePrevX = theTraX; + thePrevY = theTraY; + } + return true; +} + +DataDrawerBase* LineDataDrawer::Clone () const { + return new LineDataDrawer (*this); +} + +bool LineDataDrawer::DrawPoint (int inScreenX, int inScreenY, const PRect &inRect, Painter &inPainter) const { + inPainter.DrawLine (inScreenX-5, inScreenY+5, inScreenX+5, inScreenY-5); + inPainter.DrawLine (inScreenX-5, inScreenY-5, inScreenX+5, inScreenY+5); + return true; +} + +bool LineDataDrawer::DrawSelection (int inScreenX, int inScreenY, const PRect &inRect, Painter &inPainter) const { +// inPainter.DrawLine (inScreenX-5, inScreenY+5, inScreenX+5, inScreenY-5); +// inPainter.DrawLine (inScreenX-5, inScreenY-5, inScreenX+5, inScreenY+5); + inPainter.FillRect (inScreenX-5, inScreenY-5, 10, 10); + return true; +} + +bool DotDataDrawer::DrawPoint (int inScreenX, int inScreenY, const PRect &inRect, Painter &inPainter) const { + inPainter.DrawLine (inScreenX, inScreenY, inScreenX + 1, inScreenY); + return true; +} + +bool BarDataDrawer::DrawData (const PlotDataBase &inXData, const PlotDataBase &inYData, const PlotDataSelection &inPlotDataSelection, const AxisSetup &inXAxisSetup, const PRect &inRect, Painter &inPainter) const { + if (!mXTrafo || !mYTrafo) { + return false; + } + if (inXData.GetSize ()>inYData.GetSize ()) { + return false; + } + if (!mPlotCount) { + return false; + } + if (mDrawOnlyLastPoint) { + return DrawOnlyLastPoint (inXData, inYData, inPlotDataSelection, inXAxisSetup, inRect, inPainter); + } + + int theTraX, theTraY; + int theTraY0 = mYTrafo->Transform (0); + + int theLeft, theTop, theWidth, theHeight; + + theWidth = inRect.mW/inXData.GetSize (); + theWidth *= 0.9f; + + for (long theI=0;theI<inXData.GetSize ();theI++) { + float theX = inXData.GetValue (theI); + float theY = inYData.GetValue (theI); + theTraX = mXTrafo->Transform (theX); + theTraY = mYTrafo->Transform (theY); + + theLeft = theTraX-theWidth/2; + theTop = theTraY; + theHeight = theTraY0-theTop; + + inPainter.FillRect (theLeft, theTop, theWidth, theHeight); + +#ifdef _IUP_PPLOT_ + if (mShowValues) + DrawValue(theTraX, theTraY, theX, theY, inXData, inXAxisSetup, inPainter); +#endif + } + return true; +} + + +bool BarDataDrawer::DrawOnlyLastPoint (const PlotDataBase &inXData, const PlotDataBase &inYData, const PlotDataSelection &inPlotDataSelection, const AxisSetup &inXAxisSetup, const PRect &inRect, Painter &inPainter) const { + + PRect theRect = inRect; + theRect.mW = inRect.mW / mPlotCount; + theRect.mX = inRect.mX + mPlotIndex * theRect.mW; + + int theTraX, theTraY; + int theTraY0 = mYTrafo->Transform (0); + + int theLeft, theTop, theWidth, theHeight; + + theWidth = theRect.mW; + + // only draw last point: + long theI = inXData.GetSize () - 1; + if (theI >= 0) { + theTraX = mXTrafo->Transform (inXData.GetValue (theI)); + theTraY = mYTrafo->Transform (inYData.GetValue (theI)); + + theLeft = theRect.mX; + theTop = theTraY; + theHeight = theTraY0-theTop; + + inPainter.FillRect (theLeft, theTop, theWidth, theHeight); + } + return true; +} + + +DataDrawerBase* BarDataDrawer::Clone () const { + return new BarDataDrawer (*this); +} + +bool PPlot::DrawPlot (int inIndex, const PRect &inRect, Painter &inPainter) const { + + if (inIndex>=mPlotDataContainer.GetPlotCount ()) { + return false; + } + + const PlotDataBase *theXData = mPlotDataContainer.GetConstXData (inIndex); + const PlotDataBase *theYData = mPlotDataContainer.GetConstYData (inIndex); + if (!theXData || !theYData) { + return false; + } + const LegendData *theLegendData = mPlotDataContainer.GetConstLegendData (inIndex); + PColor theC; + if (theLegendData) { + theC = theLegendData->mColor; + } + inPainter.SetLineColor (theC.mR, theC.mG, theC.mB); + inPainter.SetFillColor (theC.mR, theC.mG, theC.mB); + + const DataDrawerBase *theD = mPlotDataContainer.GetConstDataDrawer (inIndex); + if (!theD) { + return false; + } + const PlotDataSelection *thePlotDataSelection = mPlotDataContainer.GetConstPlotDataSelection (inIndex); + if (!thePlotDataSelection) { + return false; + } + + return theD->DrawData (*theXData, *theYData, *thePlotDataSelection, mXAxisSetup, inRect, inPainter); + } + +bool PPlot::ConfigureSelf () { + long thePlotCount = mPlotDataContainer.GetPlotCount (); + if (thePlotCount == 0) { + return false; + } + if (mXAxisSetup.mLogScale) { + mXTickIterator = &mXLogTickIterator; + mXTrafo = &mXLogTrafo; + mYAxisSetup.mCrossOrigin = false; + } + else { + const PlotDataBase *theGlue = mPlotDataContainer.GetConstXData (0); + if (theGlue->IsString()) { + const StringPlotData *theStringXData = (const StringPlotData *)(theGlue); + mXTickIterator = &mXNamedTickIterator; + mXNamedTickIterator.SetStringList (*(theStringXData->GetStringData ())); + } + else { + mXTickIterator = &mXLinTickIterator; + } + mXTrafo = &mXLinTrafo; + } + if (mYAxisSetup.mLogScale) { + mYTickIterator = &mYLogTickIterator; + mYTrafo = &mYLogTrafo; + mXAxisSetup.mCrossOrigin = false; + } + else { + mYTickIterator = &mYLinTickIterator; + mYTrafo = &mYLinTrafo; + } + mXTickIterator->SetAxisSetup (&mXAxisSetup); + mYTickIterator->SetAxisSetup (&mYAxisSetup); + + // set trafo's for data drawers + for (int theI=0; theI<mPlotDataContainer.GetPlotCount ();theI++) { + DataDrawerBase *theD = (mPlotDataContainer.GetDataDrawer (theI)); + if (theD) { + theD->SetXTrafo (mXTrafo); + theD->SetYTrafo (mYTrafo); + theD->SetPlotCount (mPlotDataContainer.GetPlotCount ()); + theD->SetPlotIndex (theI); + } + } + + return true; +} + +bool PPlot::ValidateData () { + + /* check x data ascending + for (int theI=0; theI<mPlotDataContainer.GetPlotCount ();theI++) { + const RealData *theX = dynamic_cast <const RealData *> (mPlotDataContainer.GetConstXData (theI)); + if (theX && theX->size ()>0) { + float thePrev = (*theX)[0]; + for (RealData::const_iterator theJ=theX->begin ();theJ!=theX->end ();theJ++) { + float theNext = *theJ; + if (theNext<thePrev) { + return false; + } + } + } + } */ + return true; +} + +bool PPlot::CalculateAxisRanges () { + + float theXMin; + float theXMax; + + mPlotDataContainer.CalculateXRange (theXMin, theXMax); + if (mXAxisSetup.mAutoScaleMin || mXAxisSetup.mAutoScaleMax) { + + if (mXAxisSetup.mAutoScaleMin) { + mXAxisSetup.mMin = theXMin; + if (mXAxisSetup.mLogScale && (theXMin < kLogMinClipValue) ) { + mXAxisSetup.mMin = kLogMinClipValue; + } + } + + if (mXAxisSetup.mAutoScaleMax) { + mXAxisSetup.mMax = theXMax; + } + + if (!mXTickIterator->AdjustRange (mXAxisSetup.mMin, mXAxisSetup.mMax)) { + return false; + } + } + + if (mYAxisSetup.mAutoScaleMin || mYAxisSetup.mAutoScaleMax) { + float theYMin; + float theYMax; + + mPlotDataContainer.CalculateYRange (mXAxisSetup.mMin, mXAxisSetup.mMax, + theYMin, theYMax); + + if (mYAxisSetup.mAutoScaleMin) { + mYAxisSetup.mMin = theYMin; + if (mYAxisSetup.mLogScale && (theYMin < kLogMinClipValue) ) { + mYAxisSetup.mMin = kLogMinClipValue; + } + } + if (mYAxisSetup.mAutoScaleMax) { + mYAxisSetup.mMax = theYMax; + } + + if (!mYTickIterator->AdjustRange (mYAxisSetup.mMin, mYAxisSetup.mMax)) { + return false; + } + } + + return true; +} + +bool PPlot::CheckRange (const AxisSetup &inAxisSetup) const { + if (inAxisSetup.mLogScale) { + if (inAxisSetup.mMin < kLogMinClipValue) { + return false; + } + + } + return true; +} + +bool PPlot::CalculateTickInfo (const PRect &inRect, Painter &inPainter) { + float theXRange = mXAxisSetup.mMax - mXAxisSetup.mMin; + float theYRange = mYAxisSetup.mMax - mYAxisSetup.mMin; + + if (theXRange <= 0 || theYRange < 0) { + return false; + } + + if ((mYAxisSetup.mMax != 0 && fabs (theYRange / mYAxisSetup.mMax) < kRangeVerySmall) || + theYRange == 0) { + float delta = 0.1f; + if (mYAxisSetup.mMax != 0) { + delta *= fabs(mYAxisSetup.mMax); + } + + mYAxisSetup.mMax += delta; + mYAxisSetup.mMin -= delta; + theYRange = mYAxisSetup.mMax - mYAxisSetup.mMin; + } + + if (mXAxisSetup.mTickInfo.mAutoTick) { + inPainter.SetStyle(mXAxisSetup.mTickInfo.mStyle); + int theTextWidth = inPainter.CalculateTextDrawSize ("12345"); + float theDivGuess = inRect.mW/(kMajorTickXInitialFac*theTextWidth); + if (!mXTickIterator->InitFromRanges (theXRange, inRect.mH, theDivGuess, mXAxisSetup.mTickInfo)) { + return false; + } + } + if (mYAxisSetup.mTickInfo.mAutoTick) { + float theTextHeight = inPainter.GetFontHeight (); + float theDivGuess = inRect.mH/(kMajorTickYInitialFac*theTextHeight); + if (!mYTickIterator->InitFromRanges (theYRange, inRect.mW, theDivGuess, mYAxisSetup.mTickInfo)) { + return false; + } + } + + SetTickSizes (inPainter.GetFontHeight (), mXAxisSetup.mTickInfo); + SetTickSizes (inPainter.GetFontHeight (), mYAxisSetup.mTickInfo); + + return true; +} + +void PPlot::SetTickSizes (int inFontHeight, TickInfo &ioTickInfo) { + if (ioTickInfo.mAutoTickSize) { + float theFac = kRelMinorTickSize/kRelMajorTickSize; + float theMax = Round (inFontHeight*kMaxMajorTickSizeInFontHeight); + if (ioTickInfo.mMajorTickScreenSize>theMax) { + ioTickInfo.mMajorTickScreenSize = theMax; + } + ioTickInfo.mMinorTickScreenSize = Round (ioTickInfo.mMajorTickScreenSize*theFac); + } +} + + +bool PPlot::CalculateLogTransformation (int inBegin, int inEnd, const AxisSetup& inAxisSetup, LogTrafo& outTrafo) { + + float theBase = inAxisSetup.mLogBase; + long theLogFac = 1;//inAxisSetup.mLogFactor; + float theDataRange = SafeLog (inAxisSetup.mMax, theBase, theLogFac) - SafeLog(inAxisSetup.mMin, theBase, theLogFac); + if (theDataRange < kFloatSmall) { + return false; + } + float theTargetRange = inEnd - inBegin; + float theScale = theTargetRange / theDataRange; + + if (inAxisSetup.mAscending ) { + outTrafo.mOffset = inBegin - SafeLog(inAxisSetup.mMin, theBase, theLogFac) * theScale; + } else { + outTrafo.mOffset = inEnd + SafeLog(inAxisSetup.mMin, theBase, theLogFac) * theScale; + } + outTrafo.mSlope = -theScale; + outTrafo.mBase = theBase; +// outTrafo.mFactor = inAxisSetup.mLogFactor; + + if (inAxisSetup.mAscending) { + outTrafo.mSlope *= -1; + } + return true; +} + +bool PPlot::CalculateLinTransformation (int inBegin, int inEnd, const AxisSetup& inAxisSetup, LinTrafo& outTrafo) { + float theDataRange = inAxisSetup.mMax - inAxisSetup.mMin; + if (theDataRange < kFloatSmall) { + return false; + } + float theMin = inAxisSetup.mMin; + if (inAxisSetup.mDiscrete) + { + theDataRange++; + theMin -= 0.5f; + } + + float theTargetRange = inEnd - inBegin; + float theScale = theTargetRange / theDataRange; + + if (inAxisSetup.mAscending) { + outTrafo.mOffset = inBegin - theMin * theScale; + } else { + outTrafo.mOffset = inEnd + theMin * theScale; + } + outTrafo.mSlope = -theScale; + + if (inAxisSetup.mAscending) { + outTrafo.mSlope *= -1; + } + return true; +} + +bool PPlot::CalculateXTransformation (const PRect &inRect) { + if (mXAxisSetup.mLogScale) { + return CalculateLogTransformation (inRect.mX, inRect.mX + inRect.mW, mXAxisSetup, mXLogTrafo); + } + else { + return CalculateLinTransformation (inRect.mX, inRect.mX + inRect.mW, mXAxisSetup, mXLinTrafo); + } +} + +bool PPlot::CalculateYTransformation (const PRect &inRect) { + if (mYAxisSetup.mLogScale) { + return CalculateLogTransformation (inRect.mY, inRect.mY + inRect.mH, mYAxisSetup, mYLogTrafo); + } + else { + return CalculateLinTransformation (inRect.mY, inRect.mY + inRect.mH, mYAxisSetup, mYLinTrafo); + } +} + +#ifndef _IUP_PPLOT_ +bool MakeExamplePlot (int inExample, PPlot &ioPPlot) { + switch (inExample) { + case 1: + MakeExamplePlot1 (ioPPlot); + return true; + break; + case 2: + MakeExamplePlot2 (ioPPlot); + return true; + break; + case 3: + MakeExamplePlot3 (ioPPlot); + return true; + break; + case 4: + MakeExamplePlot4 (ioPPlot); + return true; + break; + case 5: + MakeExamplePlot5 (ioPPlot); + return true; + break; + case 6: + MakeExamplePlot6 (ioPPlot); + return true; + break; + case 7: + MakeExamplePlot7 (ioPPlot); + return true; + break; + case 8: + MakeExamplePlot8 (ioPPlot); + return true; + break; + } + return false; +} + +void MakeExamplePlot1 (PPlot &ioPPlot) { + + int theI; + PlotData *theX1 = new PlotData (); + PlotData *theY1 = new PlotData (); + float theFac = (float)1.0/(100*100*100); + for (theI=-100;theI<=100;theI++) { + theX1->push_back (theI+50); + theY1->push_back (theFac*theI*theI*theI); + } + LineDataDrawer *theDataDrawer1 = new LineDataDrawer (); + theDataDrawer1->mStyle.mPenWidth = 3; + ioPPlot.mPlotDataContainer.AddXYPlot (theX1, theY1, 0, theDataDrawer1); + ioPPlot.mPlotBackground.mTitle = "Bar"; + ioPPlot.mPlotBackground.mStyle.mFontSize = 20; + ioPPlot.mMargins.mTop = 60; + ioPPlot.mXAxisSetup.mLabel = "gnu (Foo)"; + ioPPlot.mYAxisSetup.mLabel = "Space (m^3)"; + ioPPlot.mYAxisSetup.mStyle.mFontSize = 9; + ioPPlot.mYAxisSetup.mTickInfo.mStyle.mFontSize = 5; + ioPPlot.mYAxisSetup.mStyle.mPenWidth = 2; + ioPPlot.mXAxisSetup.mStyle = ioPPlot.mYAxisSetup.mStyle; + ioPPlot.mXAxisSetup.mTickInfo.mStyle = ioPPlot.mYAxisSetup.mTickInfo.mStyle; + + PlotData *theX2 = new PlotData (); + PlotData *theY2 = new PlotData (); + theFac = (float)2.0/100; + for (theI=-100;theI<=100;theI++) { + theX2->push_back (theI); + theY2->push_back (-theFac*theI); + } + ioPPlot.mPlotDataContainer.AddXYPlot (theX2, theY2); + LegendData *theLegendData2 = ioPPlot.mPlotDataContainer.GetLegendData (1); + theLegendData2->mStyle.mFontSize = 9; + + PlotData *theX3 = new PlotData (); + PlotData *theY3 = new PlotData (); + for (theI=-100;theI<=100;theI++) { + theY3->push_back (0.01*theI); + theX3->push_back (0.01*theI*theI-30); + } + ioPPlot.mPlotDataContainer.AddXYPlot (theX3, theY3); +} + +void MakeExamplePlot2 (PPlot &ioPPlot) { + + int theI; + PlotData *theX1 = new PlotData (); + PlotData *theY1 = new PlotData (); + float theFac = (float)1.0/(100*100*100); + for (theI=0;theI<=100;theI++) { + theX1->push_back (theI); + theY1->push_back (theFac*theI*theI*theI); + } + ioPPlot.mPlotDataContainer.AddXYPlot (theX1, theY1, 0); + + PlotData *theX2 = new PlotData (); + PlotData *theY2 = new PlotData (); + theFac = (float)2.0/100; + for (theI=0;theI<=100;theI++) { + theX2->push_back (theI); + theY2->push_back (-theFac*theI); + } + ioPPlot.mPlotDataContainer.AddXYPlot (theX2, theY2, 0); + + ioPPlot.mPlotBackground.mTitle = "no autoscale"; + ioPPlot.mPlotBackground.mStyle.mFontSize = 15; + ioPPlot.mPlotBackground.mTransparent = false; + ioPPlot.mPlotBackground.mPlotRegionBackColor = PColor (200,200,200); + ioPPlot.mMargins.mTop = 60; + ioPPlot.mMargins.mRight = 30; + ioPPlot.mXAxisSetup.mLabel = "Tg (X)"; + ioPPlot.mXAxisSetup.SetAutoScale (false); + ioPPlot.mXAxisSetup.mMin = 10; + ioPPlot.mXAxisSetup.mMax = 60; + ioPPlot.mYAxisSetup.SetAutoScale (false); + ioPPlot.mYAxisSetup.mMin = -0.5; + ioPPlot.mYAxisSetup.mMax = 0.5; + + ioPPlot.mXAxisSetup.mCrossOrigin = false; + ioPPlot.mYAxisSetup.mCrossOrigin = false; + ioPPlot.mXAxisSetup.mAscending = false; + ioPPlot.mYAxisSetup.mAscending = true; + + // M.T. - use a color different from background + ioPPlot.mGridInfo.mGridColor = PColor(128,255,128); // some sort of green +} + +void MakeExamplePlot3 (PPlot &ioPPlot) { + + PlotData *theX1 = new PlotData (); + PlotData *theY1 = new PlotData (); + float theFac = 1.0f/(100*100*100); + for (int theI=0;theI<=100;theI++) { + // theX1->push_back (theI*0.001); + theX1->push_back (theI); + theY1->push_back (theFac*theI*theI*theI); + } + ioPPlot.mPlotDataContainer.AddXYPlot (0, theY1, 0); + + ioPPlot.mPlotBackground.mTitle = "narrow margins"; + ioPPlot.mPlotBackground.mTransparent = false; + ioPPlot.mPlotBackground.mPlotRegionBackColor = PColor (200,200,200); + ioPPlot.mMargins.mTop = 50; + ioPPlot.mMargins.mRight = 10; + ioPPlot.mMargins.mLeft = 10; + ioPPlot.mMargins.mBottom = 10; + + // M.T. - use a color different from background + ioPPlot.mGridInfo.mGridColor = PColor(128,255,128); // some sort of green +} + +void MakeExamplePlot4 (PPlot &ioPPlot) { + + PlotData *theX1 = new PlotData (); + PlotData *theY1 = new PlotData (); + float theFac = 100.0f/(100*100*100); + for (int theI=0;theI<=100;theI++) { + theX1->push_back (0.0001+theI*0.001); + theY1->push_back (0.01+theFac*theI*theI*theI); + } + LegendData *theLegend = new LegendData (); + theLegend->mName = "foo"; + theLegend->mColor = PColor (100,100,200); + ioPPlot.mPlotDataContainer.AddXYPlot (theX1, theY1, theLegend); + ioPPlot.mXAxisSetup.mLogScale = true; + ioPPlot.mYAxisSetup.mLogScale = true; + ioPPlot.mYAxisSetup.mLogBase = 2; + ioPPlot.mMargins.mLeft = 50; + ioPPlot.mMargins.mTop = 20; + + ioPPlot.mGridInfo.mXGridOn = true; + ioPPlot.mGridInfo.mYGridOn = true; +} + +void MakeExamplePlot5 (PPlot &ioPPlot) { + + const char * kLables[12] = {"jan","feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"}; + const float kData[12] = {1,2,3,4,5,6,7,8,9,0,1,2}; + + StringPlotData *theX1 = new StringPlotData (); + PlotData *theY1 = new PlotData (); + for (int theI=0;theI<12;theI++) { + theX1->AddItem (kLables[theI]); + theY1->push_back (kData[theI]); + } + LegendData *theLegend = new LegendData (); + theLegend->mName = "bar"; + theLegend->mColor = PColor (100,100,200); + BarDataDrawer *theDataDrawer = new BarDataDrawer (); + ioPPlot.mPlotDataContainer.AddXYPlot (theX1, theY1, theLegend, theDataDrawer); + ioPPlot.mMargins.mLeft = 50; + ioPPlot.mMargins.mTop = 20; +} + +void MakeExamplePlot6 (PPlot &ioPPlot) { + + int theI; + + ioPPlot.mPlotBackground.mTitle = "line styles"; + PlotData *theX1 = new PlotData (); + PlotData *theY1 = new PlotData (); + float theFac = 100.0f/(100*100*100); + for (theI=0;theI<=10;theI++) { + theX1->push_back (0.0001+theI*0.001); + theY1->push_back (0.01+theFac*theI*theI); + } + LineDataDrawer *theDataDrawer1 = new LineDataDrawer (); + theDataDrawer1->mDrawPoint = true; + theDataDrawer1->mStyle.mPenWidth = 3; + ioPPlot.mPlotDataContainer.AddXYPlot (theX1, theY1, 0, theDataDrawer1); + + PlotData *theX2 = new PlotData (); + PlotData *theY2 = new PlotData (); + for (theI=0;theI<=10;theI++) { + theX2->push_back (0.0001+theI*0.001); + theY2->push_back (0.2-theFac*theI*theI); + } + LineDataDrawer *theDataDrawer2 = new LineDataDrawer (); + theDataDrawer2->mDrawPoint = true; + theDataDrawer2->mDrawLine = false; + ioPPlot.mPlotDataContainer.AddXYPlot (theX2, theY2, 0, theDataDrawer2); + + ioPPlot.mMargins.mLeft = 50; + ioPPlot.mMargins.mTop = 40; +} + +void MakeExamplePlot7 (PPlot &ioPPlot) { + + PlotData *theX1 = new PlotData (); + PlotData *theY1 = new PlotData (); + float theFac = 100.0f/(100*100*100); + for (int theI=0;theI<=100;theI++) { + theX1->push_back (0.0001+theI*0.001); + theY1->push_back (0.01+theFac*theI*theI*theI); + } + LegendData *theLegend = new LegendData (); + theLegend->mName = "foo"; + theLegend->mColor = PColor (100,100,200); + ioPPlot.mPlotDataContainer.AddXYPlot (theX1, theY1, theLegend); + ioPPlot.mYAxisSetup.mLogScale = true; + ioPPlot.mYAxisSetup.mLogFactor = 20; + ioPPlot.mMargins.mLeft = 50; + ioPPlot.mMargins.mTop = 20; + + ioPPlot.mGridInfo.mXGridOn = true; + ioPPlot.mGridInfo.mYGridOn = true; +} + +void MakeExamplePlot8 (PPlot &ioPPlot) { + + ioPPlot.mPlotBackground.mTitle = "data selection and editing"; + PlotData *theX1 = new PlotData (); + PlotData *theY1 = new PlotData (); + float theFac = 100.0f/(100*100*100); + for (int theI=-10;theI<=10;theI++) { + theX1->push_back (0.001*theI); + theY1->push_back (0.01+theFac*theI*theI*theI); + } + LegendData *theLegend = new LegendData (); + theLegend->mName = "foo"; + theLegend->mColor = PColor (100,100,200); + + PlotDataSelection *thePlotDataSelection = new PlotDataSelection (); + ioPPlot.mPlotDataContainer.AddXYPlot (theX1, theY1, theLegend, 0, thePlotDataSelection); + ioPPlot.mMargins.mLeft = 30; + ioPPlot.mMargins.mTop = 30; + ioPPlot.mMargins.mBottom = 30; + ioPPlot.mMargins.mRight = 30; +} + +void MakePainterTester (PPlot &ioPPlot) { + ioPPlot.SetPPlotDrawer (new PainterTester ()); +} + +static PPlot *sCurrentPPlot=0; + +void SetCurrentPPlot (PPlot *inPPlot) { + sCurrentPPlot = inPPlot; +} +#include <assert.h> +PPlot & GetCurrentPPlot () { + fprintf (stderr, "getplot\n"); + if (sCurrentPPlot) { + return *sCurrentPPlot; + } + assert (0); + fprintf (stderr, "aargh\n"); + + return *sCurrentPPlot;// this should not happen +} + + + +void MakeCopy (const PPlot &inPPlot, PPlot &outPPlot) { + // copy settings + outPPlot.mGridInfo = inPPlot.mGridInfo; + outPPlot.mMargins = inPPlot.mMargins; + outPPlot.mXAxisSetup = inPPlot.mXAxisSetup; + outPPlot.mYAxisSetup = inPPlot.mYAxisSetup; + outPPlot.mPlotBackground = inPPlot.mPlotBackground; + + // now the data + for (int theI=0;theI<inPPlot.mPlotDataContainer.GetPlotCount ();theI++) { + const PlotDataBase *theXData = inPPlot.mPlotDataContainer.GetConstXData (theI); + const PlotDataBase *theYData = inPPlot.mPlotDataContainer.GetConstYData (theI); + const LegendData *theLegendData = inPPlot.mPlotDataContainer.GetConstLegendData (theI); + const DataDrawerBase* theDrawer = inPPlot.mPlotDataContainer.GetConstDataDrawer (theI); + + PlotDataBase *theNewXData = new PlotDataPointer (theXData); + PlotDataBase *theNewYData = new PlotDataPointer (theYData); + LegendData *theNewLegendData = new LegendData (); + *theNewLegendData = *theLegendData; + DataDrawerBase* theNewDrawer = theDrawer->Clone (); + + outPPlot.mPlotDataContainer.AddXYPlot (theNewXData, theNewYData, theNewLegendData, theNewDrawer); + + } + +} +#endif |