improved and bugfixed handling of aspectRatio and its documentation

This commit is contained in:
jkriege2 2020-09-11 23:19:31 +02:00
parent fa7b08940e
commit 9a3f321f66
3 changed files with 114 additions and 66 deletions

View File

@ -441,11 +441,13 @@ void JKQTBasePlotter::zoomOut(double factor) {
void JKQTBasePlotter::setMaintainAspectRatio(bool value) {
maintainAspectRatio=value;
setAspectRatio(aspectRatio);
redrawPlot();
}
void JKQTBasePlotter::setMaintainAxisAspectRatio(bool value) {
maintainAxisAspectRatio=value;
setAspectRatio(axisAspectRatio);
redrawPlot();
}
@ -688,53 +690,42 @@ void JKQTBasePlotter::loadSettings(const QSettings &settings, const QString& gro
void JKQTBasePlotter::setXY(double xminn, double xmaxx, double yminn, double ymaxx){
void JKQTBasePlotter::correctXYRangeForAspectRatio(double& xminn, double& xmaxx, double& yminn, double& ymaxx) const {
if (xminn>xmaxx) std::swap(xminn,xmaxx);
if (yminn>ymaxx) std::swap(yminn,ymaxx);
if (maintainAspectRatio) {
if (xAxis->isLinearAxis() && yAxis->isLinearAxis()) {
const double mid=(yminn+ymaxx)/2.0;
const double w=fabs(xmaxx-xminn)/aspectRatio;
//qDebug()<<"mod y from "<<yminn<<"..."<<ymaxx<<" to "<<mid-w/2.0<<"..."<<mid+w/2.0;
yminn=mid-w/2.0;
ymaxx=mid+w/2.0;
} else if (xAxis->isLogAxis() && yAxis->isLogAxis()) {
const double mid=(log(yminn)+log(ymaxx))/2.0;
const double w=fabs(log(xmaxx)-log(xminn))/aspectRatio;
yminn=exp(mid-w/2.0);
ymaxx=exp(mid+w/2.0);
}
}
}
void JKQTBasePlotter::setXY(double xminn, double xmaxx, double yminn, double ymaxx) {
correctXYRangeForAspectRatio(xminn, xmaxx, yminn, ymaxx);
xAxis->setRange(xminn, xmaxx);
yAxis->setRange(yminn, ymaxx);
if (maintainAxisAspectRatio) {
if (xAxis->isLinearAxis() && yAxis->isLinearAxis()) {
const double mid=(yAxis->getMax()+yAxis->getMin())/2.0;
const double w=fabs(xmaxx-xminn)/axisAspectRatio;
yAxis->setRange(mid-w/2.0, mid+w/2.0);
} else if (xAxis->isLogAxis() && yAxis->isLogAxis()) {
const double mid=(log(yAxis->getMax())+log(yAxis->getMin()))/2.0;
const double w=fabs(log(xmaxx)-log(xminn))/axisAspectRatio;
yAxis->setRange(exp(mid-w/2.0), exp(mid+w/2.0));
}
}
if (emitSignals) emit zoomChangedLocally(xAxis->getMin(), xAxis->getMax(), yAxis->getMin(), yAxis->getMax(), this);
}
void JKQTBasePlotter::setX(double xminn, double xmaxx){
xAxis->setRange(xminn, xmaxx);
if (maintainAxisAspectRatio) {
if (xAxis->isLinearAxis() && yAxis->isLinearAxis()) {
const double mid=(yAxis->getMax()+yAxis->getMin())/2.0;
const double w=fabs(xmaxx-xminn)/axisAspectRatio;
yAxis->setRange(mid-w/2.0, mid+w/2.0);
} else if (xAxis->isLogAxis() && yAxis->isLogAxis()) {
const double mid=(log(yAxis->getMax())+log(yAxis->getMin()))/2.0;
const double w=fabs(log(xmaxx)-log(xminn))/axisAspectRatio;
yAxis->setRange(exp(mid-w/2.0), exp(mid+w/2.0));
}
}
if (emitSignals) emit zoomChangedLocally(xAxis->getMin(), xAxis->getMax(), yAxis->getMin(), yAxis->getMax(), this);
setXY(xminn, xmaxx, yAxis->getMin(), yAxis->getMax());
}
void JKQTBasePlotter::setY(double yminn, double ymaxx) {
yAxis->setRange(yminn, ymaxx);
if (maintainAxisAspectRatio) {
if (xAxis->isLinearAxis() && yAxis->isLinearAxis()) {
const double mid=(xAxis->getMax()+xAxis->getMin())/2.0;
const double w=fabs(ymaxx-yminn)*axisAspectRatio;
xAxis->setRange(mid-w/2.0, mid+w/2.0);
} else if (xAxis->isLogAxis() && yAxis->isLogAxis()) {
const double mid=(log(xAxis->getMax())+log(xAxis->getMin()))/2.0;
const double w=fabs(log(ymaxx)-log(yminn))/axisAspectRatio;
xAxis->setRange(exp(mid-w/2.0), exp(mid+w/2.0));
}
}
if (emitSignals) emit zoomChangedLocally(xAxis->getMin(), xAxis->getMax(), yAxis->getMin(), yAxis->getMax(), this);
setXY(xAxis->getMin(), xAxis->getMax(), yminn, ymaxx);
}
void JKQTBasePlotter::setAbsoluteX(double xminn, double xmaxx) {
@ -2394,6 +2385,7 @@ void JKQTBasePlotter::setAspectRatio(double __value)
{
if (jkqtp_approximatelyUnequal(this->aspectRatio , __value)) {
this->aspectRatio = __value;
setXY(getXMin(), getXMax(), getYMin(), getYMax());
redrawPlot();
}
}

View File

@ -167,7 +167,9 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPPaintDeviceAdapter {
*
* You can set two different aspect ratios:
* - The ratio of plotWidth/plotHeight (setAspectRatio(), setMaintainAspectRatio()) will keep the plots pixel-width and height at a certain value.
* \f[ \mbox{aspectRatio}=\frac{\mbox{plotWidth}}{\mbox{plotHeight}} \f]
* - The ratio of (xmax-xmin)/(ymax-ymin) (setAxisAspectRatio(), setMaintainAxisAspectRatio()) will keep the displayed axis ranges in a certain ratio.
* \f[ \mbox{axisAspectRatio}=\frac{\left|x_\text{max}-x_\text{min}\right|}{\left|y_\text{max}-y_\text{min}\right|} \f]
* .
* So to achieve different effects, use these combinations:
* - you have a 200x100 range where each 1x1-pixel should have an aspect ratio of 4:
@ -656,14 +658,14 @@ class JKQTPLOTTER_LIB_EXPORT JKQTBasePlotter: public QObject {
/** \copydoc JKQTBasePlotterStyle::plotBorderRight */
int getPlotBorderRight() const;
/** \brief returns whether the maintaining of the data aspect ratio is enabled or disabled */
/** \brief returns whether the maintaining of the data aspect ratio is enabled or disabled \see aspectRatio */
bool doesMaintainAspectRatio() const;
/** \brief returns the data aspect ratio, enforced with setMaintainApsectRatio(true) */
/** \brief returns the data aspect ratio, enforced with setMaintainApsectRatio(true) \see aspectRatio */
double getAspectRatio() const;
/** \brief returns whether the maintaining of the axis aspect ratio is enabled or disabled */
/** \brief returns whether the maintaining of the axis aspect ratio is enabled or disabled \see axisAspectRatio */
bool doesMaintainAxisAspectRatio() const;
/** \brief returns the axis aspect ratio, enforced with setMaintainAxisApsectRatio(true) */
/** \brief returns the axis aspect ratio, enforced with setMaintainAxisApsectRatio(true) \see axisAspectRatio */
double getAxisAspectRatio() const;
/** \copydoc JKQTBasePlotterStyle::useAntiAliasingForSystem */
bool isUsingAntiAliasingForSystem() const;
@ -1075,7 +1077,13 @@ class JKQTPLOTTER_LIB_EXPORT JKQTBasePlotter: public QObject {
QSizeF getTextSizeSize(const QString& fontName, double fontSize, const QString& text, QPainter &painter);
/** \brief takes a new axis range \a xminn ... \a xmaxx and \a yminn ... \a ymaxx and corrects the values to match the currently set axisAspectRatio
*
* This function is used by setXY(), setX(), setY().
*
* \see axisAspectRatio, setXY(), setX(), setY()
*/
void correctXYRangeForAspectRatio(double &xminn, double &xmaxx, double &yminn, double &ymaxx) const;
signals:
/** \brief signal: emitted whenever the user selects a new x-y zoom range (by mouse) */
void zoomChangedLocally(double newxmin, double newxmax, double newymin, double newymax, JKQTBasePlotter* sender);
@ -1391,10 +1399,10 @@ class JKQTPLOTTER_LIB_EXPORT JKQTBasePlotter: public QObject {
/** \brief zooms out of the graph (the same as turning the mouse wheel) by the given factor */
void zoomOut(double factor=2.0);
/** \brief en-/disables the maintaining of the data aspect ratio */
/** \brief en-/disables the maintaining of the data aspect ratio \see aspectRatio */
void setMaintainAspectRatio(bool value);
/** \brief en-/disables the maintaining of the axis aspect ratio */
/** \brief en-/disables the maintaining of the axis aspect ratio \see axisAspectRatio */
void setMaintainAxisAspectRatio(bool value);
/** \brief set filename and prefix, used by loadUserSettings() and saveUserSettings()
@ -1441,9 +1449,9 @@ class JKQTPLOTTER_LIB_EXPORT JKQTBasePlotter: public QObject {
/** \brief set all graphs invisible, except graph start, start+n, start+2*n, ... */
void setOnlyNthGraphsVisible(int start, int n);
/** \brief sets the data aspect ratio, enforced with setMaintainApsectRatio(true) */
/** \brief sets the data aspect ratio, enforced with setMaintainApsectRatio(true) \see aspectRatio */
void setAspectRatio(double __value);
/** \brief sets the axis aspect ratio, enforced with setMaintainAxisApsectRatio(true) */
/** \brief sets the axis aspect ratio, enforced with setMaintainAxisApsectRatio(true) \see axisAspectRatio */
void setAxisAspectRatio(double __value);
/*! \copydoc JKQTBasePlotterStyle::useAntiAliasingForSystem */
void setUseAntiAliasingForSystem(bool __value);
@ -1952,14 +1960,26 @@ class JKQTPLOTTER_LIB_EXPORT JKQTBasePlotter: public QObject {
*/
int internalPlotHeight;
/** \brief indicates whether the widget should maintain an aspect ratio of plotwidth and plotheight */
/** \brief indicates whether the widget should maintain an aspect ratio of plotwidth and plotheight
*
* \see aspectRatio
*/
bool maintainAspectRatio;
/** \brief the aspect ratio of plotwidth and plotheight to maintain, if \c maintainAspectRatio==true */
/** \brief the aspect ratio of plotwidth and plotheight to maintain, if \c maintainAspectRatio==true
*
* \f[ \mbox{aspectRatio}=\frac{\mbox{plotWidth}}{\mbox{plotHeight}} \f]
*
* \see maintainAspectRatio
*/
double aspectRatio;
/** \brief indicates whether the axes should maintain an aspect ratio
*
* \note An axis aspect ration is only well defined for linear axes (if both axes are linear).
* When the axis aspect ratio is to be maintained and new axis ranges are set (e.g. when calling setXY() ),
* the given axis ranges are modified, so
* \f[ \mbox{axisAspectRatio}=\frac{\left|x_\text{max}-x_\text{min}\right|}{\left|y_\text{max}-y_\text{min}\right|} \f]
*
* \note An axis aspect ratio is only well defined for linear axes (if both axes are linear).
* If both axes a logarithmic, the axis ration is defined for log(axismax)-log(axismin).
* For other combinations of axes, this function is deactivated
*
@ -1968,7 +1988,11 @@ class JKQTPLOTTER_LIB_EXPORT JKQTBasePlotter: public QObject {
bool maintainAxisAspectRatio;
/** \brief the aspect ratio of axis widths to maintain, if \c maintainAxisAspectRatio==true
*
* \note An axis aspect ration is only well defined for linear axes (if both axes are linear).
* When the axis aspect ratio is to be maintained and new axis ranges are set (e.g. when calling setXY() ),
* the given axis ranges are modified, so
* \f[ \mbox{axisAspectRatio}=\frac{\left|x_\text{max}-x_\text{min}\right|}{\left|y_\text{max}-y_\text{min}\right|} \f]
*
* \note An axis aspect ratio is only well defined for linear axes (if both axes are linear).
* If both axes a logarithmic, the axis ration is defined for log(axismax)-log(axismin).
* For other combinations of axes, this function is deactivated
*

View File

@ -484,16 +484,31 @@ void JKQTPlotter::paintUserAction() {
painter.setRenderHint(JKQTPEnhancedPainter::TextAntialiasing, true);
painter.setPen(plotterStyle.userActionOverlayPen);
if (jkqtp_approximatelyUnequal(mouseDragRectXEnd,mouseDragRectXStart) && jkqtp_approximatelyUnequal(mouseDragRectYEnd,mouseDragRectYStart)) {
double x1=plotter->x2p(mouseDragRectXStart)*magnification;
double y1=plotter->y2p(mouseDragRectYStart)*magnification;
double x2=plotter->x2p(mouseDragRectXEnd)*magnification;
double y2=plotter->y2p(mouseDragRectYEnd)*magnification;
double dx=x2-x1;
double dy=y2-y1;
if ((currentMouseDragAction.mode==jkqtpmdaZoomByRectangle) || (currentMouseDragAction.mode==jkqtpmdaDrawRectangleForEvent)) {
const double x1=plotter->x2p(mouseDragRectXStart)*magnification;
const double y1=plotter->y2p(mouseDragRectYStart)*magnification;
const double x2=plotter->x2p(mouseDragRectXEnd)*magnification;
const double y2=plotter->y2p(mouseDragRectYEnd)*magnification;
const double dx=x2-x1;
const double dy=y2-y1;
if (currentMouseDragAction.mode==jkqtpmdaDrawRectangleForEvent) {
painter.fillRect(QRectF(x1, y1, x2-x1, y2-y1), plotterStyle.userActionOverlayBrush);
painter.setPen(plotterStyle.userActionOverlayPen);
painter.drawRect(QRectF(x1, y1, x2-x1, y2-y1));
} else if (currentMouseDragAction.mode==jkqtpmdaZoomByRectangle) {
double xmin=mouseDragRectXStart;
double xmax=mouseDragRectXEnd;
double ymin=mouseDragRectYStart;
double ymax=mouseDragRectYEnd;
plotter->correctXYRangeForAspectRatio(xmin,xmax,ymin,ymax);
const double xz1=plotter->x2p(xmin)*magnification;
const double yz1=plotter->y2p(ymin)*magnification;
const double xz2=plotter->x2p(xmax)*magnification;
const double yz2=plotter->y2p(ymax)*magnification;
painter.fillRect(QRectF(xz1, yz1, xz2-xz1, yz2-yz1), plotterStyle.userActionOverlayBrush);
painter.setPen(plotterStyle.userActionOverlayPen);
painter.drawRect(QRectF(xz1, yz1, xz2-xz1, yz2-yz1));
} else if (currentMouseDragAction.mode==jkqtpmdaDrawCircleForEvent) {
painter.setPen(plotterStyle.userActionOverlayPen);
painter.setBrush(plotterStyle.userActionOverlayBrush);
@ -717,7 +732,13 @@ void JKQTPlotter::mouseMoveEvent ( QMouseEvent * event ) {
event->accept();
//std::cout<<mouseZoomingTStart<<" -- "<<mouseZoomingTEnd<<std::endl;
if (currentMouseDragAction.mode==jkqtpmdaZoomByRectangle) {
emit plotNewZoomRectangle(mouseDragRectXStart, mouseDragRectXEnd, mouseDragRectYStart, mouseDragRectYEnd, event->modifiers());
double xmin=mouseDragRectXStart;
double xmax=mouseDragRectXEnd;
double ymin=mouseDragRectYStart;
double ymax=mouseDragRectYEnd;
plotter->correctXYRangeForAspectRatio(xmin,xmax,ymin,ymax);
emit plotNewZoomRectangle(xmin,xmax,ymin,ymax, event->modifiers());
//emit plotNewZoomRectangle(mouseDragRectXStart, mouseDragRectXEnd, mouseDragRectYStart, mouseDragRectYEnd, event->modifiers());
}
if ((currentMouseDragAction.mode==jkqtpmdaScribbleForEvents) && (jkqtp_approximatelyUnequal(mouseDragRectXStart,mouseDragRectXEnd) || jkqtp_approximatelyUnequal(mouseDragRectYStart,mouseDragRectYEnd)) ) {
emit userScribbleClick(mouseDragRectXEnd, mouseDragRectYEnd, event->modifiers(), false, false);
@ -816,6 +837,9 @@ void JKQTPlotter::mouseReleaseEvent ( QMouseEvent * event ){
double ymin=mouseDragRectYStart;
double ymax=mouseDragRectYEnd;
plotter->correctXYRangeForAspectRatio(xmin,xmax,ymin,ymax);
emit zoomChangedLocally(xmin, xmax, ymin, ymax, this);
plotter->setXY(xmin, xmax, ymin, ymax);
} else if (currentMouseDragAction.mode==jkqtpmdaPanPlotOnRelease) {
@ -924,6 +948,14 @@ void JKQTPlotter::keyReleaseEvent(QKeyEvent *event) {
}
void JKQTPlotter::wheelEvent ( QWheelEvent * event ) {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
const double wheel_x=event->position().x();
const double wheel_y=event->position().y();
#else
const int wheel_x=event->x();
const int wheel_y=event->y();
#endif
//qDebug()<<"wheelEvent("<<event->modifiers()<<"): plotterStyle.registeredMouseWheelActions="<<plotterStyle.registeredMouseWheelActions;
auto itAction=findMatchingMouseWheelAction(event->modifiers());
//qDebug()<<"wheelEvent("<<event->modifiers()<<"): plotterStyle.registeredMouseWheelActions="<<plotterStyle.registeredMouseWheelActions;
@ -934,14 +966,14 @@ void JKQTPlotter::wheelEvent ( QWheelEvent * event ) {
//if (act==JKQTPMouseWheelActions::jkqtpmwaZoomByWheel) {
//qDebug()<<"wheelEvent("<<event->modifiers()<<"):ZoomByWheel";
const double factor=pow(2.0, 1.0*static_cast<double>(event->angleDelta().y())/120.0)*2.0;
double xmin=plotter->p2x(static_cast<double>(event->x())/magnification-static_cast<double>(plotter->getPlotWidth())/factor);
double xmax=plotter->p2x(static_cast<double>(event->x())/magnification+static_cast<double>(plotter->getPlotWidth())/factor);
double ymin=plotter->p2y(static_cast<double>(event->y())/magnification-static_cast<double>(getPlotYOffset())+static_cast<double>(plotter->getPlotHeight())/factor);
double ymax=plotter->p2y(static_cast<double>(event->y())/magnification-static_cast<double>(getPlotYOffset())-static_cast<double>(plotter->getPlotHeight())/factor);
if ( (event->x()/magnification<plotter->getInternalPlotBorderLeft()) || (event->x()/magnification>plotter->getPlotWidth()+plotter->getInternalPlotBorderLeft()) ) {
double xmin=plotter->p2x(static_cast<double>(wheel_x)/magnification-static_cast<double>(plotter->getPlotWidth())/factor);
double xmax=plotter->p2x(static_cast<double>(wheel_x)/magnification+static_cast<double>(plotter->getPlotWidth())/factor);
double ymin=plotter->p2y(static_cast<double>(wheel_y)/magnification-static_cast<double>(getPlotYOffset())+static_cast<double>(plotter->getPlotHeight())/factor);
double ymax=plotter->p2y(static_cast<double>(wheel_y)/magnification-static_cast<double>(getPlotYOffset())-static_cast<double>(plotter->getPlotHeight())/factor);
if ( (wheel_x/magnification<plotter->getInternalPlotBorderLeft()) || (wheel_x/magnification>plotter->getPlotWidth()+plotter->getInternalPlotBorderLeft()) ) {
xmin=getXMin();
xmax=getXMax();
} else if (((event->y()-getPlotYOffset())/magnification<plotter->getInternalPlotBorderTop()) || ((event->y()-getPlotYOffset())/magnification>plotter->getPlotHeight()+plotter->getInternalPlotBorderTop()) ) {
} else if (((wheel_y-getPlotYOffset())/magnification<plotter->getInternalPlotBorderTop()) || ((wheel_y-getPlotYOffset())/magnification>plotter->getPlotHeight()+plotter->getInternalPlotBorderTop()) ) {
ymin=getYMin();
ymax=getYMax();
}
@ -960,9 +992,9 @@ void JKQTPlotter::wheelEvent ( QWheelEvent * event ) {
if (d.x()<0 && d.x()>-10) d.setX(-10);
if (d.y()>=0 && d.y()<10) d.setY(10);
if (d.y()<0 && d.y()>-10) d.setY(-10);
if ( (event->x()/magnification<plotter->getInternalPlotBorderLeft()) || (event->x()/magnification>plotter->getPlotWidth()+plotter->getInternalPlotBorderLeft()) ) {
if ( (wheel_x/magnification<plotter->getInternalPlotBorderLeft()) || (wheel_x/magnification>plotter->getPlotWidth()+plotter->getInternalPlotBorderLeft()) ) {
zoomRect.translate(0, d.y());
} else if (((event->y()-getPlotYOffset())/magnification<plotter->getInternalPlotBorderTop()) || ((event->y()-getPlotYOffset())/magnification>plotter->getPlotHeight()+plotter->getInternalPlotBorderTop()) ) {
} else if (((wheel_y-getPlotYOffset())/magnification<plotter->getInternalPlotBorderTop()) || ((wheel_y-getPlotYOffset())/magnification>plotter->getPlotHeight()+plotter->getInternalPlotBorderTop()) ) {
zoomRect.translate(d.x(), 0);
} else {
zoomRect.translate(d.x(), d.y());
@ -974,7 +1006,7 @@ void JKQTPlotter::wheelEvent ( QWheelEvent * event ) {
event->accept();
emit plotMouseWheelOperated(plotter->p2x(event->x()), plotter->p2x(event->y()), event->modifiers(), event->angleDelta().x(), event->angleDelta().y());
emit plotMouseWheelOperated(plotter->p2x(wheel_x), plotter->p2x(wheel_y), event->modifiers(), event->angleDelta().x(), event->angleDelta().y());
updateCursor();
currentMouseDragAction.clear();