JKQTPVectorFieldGraph gained the option to also scale the line width with the vector length/magnitude

This commit is contained in:
jkriege2 2024-02-09 16:45:40 +01:00
parent 4d58448d17
commit 4e29109937
8 changed files with 115 additions and 11 deletions

View File

@ -274,7 +274,7 @@ if(JKQtPlotter_BUILD_EXAMPLES)
boxplot/JKQTPBoxplotVerticalGraph,JKQTPBoxplotHorizontalGraph/--iteratefunctorsteps--iteratefunctorsteps_suppressinitial--smallscreenshotplot
second_axis/JKQTBasePlotter_addSecondaryYAxis,JKQTBasePlotter_addSecondaryXAxis
graphlabels/JKQTPGLabelAwayFromXAxis,JKQTPGLabelAwayFromYAxis,JKQTPGLabelTowardsXAxis,JKQTPGLabelTowardsYAxis,JKQTPGLabelAboveData,JKQTPGLabelRightHandSide,JKQTPGLabelBelowData,JKQTPGLabelLeftHandSide,JKQTPGLSimpleBox,JKQTPGLSimpleBoxVertical,JKQTPGLSimpleBoxAndLine,JKQTPGLSimpleBoxAndLineVertical,JKQTPGLSimpleBoxAndLineONLYLABELS,JKQTPGLSimpleBoxAndLineONLYLABELSVertical/--iteratefunctorsteps--smallscreenshotplot
vectorfield/JKQTPVectorFieldGraph,JKQTPVectorFieldGraphAnchorBottom,JKQTPVectorFieldGraphAnchorMid,JKQTPVectorFieldGraphAnchorTip,JKQTPVectorFieldGraphAutoscaleLength,JKQTPVectorFieldGraphLengthFromData,JKQTPVectorFieldGraphIgnoreLength/--iteratefunctorsteps
vectorfield/JKQTPVectorFieldGraph,JKQTPVectorFieldGraphAnchorBottom,JKQTPVectorFieldGraphAnchorMid,JKQTPVectorFieldGraphAnchorTip,JKQTPVectorFieldGraphAutoscaleLength,JKQTPVectorFieldGraphLengthFromData,JKQTPVectorFieldGraphIgnoreLength,JKQTPVectorFieldGraphIgnoreLengthAutoscaleLineWidthFromLength,JKQTPVectorFieldGraphAutoscaleLengthAutoscaleLineWidthFromLength/--iteratefunctorsteps
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
doc/images/icon_code_16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -53,3 +53,15 @@ Alternatively you can also set
which will draw all vectors with the same length. You can scale this length by setting JKQTPVectorFieldGraph::setAutoscaleLengthFactor() ). The result then looks like this:
![vectorfield](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/doc/images/JKQTPVectorFieldGraphIgnoreLength.png)
Finally it is also possibly to scale the vector's line width with its length:
```.cpp
graph1->setVectorLengthMode(JKQTPVectorFieldGraph::AutoscaleLength);
graph1->setVectorLineWidthMode(JKQTPVectorFieldGraph::AutoscaleLineWidthFromLength);
```
This will result in a plot like this:
![vectorfield](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/doc/images/JKQTPVectorFieldGraphAutoscaleLengthAutoscaleLineWidthFromLength.png)

View File

@ -61,9 +61,9 @@ int main(int argc, char* argv[])
plot.resize(400/plot.devicePixelRatioF(),430/plot.devicePixelRatioF());
JKQTPXYScatterGraph* g2;
app.addExportStepFunctor([&](){
JKQTPXYScatterGraph* g2=new JKQTPXYScatterGraph(&plot);
g2=new JKQTPXYScatterGraph(&plot);
g2->setXYColumns(columnXY);
g2->setTitle("anchor points");
g2->setSymbolSize(5);
@ -97,5 +97,23 @@ int main(int argc, char* argv[])
plot.redrawPlot();
});
app.addExportStepFunctor([&](){
g2->setVisible(false);
graph1->setAnchorPoint(JKQTPVectorFieldGraph::AnchorBottom);
graph1->setVectorLengthMode(JKQTPVectorFieldGraph::IgnoreLength);
graph1->setVectorLineWidthMode(JKQTPVectorFieldGraph::AutoscaleLineWidthFromLength);
graph1->setLineWidth(4);
plot.redrawPlot();
});
app.addExportStepFunctor([&](){
g2->setVisible(false);
graph1->setAnchorPoint(JKQTPVectorFieldGraph::AnchorBottom);
graph1->setVectorLengthMode(JKQTPVectorFieldGraph::AutoscaleLength);
graph1->setVectorLineWidthMode(JKQTPVectorFieldGraph::AutoscaleLineWidthFromLength);
graph1->setLineWidth(4);
plot.redrawPlot();
});
return app.exec();
}

View File

@ -25,7 +25,7 @@
#include <QDebug>
#include <QDateTime>
#include "jkqtcommon/jkqtpdrawingtools.h"
#include "jkqtmath/jkqtpstatisticstools.h"
#include "jkqtmath/jkqtpstatbasics.h"
#include "jkqtplotter/jkqtptools.h"
#define SmallestGreaterZeroCompare_xvsgz() if ((xvsgz>10.0*DBL_MIN)&&((smallestGreaterZero<10.0*DBL_MIN) || (xvsgz<smallestGreaterZero))) smallestGreaterZero=xvsgz;
@ -37,7 +37,9 @@ JKQTPVectorFieldGraph::JKQTPVectorFieldGraph(JKQTBasePlotter *parent):
m_vectorLengthMode(AutoscaleLength),
m_autoscaleLengthFactor(0.8),
m_lengthScaleFactor(1.0),
m_anchorPoint(AnchorBottom)
m_anchorPoint(AnchorBottom),
m_vectorLineWidthMode(DefaultVectorLineWidth),
m_minLineWidth(0.001)
{
initDecoratedLineStyle(parent, parentPlotStyle, JKQTPPlotStyleType::Default);
setTailDecoratorStyle(JKQTPNoDecorator);
@ -65,6 +67,7 @@ void JKQTPVectorFieldGraph::draw(JKQTPEnhancedPainter &painter)
{
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
const QPen p=getLinePen(painter, parent);
const double lw=getLineWidth();
painter.setPen(p);
painter.setBrush(p.color());
@ -72,6 +75,7 @@ void JKQTPVectorFieldGraph::draw(JKQTPEnhancedPainter &painter)
int imin=0;
double scale=1;
if (getIndexRange(imin, imax)) {
double minVecLen=0, maxVecLen=0;
// first determine (auto-scale) factor
if (m_vectorLengthMode==AutoscaleLength || m_vectorLengthMode==IgnoreLength) {
double avgVecLength=0;
@ -91,11 +95,14 @@ void JKQTPVectorFieldGraph::draw(JKQTPEnhancedPainter &painter)
if (NDatapoints==0) {
xmin=xmax=xv;
ymin=ymax=yv;
minVecLen=maxVecLen=l;
} else {
xmin=qMin(xmin,xv);
xmax=qMax(xmax,xv);
ymin=qMin(ymin,yv);
ymax=qMax(ymax,yv);
minVecLen=qMin(minVecLen,l);
maxVecLen=qMax(maxVecLen,l);
}
NDatapoints++;
}
@ -117,15 +124,15 @@ void JKQTPVectorFieldGraph::draw(JKQTPEnhancedPainter &painter)
const double yv=datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i));
const double x=transformX(xv);
const double y=transformY(yv);
const QPointF vecv=[&]() {
QPointF vec=getVectorDxDy(i);
const QPointF vec_orig=getVectorDxDy(i);
const QPointF vecv=[&](QPointF vec) {
if (m_vectorLengthMode==IgnoreLength) {
const double veclen=sqrt(jkqtp_sqr(vec.x())+jkqtp_sqr(vec.y()));
if (qFuzzyIsNull(veclen)) vec=QPointF(0,0);
else vec/=veclen; // normalize vector
}
return vec;
}();
}(vec_orig);
const QLineF l=[&]() {
switch (m_anchorPoint) {
case AnchorBottom: return QLineF(x,y,transformX(xv+scale*vecv.x()),transformY(yv+scale*vecv.y()));
@ -135,7 +142,16 @@ void JKQTPVectorFieldGraph::draw(JKQTPEnhancedPainter &painter)
return QLineF(JKQTP_NAN,JKQTP_NAN,JKQTP_NAN,JKQTP_NAN);
}();
if (JKQTPIsOKFloat(l) && l.length()>0) {
JKQTPPlotDecoratedLine(painter,l, getTailDecoratorStyle(), calcTailDecoratorSize(p.widthF()), getHeadDecoratorStyle(), calcHeadDecoratorSize(p.widthF()));
double actualLW=p.widthF();
if (m_vectorLineWidthMode==AutoscaleLineWidthFromLength) {
const double vec_origlen=sqrt(jkqtp_sqr(vec_orig.x())+jkqtp_sqr(vec_orig.y()));
QPen plw=p;
plw.setWidthF(m_minLineWidth+(vec_origlen-minVecLen)/(maxVecLen-minVecLen)*(lw-m_minLineWidth));
painter.setPen(plw);
actualLW=plw.widthF();
}
JKQTPPlotDecoratedLine(painter,l, getTailDecoratorStyle(), calcTailDecoratorSize(actualLW), getHeadDecoratorStyle(), calcHeadDecoratorSize(actualLW));
}
}
@ -198,3 +214,23 @@ void JKQTPVectorFieldGraph::setAnchorPoint(VectorAnchorPoint newAnchorPoint)
{
m_anchorPoint = newAnchorPoint;
}
void JKQTPVectorFieldGraph::setVectorLineWidthMode(VectorLineWidthMode m)
{
m_vectorLineWidthMode=m;
}
JKQTPVectorFieldGraph::VectorLineWidthMode JKQTPVectorFieldGraph::getVectorLineWidthMode() const
{
return m_vectorLineWidthMode;
}
void JKQTPVectorFieldGraph::setMinLineWidth(double lw)
{
m_minLineWidth=lw;
}
double JKQTPVectorFieldGraph::getMinLineWIdth() const
{
return m_minLineWidth;
}

View File

@ -83,6 +83,11 @@ class JKQTPDatastore;
VectorLengthMode.
3. By default, vector start at \c (x,y). But you can also make them be centered around or
point to \c (x,y) . This can be set by setAnchorPoint().
4. Using setVectorLineWidthMode(JKQTPVectorFieldGraph::AutoscaleLineWidthFromLength) you can also
scale the line width of each vector by the vector's length. This sometimes gives an easier to read
representation of the vector properties, especially if combined with
setVectorLengthMode(JKQTPVectorFieldGraph::IgnoreLength) :
\image html JKQTPVectorFieldGraphIgnoreLengthAutoscaleLineWidthFromLength.png
.
\see \ref JKQTPlotterVectorFieldExample , JKQTPGraphDecoratedLineStyleMixin , JKQTPXYAndVectorGraph
@ -110,6 +115,15 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPVectorFieldGraph: public JKQTPXYAndVectorGraph
};
Q_ENUM(VectorLengthMode)
/** \brief describes how the line width scales with the vector properties (or not) */
enum VectorLineWidthMode {
DefaultVectorLineWidth, //!< \brief line width is equal to JKQTPGraphLineStyleMixin::getLineWidth() for all vectors \image html JKQTPVectorFieldGraphIgnoreLength.png
AutoscaleLineWidthFromLength, //!< \brief line width is determined from the vector length. The maximum line width is given by JKQTPGraphLineStyleMixin::getLineWidth() and the minim line width by getMinLineWidth() \image html JKQTPVectorFieldGraphAutoscaleLengthAutoscaleLineWidthFromLength.png
};
Q_ENUM(VectorLineWidthMode)
/** \brief class constructor */
explicit JKQTPVectorFieldGraph(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
@ -143,10 +157,22 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPVectorFieldGraph: public JKQTPXYAndVectorGraph
/** \copydoc m_anchorPoint */
void setAnchorPoint(VectorAnchorPoint newAnchorPoint);
/** \copydoc m_vectorLineWidthMode */
void setVectorLineWidthMode(VectorLineWidthMode m);
/** \copydoc m_vectorLineWidthMode */
VectorLineWidthMode getVectorLineWidthMode() const;
/** \copydoc m_minLineWidth */
void setMinLineWidth(double lw);
/** \copydoc m_minLineWidth */
double getMinLineWIdth() const;
Q_PROPERTY(VectorLengthMode vectorLengthMode READ getVectorLengthMode WRITE setVectorLengthMode )
Q_PROPERTY(bool autoscaleLengthFactor READ getAutoscaleLengthFactor WRITE setAutoscaleLengthFactor )
Q_PROPERTY(double lengthScaleFactor READ getLengthScaleFactor WRITE setLengthScaleFactor )
Q_PROPERTY(VectorAnchorPoint anchorPoint READ getAnchorPoint WRITE setAnchorPoint )
Q_PROPERTY(double minLineWidth READ getMinLineWIdth WRITE setMinLineWidth )
Q_PROPERTY(VectorLineWidthMode vectorLineWidthMode READ getVectorLineWidthMode WRITE setVectorLineWidthMode )
protected:
private:
/** \brief indicates how the length of the drawn vectors are determined from the data
@ -163,7 +189,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPVectorFieldGraph: public JKQTPXYAndVectorGraph
* \image html JKQTPVectorFieldGraphIgnoreLength.png
* .
*
* \see VectorLengthMode, setVectorLengthMode(), getVectorLengthMode(), m_autoscaleFactor, m_autoscaleLengthFactor
* \see VectorLengthMode, setVectorLengthMode(), getVectorLengthMode(), m_lengthScaleFactor, m_autoscaleLengthFactor
*/
VectorLengthMode m_vectorLengthMode;
/** \brief a scaling factor that can be used to modify the result of the autoscaling algorithm (m_vectorLengthMode \c ==AutoscaleLength)
@ -179,9 +205,21 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPVectorFieldGraph: public JKQTPXYAndVectorGraph
double m_lengthScaleFactor;
/** \brief defines where the vector is anchored
*
* \see VectorAnchorPoint
* \see VectorAnchorPoint, setAnchorPoint(), getAnchorPoint()
*/
VectorAnchorPoint m_anchorPoint;
/** \brief determines how the line width of the vectors is derived.
*
* \note the available options are described with VectorLineWidthMode
*
* \see setVectorLineWidthMode(), getVectorLineWidthMode(), VectorLineWidthMode, m_minLineWidth
*/
VectorLineWidthMode m_vectorLineWidthMode;
/** \brief minimum line-width in pt, used for some modes of m_vectorLineWidthMode
*
* \see setMinLineWidth(), getMinLineWidth(), m_vectorLineWidthMode
*/
double m_minLineWidth;
};