24 #include "KDChartCartesianCoordinatePlane_p.h" 27 #include "KDChartAbstractDiagram_p.h" 29 #include "CartesianCoordinateTransformation.h" 32 #include "KDChartPainterSaver_p.h" 36 #include <KDABLibFakes> 38 #include <QApplication> 50 CartesianCoordinatePlane::Private::Private()
52 , bPaintIsRunning( false )
53 , hasOwnGridAttributesHorizontal( false )
54 , hasOwnGridAttributesVertical( false )
55 , isometricScaling( false )
60 , autoAdjustHorizontalRangeToData( 67 )
61 , autoAdjustVerticalRangeToData( 67 )
62 , autoAdjustGridToZoom( true )
63 , fixedDataCoordinateSpaceRelation( false )
64 , xAxisStartAtZero( true )
65 , reverseVerticalPlane( false )
66 , reverseHorizontalPlane( false )
70 CartesianCoordinatePlane::CartesianCoordinatePlane(
Chart* parent )
81 void CartesianCoordinatePlane::init()
89 Q_ASSERT_X( dynamic_cast<AbstractCartesianDiagram*>( diagram ),
90 "CartesianCoordinatePlane::addDiagram",
"Only cartesian " 91 "diagrams can be added to a cartesian coordinate plane!" );
103 if (
d->bPaintIsRunning ) {
106 d->bPaintIsRunning =
true;
109 if ( !diags.isEmpty() )
118 PainterSaver painterSaver( painter );
119 QRect clipRect = drawArea.toRect().adjusted( -1, -1, 1, 1 );
120 QRegion clipRegion( clipRect );
121 painter->setClipRegion( clipRegion );
124 d->grid->drawGrid( &ctx );
127 for (
int i = 0; i < diags.size(); i++ )
129 if ( diags[i]->isHidden() ) {
132 bool doDumpPaintTime = AbstractDiagram::Private::get( diags[ i ] )->doDumpPaintTime;
134 if ( doDumpPaintTime ) {
138 PainterSaver diagramPainterSaver( painter );
139 diags[i]->paint( &ctx );
141 if ( doDumpPaintTime ) {
142 qDebug() <<
"Painting diagram" << i <<
"took" << stopWatch.elapsed() <<
"milliseconds";
147 d->bPaintIsRunning =
false;
163 bool bStarting =
true;
168 if ( bStarting || dataBoundariesPair.first.x() < minX ) minX = dataBoundariesPair.first.x();
169 if ( bStarting || dataBoundariesPair.first.y() < minY ) minY = dataBoundariesPair.first.y();
170 if ( bStarting || dataBoundariesPair.second.x() > maxX ) maxX = dataBoundariesPair.second.x();
171 if ( bStarting || dataBoundariesPair.second.y() > maxY ) maxY = dataBoundariesPair.second.y();
175 QRectF dataBoundingRect;
176 dataBoundingRect.setBottomLeft( QPointF( minX, minY ) );
177 dataBoundingRect.setTopRight( QPointF( maxX, maxY ) );
178 return dataBoundingRect;
183 const QRectF& r,
unsigned int percentX,
unsigned int percentY )
const 187 const bool isPositive = r.left() >= 0;
188 if ( ( r.right() >= 0 ) == isPositive ) {
189 qreal upperBound = qMax( r.left(), r.right() );
190 qreal lowerBound = qMin( r.left(), r.right() );
191 qreal innerBound = isPositive ? lowerBound : upperBound;
192 qreal outerBound = isPositive ? upperBound : lowerBound;
193 if ( innerBound / outerBound * 100 <= percentX &&
d->xAxisStartAtZero ) {
204 const bool isPositive = r.bottom() >= 0;
205 if ( ( r.top() >= 0 ) == isPositive ) {
206 qreal upperBound = qMax( r.top(), r.bottom() );
207 qreal lowerBound = qMin( r.top(), r.bottom() );
208 const qreal innerBound = isPositive ? lowerBound : upperBound;
209 const qreal outerBound = isPositive ? upperBound : lowerBound;
210 if ( innerBound / outerBound * 100 <= percentY ) {
212 ret.setBottom( 0.0 );
226 const bool bAutoAdjustHorizontalRange =
d->autoAdjustHorizontalRangeToData < 100;
227 const bool bAutoAdjustVerticalRange =
d->autoAdjustVerticalRangeToData < 100;
229 const bool bHardHorizontalRange = (!bAutoAdjustHorizontalRange) && (
d->horizontalMin !=
d->horizontalMax || (ISNAN(
d->horizontalMin) != ISNAN(
d->horizontalMax)));
230 const bool bHardVerticalRange = (!bAutoAdjustVerticalRange) && (
d->verticalMin !=
d->verticalMax || (ISNAN(
d->verticalMin) != ISNAN(
d->verticalMax)));
231 QRectF dataBoundingRect;
234 if ( bHardHorizontalRange && bHardVerticalRange ) {
235 dataBoundingRect.setLeft(
d->horizontalMin );
236 dataBoundingRect.setRight(
d->horizontalMax );
237 dataBoundingRect.setBottom(
d->verticalMin );
238 dataBoundingRect.setTop(
d->verticalMax );
242 if ( bHardHorizontalRange ) {
243 if (!ISNAN(
d->horizontalMin))
244 dataBoundingRect.setLeft(
d->horizontalMin );
245 if (!ISNAN(
d->horizontalMax))
246 dataBoundingRect.setRight(
d->horizontalMax );
248 if ( bHardVerticalRange ) {
249 if (!ISNAN(
d->verticalMin))
250 dataBoundingRect.setBottom(
d->verticalMin );
251 if (!ISNAN(
d->verticalMax))
252 dataBoundingRect.setTop(
d->verticalMax );
258 dataBoundingRect,
d->autoAdjustHorizontalRangeToData,
d->autoAdjustVerticalRangeToData );
259 if ( bAutoAdjustHorizontalRange ) {
263 if ( bAutoAdjustVerticalRange ) {
268 return dataBoundingRect;
286 const Qt::Orientation diagramOrientation = barDiagram != 0 ? barDiagram->
orientation() : Qt::Vertical;
287 const bool diagramIsVertical = diagramOrientation == Qt::Vertical;
300 diagramIsVertical ? ( !stockDiagram && dgr->
datasetDimension() > 1 ) :
true,
329 return QRectF(
areaGeometry() ).adjusted( 1.0, 1.0, -2.0, -2.0 );
335 if (
d->dimensions.isEmpty() )
340 const QPointF pt( qMin( dimX.
start, dimX.
end ), qMax( dimY.
start, dimY.
end ) );
342 const QRectF dataBoundingRect( pt, siz );
345 const QPointF topLeft(
d->reverseHorizontalPlane ? dataBoundingRect.right() : dataBoundingRect.left(),
346 d->reverseVerticalPlane ? dataBoundingRect.bottom() : dataBoundingRect.top() );
348 const qreal width = dataBoundingRect.width() * (
d->reverseHorizontalPlane ? -1.0 : 1.0 );
349 const qreal height = dataBoundingRect.height() * (
d->reverseVerticalPlane ? -1.0 : 1.0 );
351 return QRectF( topLeft, QSizeF( width, height ) );
357 QPointF physicalTopLeft =
d->coordinateTransformation.translate( logArea.topLeft() );
358 QPointF physicalBottomRight =
d->coordinateTransformation.translate( logArea.bottomRight() );
360 return QRectF( physicalTopLeft, physicalBottomRight ).normalized();
371 Q_ASSERT_X (
d->dimensions.count() == 2,
"CartesianCoordinatePlane::layoutDiagrams",
372 "Error: gridDimensionsList() did not return exactly two dimensions." );
384 d->coordinateTransformation.updateTransform( logArea, physicalArea );
391 d->fixedDataCoordinateSpaceRelation = fixed;
392 d->fixedDataCoordinateSpaceRelationPinnedSize = QSize();
398 return d->fixedDataCoordinateSpaceRelation;
403 if (
d->xAxisStartAtZero == fixedStart)
406 d->xAxisStartAtZero = fixedStart;
411 return d->xAxisStartAtZero;
416 if ( !
d->fixedDataCoordinateSpaceRelation ) {
420 if ( !geometry.isValid() ) {
427 if ( !
d->fixedDataCoordinateSpaceRelationPinnedSize.isValid() ) {
428 d->fixedDataCoordinateSpaceRelationPinnedSize = geometry.size();
434 if (
d->fixedDataCoordinateSpaceRelationPinnedSize != geometry.size() ) {
435 const qreal widthScaling =
d->fixedDataCoordinateSpaceRelationPinnedSize.width() / geometry.width();
436 const qreal heightScaling =
d->fixedDataCoordinateSpaceRelationPinnedSize.height() / geometry.height();
438 const qreal newZoomX =
d->fixedDataCoordinateSpaceRelationPinnedZoom.xFactor * widthScaling;
439 const qreal newZoomY =
d->fixedDataCoordinateSpaceRelationPinnedZoom.yFactor * heightScaling;
441 const QPointF newCenter = QPointF(
d->fixedDataCoordinateSpaceRelationPinnedZoom.xCenter / widthScaling,
442 d->fixedDataCoordinateSpaceRelationPinnedZoom.yCenter / heightScaling );
444 bool changed =
false;
462 return d->coordinateTransformation.translate( diagramPoint );
467 return d->coordinateTransformation.translateBack( screenPoint );
472 if (
d->isometricScaling != isOn ) {
473 d->isometricScaling = isOn;
481 return d->isometricScaling;
486 if (
d->coordinateTransformation.zoom.xFactor == factor ) {
489 d->coordinateTransformation.zoom.xFactor = factor;
490 if (
d->autoAdjustGridToZoom ) {
491 d->grid->setNeedRecalculate();
498 if (
d->coordinateTransformation.zoom.yFactor == factor ) {
501 d->coordinateTransformation.zoom.yFactor = factor;
502 if (
d->autoAdjustGridToZoom ) {
503 d->grid->setNeedRecalculate();
510 if (
d->coordinateTransformation.zoom.center() == point ) {
513 d->coordinateTransformation.zoom.setCenter( point );
514 if (
d->autoAdjustGridToZoom ) {
515 d->grid->setNeedRecalculate();
554 return d->coordinateTransformation.zoom.center();
559 return d->coordinateTransformation.zoom.xFactor;
564 return d->coordinateTransformation.zoom.yFactor;
570 return d->coordinateTransformation.axesCalcModeY;
575 return d->coordinateTransformation.axesCalcModeX;
580 if (
d->coordinateTransformation.axesCalcModeY != mode ||
581 d->coordinateTransformation.axesCalcModeX != mode ) {
582 d->coordinateTransformation.axesCalcModeY = mode;
583 d->coordinateTransformation.axesCalcModeX = mode;
593 if (
d->coordinateTransformation.axesCalcModeY != mode ) {
594 d->coordinateTransformation.axesCalcModeY = mode;
603 if (
d->coordinateTransformation.axesCalcModeX != mode ) {
604 d->coordinateTransformation.axesCalcModeX = mode;
611 inline bool fuzzyCompare( qreal a, qreal b )
613 if ( ISNAN(a) && ISNAN(b) )
615 if ( qFuzzyIsNull(a) && qFuzzyIsNull(b) )
617 return qFuzzyCompare( a, b );
623 if ( !fuzzyCompare(
d->horizontalMin, range.first) || !fuzzyCompare(
d->horizontalMax, range.second) ) {
624 d->autoAdjustHorizontalRangeToData = 100;
625 d->horizontalMin = range.first;
626 d->horizontalMax = range.second;
635 if ( !fuzzyCompare(
d->verticalMin, range.first) || !fuzzyCompare(
d->verticalMax, range.second) ) {
636 d->autoAdjustVerticalRangeToData = 100;
637 d->verticalMin = range.first;
638 d->verticalMax = range.second;
658 d->horizontalMin = dataBoundingRect.left();
659 d->horizontalMax = dataBoundingRect.right();
660 d->verticalMin = dataBoundingRect.top();
661 d->verticalMax = dataBoundingRect.bottom();
669 d->horizontalMin = dataBoundingRect.left();
670 d->horizontalMax = dataBoundingRect.right();
678 d->verticalMin = dataBoundingRect.bottom();
679 d->verticalMax = dataBoundingRect.top();
686 if (
d->autoAdjustHorizontalRangeToData != percentEmpty )
688 d->autoAdjustHorizontalRangeToData = percentEmpty;
689 d->horizontalMin = 0.0;
690 d->horizontalMax = 0.0;
698 if (
d->autoAdjustVerticalRangeToData != percentEmpty )
700 d->autoAdjustVerticalRangeToData = percentEmpty;
701 d->verticalMin = 0.0;
702 d->verticalMax = 0.0;
710 return d->autoAdjustHorizontalRangeToData;
715 return d->autoAdjustVerticalRangeToData;
719 Qt::Orientation orientation,
722 if ( orientation == Qt::Horizontal )
723 d->gridAttributesHorizontal = a;
725 d->gridAttributesVertical = a;
726 setHasOwnGridAttributes( orientation,
true );
733 setHasOwnGridAttributes( orientation,
false );
740 if ( orientation == Qt::Horizontal )
741 return d->gridAttributesHorizontal;
743 return d->gridAttributesVertical;
749 void CartesianCoordinatePlane::setHasOwnGridAttributes( Qt::Orientation orientation,
bool on )
751 if ( orientation == Qt::Horizontal )
752 d->hasOwnGridAttributesHorizontal = on;
754 d->hasOwnGridAttributesVertical = on;
760 return orientation == Qt::Horizontal ?
d->hasOwnGridAttributesHorizontal
761 :
d->hasOwnGridAttributesVertical;
766 if (
d->autoAdjustGridToZoom != autoAdjust ) {
767 d->autoAdjustGridToZoom = autoAdjust;
768 d->grid->setNeedRecalculate();
773 #if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE) 778 return d->autoAdjustGridToZoom;
793 if ( p != 0 && p !=
this )
801 if ( plane ==
this || painter == 0 )
804 const QPointF zero = QPointF( 0, 0 );
805 const QPointF tenX = QPointF( 10, 0 );
806 const QPointF tenY = QPointF( 0, 10 );
811 painter->translate(
translate( zero ).x(), 0.0 );
813 painter->scale( factor, 1.0 );
814 painter->translate( -plane->
translate( zero ).x(), 0.0 );
818 painter->translate( 0.0,
translate( zero ).y() );
820 painter->scale( 1.0, factor );
821 painter->translate( 0.0, -plane->
translate( zero ).y() );
830 if (
d->reverseHorizontalPlane == reverse )
833 d->reverseHorizontalPlane = reverse;
840 return d->reverseHorizontalPlane;
845 if (
d->reverseVerticalPlane == reverse )
848 d->reverseVerticalPlane = reverse;
855 return d->reverseVerticalPlane;
865 result.setBottomRight(
translateBack( drawArea.bottomRight() ) );
876 d->geometry = rectangle;
877 if (
d->isometricScaling ) {
881 if ( hfw < rectangle.height() ) {
882 d->geometry.setHeight( hfw );
884 d->geometry.setWidth( qRound( qreal( rectangle.width() ) *
885 qreal( rectangle.height() ) / qreal( hfw ) ) );
892 diagram->
resize(
d->geometry.size() );
899 return d->isometricScaling ? Qt::Horizontal : ( Qt::Horizontal | Qt::Vertical );
904 return d->isometricScaling;
913 return qRound( qreal( w ) * qAbs( qreal( dataRect.height() ) / qreal( dataRect.width() ) ) );
919 if (
d->isometricScaling ) {
921 sh =
d->geometry.size();
void handleFixedDataCoordinateSpaceRelation(const QRectF &geometry)
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane, TernaryCoordinatePlane.
QSize sizeHint() const
pure virtual in QLayoutItem
Qt::Orientations expandingDirections() const
pure virtual in QLayoutItem
virtual void setZoomFactorX(qreal factor)
bool isVerticalRangeReversed() const
void setIsometricScaling(bool onOff)
If onOff is true, enforce that X and Y distances are scaled by the same factor.
virtual DataDimensionsList getDataDimensionsList() const
unsigned int autoAdjustVerticalRangeToData() const
Returns the maximal allowed percent of the vertical space covered by the coordinate plane that may be...
void setPainter(QPainter *painter)
virtual QPointF zoomCenter() const
const QPointF translate(const QPointF &diagramPoint) const
Translate the given point in value space coordinates to a position in pixel space.
void setHorizontalRangeReversed(bool reverse)
Sets whether the horizontal range should be reversed or not, i.e.
void resetGridAttributes(Qt::Orientation orientation)
Reset the attributes to be used for grid lines drawn in horizontal direction (or in vertical directio...
A chart with one or more diagrams.
void setAxesCalcModeY(AxesCalcMode mode)
Specifies the calculation mode for all Ordinate axes.
ZoomParameters stores the center and the factor of zooming internally.
void setAutoAdjustVerticalRangeToData(unsigned int percentEmpty=67)
Automatically adjust vertical range settings to the ranges covered by the model's values...
void adjustHorizontalRangeToData()
Adjust horizontal range settings to the ranges covered by the model's data values.
QRectF diagramArea() const
Returns the (physical) area occupied by the diagram.
virtual void paint(QPainter *)
reimpl
const QPointF translateBack(const QPointF &screenPoint) const
void slotLayoutChanged(AbstractDiagram *)
QPair< qreal, qreal > verticalRange() const
virtual void setZoomFactorY(qreal factor)
const GridAttributes gridAttributes(Qt::Orientation orientation) const
virtual void setZoomFactors(qreal factorX, qreal factorY)
void viewportCoordinateSystemChanged()
Emitted upon change of the view coordinate system.
virtual QRectF drawingArea() const
virtual void resize(const QSizeF &area)=0
Called by the widget's sizeEvent.
unsigned int autoAdjustHorizontalRangeToData() const
Returns the maximal allowed percent of the horizontal space covered by the coordinate plane that may ...
qreal gridSubStepWidth() const
Returns the sub-step width to be used for calculating the sub-grid lines.
virtual QRectF calculateRawDataBoundingRect() const
virtual QSize sizeHint() const
pure virtual in QLayoutItem
virtual QRect areaGeometry() const
AbstractCoordinatePlane * sharedAxisMasterPlane(QPainter *p=0)
reimpl
QRectF adjustedToMaxEmptyInnerPercentage(const QRectF &r, unsigned int percentX, unsigned int percentY) const
BarDiagram defines a common bar diagram.
virtual qreal zoomFactorX() const
const bool autoAdjustGridToZoom() const
Return the status of the built-in grid adjusting feature.
void update()
Calling update() on the plane triggers the global KDChart::Chart::update()
void setXAxisStartAtZero(bool fixedStart)
Allows to fix the lower bound of X axis to zero when diagram is in first quadrant.
AbstractDiagram defines the interface for diagram classes.
void setGridAttributes(Qt::Orientation orientation, const GridAttributes &)
Set the attributes to be used for grid lines drawn in horizontal direction (or in vertical direction...
const QPair< QPointF, QPointF > dataBoundaries() const
Return the bottom left and top right data point, that the diagram will display (unless the grid adjus...
bool xAxisStartAtZero() const
void setAutoAdjustHorizontalRangeToData(unsigned int percentEmpty=67)
Automatically adjust horizontal range settings to the ranges covered by the model's values...
bool isHorizontalRangeReversed() const
The class for cartesian axes.
void setFixedDataCoordinateSpaceRelation(bool fixed)
Allows to specify a fixed data-space / coordinate-space relation.
QRectF visibleDiagramArea() const
Returns the visible part of the diagram area, i.e.
bool doneSetZoomFactorX(qreal factor)
void setHorizontalRange(const QPair< qreal, qreal > &range)
Set the boundaries of the visible value space displayed in horizontal direction.
AbstractDiagram * diagram()
qreal gridStepWidth() const
Returns the step width to be used for calculating the grid lines.
bool hasHeightForWidth() const
virtual void setGeometry(const QRect &r)
pure virtual in QLayoutItem
virtual bool isOrdinate() const
virtual AbstractCartesianDiagram * referenceDiagram() const
QPair< qreal, qreal > horizontalRange() const
virtual KDChart::CartesianAxisList axes() const
void addDiagram(AbstractDiagram *diagram)
Adds a diagram to this coordinate plane.
bool hasFixedDataCoordinateSpaceRelation() const
virtual bool isAbscissa() const
bool doneSetZoomCenter(const QPointF ¢er)
Qt::Orientation orientation() const
bool hasOwnGridAttributes(Qt::Orientation orientation) const
void setVerticalRangeReversed(bool reverse)
Sets whether the vertical range should be reversed or not, i.e.
Base class for diagrams based on a cartesian coordianate system.
Stores information about painting diagrams.
virtual QRect geometry() const
pure virtual in QLayoutItem
virtual qreal zoomFactorY() const
void setVerticalRange(const QPair< qreal, qreal > &range)
Set the boundaries of the visible value space displayed in vertical direction.
KDChartEnums::GranularitySequence gridGranularitySequence() const
Returns the granularity sequence to be used for calculating the grid lines.
int heightForWidth(int w) const
AxesCalcMode axesCalcModeY() const
void adjustRangesToData()
Adjust both, horizontal and vertical range settings to the ranges covered by the model's data values...
void layoutDiagrams()
Distribute the available space among the diagrams and axes.
A set of attributes controlling the appearance of grids.
AxesCalcMode axesCalcModeX() const
void setGeometry(const QRect &r)
reimplemented from AbstractCoordinatePlane
DataDimensionsList gridDimensionsList()
Returns the dimensions used for drawing the grid lines.
void setAxesCalcModeX(AxesCalcMode mode)
Specifies the calculation mode for all Abscissa axes.
virtual void setZoomCenter(const QPointF ¢er)
qreal distance() const
Returns the size of the distance, equivalent to the width() (or height(), resp.) of a QRectF...
void propertiesChanged()
Emitted upon change of a property of the Coordinate Plane or any of its components.
void setAxesCalcModes(AxesCalcMode mode)
Specifies the calculation modes for all axes.
GridAttributes globalGridAttributes() const
Cartesian coordinate plane.
void setCoordinatePlane(AbstractCoordinatePlane *plane)
QRectF getRawDataBoundingRectFromDiagrams() const
void setRectangle(const QRectF &rect)
AbstractDiagramList diagrams()
virtual void addDiagram(AbstractDiagram *diagram)
Adds a diagram to this coordinate plane.
Helper class for one dimension of data, e.g.
void adjustVerticalRangeToData()
Adjust vertical range settings to the ranges covered by the model's data values.
void setAutoAdjustGridToZoom(bool autoAdjust)
Disable / re-enable the built-in grid adjusting feature.
~CartesianCoordinatePlane()
int datasetDimension() const
The dataset dimension of a diagram determines how many value dimensions it expects each datapoint to ...
QRectF visibleDataRange() const
Returns the currently visible data range.
const AbstractCoordinatePlane * coordinatePlane() const
Convenience function, returns the coordinate plane, in which this axis is used.
void setGridNeedsRecalculate()
Used by the chart to clear the cached grid data.
QRectF logicalArea() const
Returns the logical area, i.e., the rectangle defined by the very top left and very bottom right coor...
bool doneSetZoomFactorY(qreal factor)
bool doesIsometricScaling() const