#include #include #include #include #include "iupPlot.h" const double kMajorTickXInitialFac = 2.0; const double kMajorTickYInitialFac = 3.0; const double kRangeVerySmall = (double)1.0e-3; void iupPlot::CalculateTitlePos() { // it does not depend on theMargin if (mTitle.mAutoPos) { mTitle.mPosX = mViewport.mWidth / 2; mTitle.mPosY = mViewport.mHeight - 1 - mBack.mVertPadding; } } bool iupPlot::CheckInsideTitle(cdCanvas* canvas, int x, int y) const { // it does not depend on theMargin if (mTitle.GetText()) { SetTitleFont(canvas); cdCanvasTextAlignment(canvas, CD_NORTH); int xmin, xmax, ymin, ymax; cdCanvasGetTextBox(canvas, mTitle.mPosX, mTitle.mPosY, mTitle.GetText(), &xmin, &xmax, &ymin, &ymax); if (x >= xmin && x <= xmax && y >= ymin && y <= ymax) return true; } return false; } bool iupPlot::CheckInsideLegend(int x, int y) const { if (mLegend.mShow) { if (x >= mLegend.mPos.mX && x < mLegend.mPos.mX + mLegend.mPos.mWidth && y >= mLegend.mPos.mY && y < mLegend.mPos.mY + mLegend.mPos.mHeight) return true; } return false; } int iupPlot::CalcTitleVerticalMargin(cdCanvas* canvas) const { SetTitleFont(canvas); int theTextHeight; cdCanvasGetTextSize(canvas, mTitle.GetText(), NULL, &theTextHeight); return theTextHeight + 5 + theTextHeight / 2; } int iupPlot::CalcXTickHorizontalMargin(cdCanvas* canvas, bool start) const { int theXTickHorizontalMargin = 0; if (mAxisX.mShowArrow) { if ((!start && !mAxisX.mReverse) || ( start && mAxisX.mReverse)) theXTickHorizontalMargin += mAxisX.GetArrowSize(); } if (mAxisX.mTick.mShow && mAxisX.mTick.mShowNumber) // Leave space for half number theXTickHorizontalMargin = iupPlotMax(theXTickHorizontalMargin, mAxisX.GetTickNumberWidth(canvas) / 2); return theXTickHorizontalMargin; } int iupPlot::CalcYTickVerticalMargin(cdCanvas* canvas, bool start) const { int theYTickVerticalMargin = 0; if (mAxisY.mShowArrow) { if ((!start && !mAxisY.mReverse) || ( start && mAxisY.mReverse)) theYTickVerticalMargin += mAxisY.GetArrowSize(); } if (mAxisY.mTick.mShow && mAxisY.mTick.mShowNumber) // Leave space for half number theYTickVerticalMargin = iupPlotMax(theYTickVerticalMargin, mAxisY.GetTickNumberHeight(canvas) / 2); return theYTickVerticalMargin; } int iupPlot::CalcXTickVerticalMargin(cdCanvas* canvas) const { int theXTickVerticalMargin = 0; if (mAxisX.mTick.mShow) { theXTickVerticalMargin += mAxisX.mTick.mMajorSize; if (mAxisX.mTick.mShowNumber) theXTickVerticalMargin += mAxisX.GetTickNumberHeight(canvas) + mAxisX.mTick.mMinorSize; // Use minor size as spacing } if (mAxisX.GetLabel()) { int theXFontHeight; SetFont(canvas, mAxisX.mFontStyle, mAxisX.mFontSize); cdCanvasGetFontDim(canvas, NULL, &theXFontHeight, NULL, NULL); theXTickVerticalMargin += theXFontHeight + theXFontHeight / 10; } return theXTickVerticalMargin; } int iupPlot::CalcYTickHorizontalMargin(cdCanvas* canvas) const { int theYTickHorizontalMargin = 0; if (mAxisY.mTick.mShow) { theYTickHorizontalMargin += mAxisY.mTick.mMajorSize; if (mAxisY.mTick.mShowNumber) theYTickHorizontalMargin += mAxisY.GetTickNumberWidth(canvas) + mAxisY.mTick.mMinorSize; // Use minor size as spacing } if (mAxisY.GetLabel()) { int theYFontHeight; SetFont(canvas, mAxisY.mFontStyle, mAxisY.mFontSize); cdCanvasGetFontDim(canvas, NULL, &theYFontHeight, NULL, NULL); theYTickHorizontalMargin += theYFontHeight + theYFontHeight / 10; } return theYTickHorizontalMargin; } void iupPlot::CalculateMargins(cdCanvas* canvas) { if (mBack.mMarginAuto.mTop) { mBack.mMargin.mTop = 0; if (mTitle.GetText() && mTitle.mAutoPos) // Affects only top margin mBack.mMargin.mTop += CalcTitleVerticalMargin(canvas); if (mAxisX.mShow && mAxisX.mPosition == IUP_PLOT_END) mBack.mMargin.mTop += CalcXTickVerticalMargin(canvas); if (mAxisY.mShow) mBack.mMargin.mTop = iupPlotMax(mBack.mMargin.mTop, CalcYTickVerticalMargin(canvas, false)); } if (mBack.mMarginAuto.mBottom) { mBack.mMargin.mBottom = 0; if (mAxisX.mShow && mAxisX.mPosition == IUP_PLOT_START) mBack.mMargin.mBottom += CalcXTickVerticalMargin(canvas); if (mAxisY.mShow) mBack.mMargin.mBottom = iupPlotMax(mBack.mMargin.mBottom, CalcYTickVerticalMargin(canvas, true)); } if (mBack.mMarginAuto.mLeft) { mBack.mMargin.mLeft = 0; if (mAxisY.mShow && mAxisY.mPosition == IUP_PLOT_START) mBack.mMargin.mLeft += CalcYTickHorizontalMargin(canvas); if (mAxisX.mShow) mBack.mMargin.mLeft = iupPlotMax(mBack.mMargin.mLeft, CalcXTickHorizontalMargin(canvas, true)); } if (mBack.mMarginAuto.mRight) { mBack.mMargin.mRight = 0; if (mAxisY.mShow && mAxisY.mPosition == IUP_PLOT_END) mBack.mMargin.mRight += CalcYTickHorizontalMargin(canvas); if (mAxisX.mShow) mBack.mMargin.mRight = iupPlotMax(mBack.mMargin.mRight, CalcXTickHorizontalMargin(canvas, false)); } } void iupPlot::CalculateXRange(double &outXMin, double &outXMax) const { bool theFirst = true; outXMin = 0; outXMax = 0; for (int ds = 0; ds < mDataSetListCount; ds++) { const iupPlotData *theXData = mDataSetList[ds]->GetDataX(); if (theXData->GetCount() == 0) continue; double theXMin; double theXMax; if (mDataSetList[ds]->mMode == IUP_PLOT_PIE) { theXMin = -1; theXMax = 1; } else if (!theXData->CalculateRange(theXMin, theXMax)) return; if (theFirst) { outXMin = theXMin; outXMax = theXMax; theFirst = false; } if (theXMax>outXMax) outXMax = theXMax; if (theXMinGetDataY(); double theYMin; double theYMax; if (mDataSetList[ds]->mMode == IUP_PLOT_PIE) { theYMin = -1; theYMax = 1; } else if (!theYData->CalculateRange(theYMin, theYMax)) return; if (theFirst) { outYMin = theYMin; outYMax = theYMax; theFirst = false; } if (theYMinoutYMax) outYMax = theYMax; } } bool iupPlot::CalculateAxisRange() { if (mAxisX.mAutoScaleMin || mAxisX.mAutoScaleMax) { double theXMin = 0.0; double theXMax = 1.0; CalculateXRange(theXMin, theXMax); if (mAxisX.mAutoScaleMin) { mAxisX.mMin = theXMin; if (mAxisX.mLogScale && (theXMin < kLogMinClipValue)) mAxisX.mMin = kLogMinClipValue; } if (mAxisX.mAutoScaleMax) mAxisX.mMax = theXMax; if (!mAxisX.mTickIter->AdjustRange(mAxisX.mMin, mAxisX.mMax)) return false; } if (mAxisY.mAutoScaleMin || mAxisY.mAutoScaleMax) { double theYMin = 0.0; double theYMax = 1.0; CalculateYRange(theYMin, theYMax); if (mAxisY.mAutoScaleMin) { mAxisY.mMin = theYMin; if (mAxisY.mLogScale && (theYMin < kLogMinClipValue)) mAxisY.mMin = kLogMinClipValue; } if (mAxisY.mAutoScaleMax) mAxisY.mMax = theYMax; if (!mAxisY.mTickIter->AdjustRange(mAxisY.mMin, mAxisY.mMax)) return false; } if (mScaleEqual) { if (mAxisY.HasZoom() || mAxisX.HasZoom()) { if (mAxisY.mMax - mAxisY.mMin != mAxisX.mMax - mAxisX.mMin) { double theLength; if (mAxisY.mMax - mAxisY.mMin > mAxisX.mMax - mAxisX.mMin) { theLength = mAxisY.mMax - mAxisY.mMin; mAxisX.mMax = mAxisX.mMin + theLength; } else { theLength = mAxisX.mMax - mAxisX.mMin; mAxisY.mMax = mAxisY.mMin + theLength; } } } else { double theMin = mAxisY.mMin; if (mAxisX.mMin < theMin) theMin = mAxisX.mMin; double theMax = mAxisY.mMax; if (mAxisX.mMax > theMax) theMax = mAxisX.mMax; mAxisX.mMin = theMin; mAxisY.mMin = theMin; mAxisX.mMax = theMax; mAxisY.mMax = theMax; } } return true; } bool iupPlot::CheckRange(const iupPlotAxis &inAxis) const { if (inAxis.mLogScale) { if (inAxis.mMin < kLogMinClipValue) return false; } return true; } bool iupPlot::CalculateXTransformation(const iupPlotRect &inRect) { return mAxisX.mTrafo->Calculate(inRect.mX, inRect.mX + inRect.mWidth, mAxisX); } bool iupPlot::CalculateYTransformation(const iupPlotRect &inRect) { return mAxisY.mTrafo->Calculate(inRect.mY, inRect.mY + inRect.mHeight, mAxisY); } void iupPlot::CalculateTickSize(cdCanvas* canvas, iupPlotTick &ioTick) { if (ioTick.mAutoSize) { int theFontHeight; SetFont(canvas, ioTick.mFontStyle, ioTick.mFontSize); cdCanvasGetFontDim(canvas, NULL, &theFontHeight, NULL, NULL); ioTick.mMajorSize = theFontHeight / 2; ioTick.mMinorSize = theFontHeight / 4; } } bool iupPlot::CalculateTickSpacing(const iupPlotRect &inRect, cdCanvas* canvas) { double theXRange = mAxisX.mMax - mAxisX.mMin; double theYRange = mAxisY.mMax - mAxisY.mMin; if (theXRange <= 0 || theYRange < 0) return false; // YRange can be 0, must adjust if (mAxisY.mAutoScaleMax && ((mAxisY.mMax != 0 && fabs(theYRange / mAxisY.mMax) < kRangeVerySmall) || theYRange == 0)) { double delta = 0.1; if (mAxisY.mMax != 0) delta *= fabs(mAxisY.mMax); mAxisY.mMax += delta; theYRange = mAxisY.mMax - mAxisY.mMin; } if (mAxisX.mTick.mAutoSpacing) { int theXFontHeight; SetFont(canvas, mAxisX.mTick.mFontStyle, mAxisX.mTick.mFontSize); cdCanvasGetFontDim(canvas, NULL, &theXFontHeight, NULL, NULL); int theTextWidth; cdCanvasGetTextSize(canvas, "12345", &theTextWidth, NULL); double theDivGuess = inRect.mWidth / (kMajorTickXInitialFac*theTextWidth); if (!mAxisX.mTickIter->CalculateSpacing(theXRange, theDivGuess, mAxisX.mTick)) return false; } if (mAxisY.mTick.mAutoSpacing) { int theYFontHeight; SetFont(canvas, mAxisY.mTick.mFontStyle, mAxisY.mTick.mFontSize); cdCanvasGetFontDim(canvas, NULL, &theYFontHeight, NULL, NULL); double theDivGuess = inRect.mHeight / (kMajorTickYInitialFac*theYFontHeight); if (!mAxisY.mTickIter->CalculateSpacing(theYRange, theDivGuess, mAxisY.mTick)) return false; } return true; }