NEW add JKQTPParametrizedVectorFieldGraph, which draws color-coded vector fields (color from length, angle, or user-supplied data column) + example
@ -246,6 +246,7 @@ if(JKQtPlotter_BUILD_EXAMPLES)
|
||||
#"multithreaded_complex[multithreaded]/multithreaded_complex/--mdfile=${CMAKE_CURRENT_LIST_DIR}/../examples/multithreaded/README.md --complexlabel"
|
||||
graphlabels/graphlabels,graphlabels_hor
|
||||
vectorfield
|
||||
paramvectorfield
|
||||
)
|
||||
|
||||
|
||||
@ -275,6 +276,7 @@ if(JKQtPlotter_BUILD_EXAMPLES)
|
||||
second_axis/JKQTBasePlotter_addSecondaryYAxis,JKQTBasePlotter_addSecondaryXAxis
|
||||
graphlabels/JKQTPGLabelAwayFromXAxis,JKQTPGLabelAwayFromYAxis,JKQTPGLabelTowardsXAxis,JKQTPGLabelTowardsYAxis,JKQTPGLabelAboveData,JKQTPGLabelRightHandSide,JKQTPGLabelBelowData,JKQTPGLabelLeftHandSide,JKQTPGLabelCenteredOnData,JKQTPGLabelCenteredOnDataVertical,JKQTPGLSimpleBox,JKQTPGLSimpleBoxVertical,JKQTPGLSimpleBoxAndLine,JKQTPGLSimpleBoxAndLineVertical,JKQTPGLSimpleBoxAndLineONLYLABELS,JKQTPGLSimpleBoxAndLineONLYLABELSVertical/--iteratefunctorsteps--smallscreenshotplot
|
||||
vectorfield/JKQTPVectorFieldGraph,JKQTPVectorFieldGraphAnchorBottom,JKQTPVectorFieldGraphAnchorMid,JKQTPVectorFieldGraphAnchorTip,JKQTPVectorFieldGraphAutoscaleLength,JKQTPVectorFieldGraphLengthFromData,JKQTPVectorFieldGraphIgnoreLength,JKQTPVectorFieldGraphIgnoreLengthAutoscaleLineWidthFromLength,JKQTPVectorFieldGraphAutoscaleLengthAutoscaleLineWidthFromLength/--iteratefunctorsteps
|
||||
paramvectorfield/JKQTPParametrizedVectorFieldGraph,JKQTPParametrizedVectorFieldGraphColorFromMagnitude,JKQTPParametrizedVectorFieldGraphColorFromAngle,JKQTPParametrizedVectorFieldGraphDefaultColor/--iteratefunctorsteps
|
||||
)
|
||||
|
||||
|
||||
|
@ -97,6 +97,9 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
|
||||
<tr><td> \image html vectorfield_small.png
|
||||
<td> \subpage JKQTPlotterVectorFieldExample
|
||||
<td> `JKQTPVectorFieldGraph`
|
||||
<tr><td> \image html paramvectorfield_small.png
|
||||
<td> \subpage JKQTPParametrizedVectorFieldGraphExample
|
||||
<td> `JKQTPParametrizedVectorFieldGraph`
|
||||
</table>
|
||||
|
||||
|
||||
|
@ -297,6 +297,9 @@ This group assembles graphs that represent vector fields (i.e. sets of quadruple
|
||||
<tr>
|
||||
<td>\image html vectorfield_small.png
|
||||
<td> JKQTPVectorFieldGraph
|
||||
<tr>
|
||||
<td>\image html paramvectorfield_small.png
|
||||
<td> JKQTPParametrizedVectorFieldGraph
|
||||
</table>
|
||||
|
||||
|
||||
|
@ -128,7 +128,9 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
|
||||
<li>NEW: allow linear-gradient(), currentcolor, ... in brush definitions of style.ini-file ... and using it is cyberpunk and dark styles</li>
|
||||
<li>NEW: style simple_noaxes.ini</li>
|
||||
<li>NEW: JKQTPXYGraphLabels which can draw a label next to each datapoint in the given x/y-dataset. The labels can be x-/y- or x&y-coordinates or custom, then defined by a user-supplied functor (+example \ref JKQTPlotterGraphLabelsExample)</li>
|
||||
<li>NEW: Base class JKQTPXYAndVectorGraph for graphs like vector fields, e.g. (x,y,dx,dy) or (x,y,angle,length) and an actual implementation JKQTPVectorFieldGraph (+example \ref JKQTPlotterVectorFieldExample)</li>
|
||||
<li>NEW: Base class JKQTPXYAndVectorGraph for graphs like vector fields, e.g. (x,y,dx,dy) or (x,y,angle,length) </li>
|
||||
<li>NEW: JKQTPVectorFieldGraph for drawing "simple" vector fields/quiver plots (+example \ref JKQTPlotterVectorFieldExample)</li>
|
||||
<li>NEW: JKQTPParametrizedVectorFieldGraph for drawing color-coded vector fields/quiver plots (+example \ref JKQTPParametrizedVectorFieldGraphExample)</li>
|
||||
</ul></li>
|
||||
|
||||
<li>JKQTMathText:<ul>
|
||||
|
BIN
doc/images/JKQTPParametrizedVectorFieldGraph.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
doc/images/JKQTPParametrizedVectorFieldGraphColorFromAngle.png
Normal file
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 38 KiB |
BIN
doc/images/JKQTPParametrizedVectorFieldGraphDefaultColor.png
Normal file
After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 13 KiB |
@ -91,6 +91,7 @@ if (JKQtPlotter_BUILD_LIB_JKQTPLOTTER)
|
||||
add_subdirectory(paramscatterplot_image)
|
||||
add_subdirectory(paramscatterplot_customsymbol)
|
||||
add_subdirectory(parsedfunctionplot)
|
||||
add_subdirectory(paramvectorfield)
|
||||
add_subdirectory(rgbimageplot)
|
||||
add_subdirectory(rgbimageplot_cimg)
|
||||
add_subdirectory(rgbimageplot_opencv)
|
||||
|
25
examples/paramvectorfield/CMakeLists.txt
Normal file
@ -0,0 +1,25 @@
|
||||
cmake_minimum_required(VERSION 3.23)
|
||||
|
||||
set(EXAMPLE_NAME paramvectorfield)
|
||||
set(EXENAME jkqtptest_${EXAMPLE_NAME})
|
||||
|
||||
message( STATUS ".. Building Example ${EXAMPLE_NAME}" )
|
||||
|
||||
|
||||
|
||||
add_executable(${EXENAME} WIN32 ${EXAMPLE_NAME}.cpp)
|
||||
target_link_libraries(${EXENAME} JKQTPExampleToolsLib)
|
||||
target_include_directories(${EXENAME} PRIVATE ../../lib)
|
||||
target_link_libraries(${EXENAME} ${jkqtplotter_namespace}JKQTPlotter${jkqtplotter_LIBNAME_VERSION_PART})
|
||||
|
||||
# precomiled headers to speed up compilation
|
||||
if (JKQtPlotter_BUILD_WITH_PRECOMPILED_HEADERS)
|
||||
target_precompile_headers(${EXENAME} REUSE_FROM jkqtptest_simpletest)
|
||||
endif (JKQtPlotter_BUILD_WITH_PRECOMPILED_HEADERS)
|
||||
|
||||
|
||||
# Installation
|
||||
install(TARGETS ${EXENAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
#Installation of Qt DLLs on Windows
|
||||
jkqtplotter_deployqt(${EXENAME})
|
63
examples/paramvectorfield/README.md
Normal file
@ -0,0 +1,63 @@
|
||||
# Example (JKQTPlotter): Vector Field Plot Example {#JKQTPParametrizedVectorFieldGraphExample}
|
||||
This project (see [`paramvectorfield`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/paramvectorfield) demonstrates the use of JKQTPParametrizedVectorFieldGraph to visualize a vector field with additional information encoded in the color of the vectors.
|
||||
|
||||
The source code of the main application is (see [`paramvectorfield.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/paramvectorfield/paramvectorfield.cpp).
|
||||
|
||||
Here is a short summary of the important parts of the code:
|
||||
|
||||
```.cpp
|
||||
// 1. setup a plotter window and get a pointer to the internal datastore (for convenience)
|
||||
JKQTPlotter plot;
|
||||
JKQTPDatastore* ds=plot.getDatastore();
|
||||
|
||||
|
||||
// 2. make up some arbitrary data to be used for plotting
|
||||
// this generates a 2D grid of x/y-coordinates and then calculates dx=cos(y)*sqrt(x/3.0) and dy=sin(x)*sqrt(x/3.0)
|
||||
const auto columnXY=ds->addLinearGridColumns(NX, 0, 6, NY, -3, 3,"x","y");
|
||||
const auto columnDX=ds->addCalculatedColumnFromColumn(columnXY.first, columnXY.second, [](double x,double y) { return sin(y)*sqrt(x/3.0); });
|
||||
const auto columnDY=ds->addCalculatedColumnFromColumn(columnXY.first, columnXY.second, [](double x,double y) { return cos(x)*sqrt(x/3.0); });
|
||||
// now we also calulate a column that encodes some other information that can be color-coded
|
||||
const auto columnC=ds->addCalculatedColumnFromColumn(columnXY.first, columnXY.second, [](double x,double y) { return sqrt(fabs(y)); });
|
||||
|
||||
|
||||
// 3. create JKQTPVectorFieldGraph to display the data:
|
||||
JKQTPParametrizedVectorFieldGraph* graph1=new JKQTPParametrizedVectorFieldGraph(&plot);
|
||||
graph1->setXYColumns(columnXY);
|
||||
graph1->setDxColumn(columnDX);
|
||||
graph1->setDyColumn(columnDY);
|
||||
graph1->setColorColumn(columnC);
|
||||
graph1->setTitle(QObject::tr("$\\vec{f}(x,y)=\\bigl[\\sin(y)\\cdot\\sqrt{x/3}, \\cos(x)\\cdot\\sqrt{x/3}\\bigr]^\\mathrm{T}$"));
|
||||
|
||||
// 4. add the graphs to the plot, so it is actually displayed
|
||||
plot.addGraph(graph1);
|
||||
|
||||
```
|
||||
|
||||
The result looks like this:
|
||||
|
||||
![paramvectorfield](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/paramvectorfield.png)
|
||||
|
||||
|
||||
By default, the color of the drawn vector is determined from the color column provided to the graph object.
|
||||
But you can also choose to not provide a color column and instead set
|
||||
|
||||
```.cpp
|
||||
graph1->setVectorColorMode(JKQTPParametrizedVectorFieldGraph::ColorFromMagnitude);
|
||||
```
|
||||
|
||||
Now the color encodes the actual length (or magnitude) of the vectors:
|
||||
|
||||
![paramvectorfield](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/doc/images/JKQTPParametrizedVectorFieldGraphColorFromMagnitude.png)
|
||||
|
||||
|
||||
Alternatively
|
||||
|
||||
```.cpp
|
||||
graph1->setVectorColorMode(JKQTPParametrizedVectorFieldGraph::ColorFromAngle);
|
||||
```
|
||||
|
||||
will color-encode the rotation angle (in radians, 3 o'clock is 0rad) of the vectors:
|
||||
|
||||
![paramvectorfield](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/doc/images/JKQTPParametrizedVectorFieldGraphColorFromAngle.png)
|
||||
|
||||
|
86
examples/paramvectorfield/paramvectorfield.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
/** \example vectorfield.cpp
|
||||
* Display a vector field
|
||||
*
|
||||
* \ref JKQTPlotterVectorFieldExample
|
||||
*/
|
||||
|
||||
#include "jkqtpexampleapplication.h"
|
||||
#include <QApplication>
|
||||
#include "jkqtplotter/jkqtplotter.h"
|
||||
#include "jkqtplotter/graphs/jkqtpvectorfield.h"
|
||||
#include "jkqtplotter/graphs/jkqtpscatter.h"
|
||||
#include "jkqtpexampleapplication.h"
|
||||
|
||||
|
||||
#define NX 9
|
||||
#define NY 9
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
JKQTPAppSettingController highDPIController(argc,argv);
|
||||
JKQTPExampleApplication app(argc, argv);
|
||||
|
||||
|
||||
// 1. setup a plotter window and get a pointer to the internal datastore (for convenience)
|
||||
JKQTPlotter plot;
|
||||
plot.getPlotter()->setUseAntiAliasingForGraphs(true); // nicer (but slower) plotting
|
||||
plot.getPlotter()->setUseAntiAliasingForSystem(true); // nicer (but slower) plotting
|
||||
plot.getPlotter()->setUseAntiAliasingForText(true); // nicer (but slower) text rendering
|
||||
JKQTPDatastore* ds=plot.getDatastore();
|
||||
|
||||
|
||||
|
||||
// 2. make up some arbitrary data to be used for plotting
|
||||
// this generates a 2D grid of x/y-coordinates and then calculates dx=cos(y)*sqrt(x/3.0) and dy=sin(x)*sqrt(x/3.0)
|
||||
const auto columnXY=ds->addLinearGridColumns(NX, 0, 6, NY, -3, 3,"x","y");
|
||||
const auto columnDX=ds->addCalculatedColumnFromColumn(columnXY.first, columnXY.second, [](double x,double y) { return sin(y)*sqrt(x/3.0); });
|
||||
const auto columnDY=ds->addCalculatedColumnFromColumn(columnXY.first, columnXY.second, [](double x,double y) { return cos(x)*sqrt(x/3.0); });
|
||||
// now we also calulate a column that encodes some other information that can be color-coded
|
||||
const auto columnC=ds->addCalculatedColumnFromColumn(columnXY.first, columnXY.second, [](double x,double y) { return sqrt(fabs(y)); });
|
||||
|
||||
|
||||
// 3. create JKQTPVectorFieldGraph to display the data:
|
||||
JKQTPParametrizedVectorFieldGraph* graph1=new JKQTPParametrizedVectorFieldGraph(&plot);
|
||||
graph1->setXYColumns(columnXY);
|
||||
graph1->setDxColumn(columnDX);
|
||||
graph1->setDyColumn(columnDY);
|
||||
graph1->setColorColumn(columnC);
|
||||
graph1->setTitle(QObject::tr("$\\vec{f}(x,y)=\\bigl[\\sin(y)\\cdot\\sqrt{x/3}, \\cos(x)\\cdot\\sqrt{x/3}\\bigr]^\\mathrm{T}$"));
|
||||
|
||||
// 4. add the graphs to the plot, so it is actually displayed
|
||||
plot.addGraph(graph1);
|
||||
|
||||
// 5. scale the plot so the graph is contained
|
||||
plot.getPlotter()->setAxisAspectRatio(1);
|
||||
plot.getPlotter()->setAspectRatio(1);
|
||||
plot.getPlotter()->setMaintainAxisAspectRatio(true);
|
||||
plot.getPlotter()->setMaintainAspectRatio(true);
|
||||
plot.zoomToFit();
|
||||
|
||||
|
||||
// show plotter and make it a decent size
|
||||
plot.setWindowTitle("JKQTPVectorFieldGraph example");
|
||||
plot.show();
|
||||
plot.resize(400/plot.devicePixelRatioF(),430/plot.devicePixelRatioF());
|
||||
|
||||
|
||||
|
||||
app.addExportStepFunctor([&](){
|
||||
graph1->setVectorColorMode(JKQTPParametrizedVectorFieldGraph::ColorFromMagnitude);
|
||||
plot.redrawPlot();
|
||||
});
|
||||
|
||||
app.addExportStepFunctor([&](){
|
||||
graph1->setVectorColorMode(JKQTPParametrizedVectorFieldGraph::ColorFromAngle);
|
||||
plot.redrawPlot();
|
||||
});
|
||||
|
||||
app.addExportStepFunctor([&](){
|
||||
graph1->setVectorColorMode(JKQTPParametrizedVectorFieldGraph::DefaultColor);
|
||||
plot.redrawPlot();
|
||||
});
|
||||
|
||||
|
||||
return app.exec();
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
# Example (JKQTPlotter): Vector Field Plot Example {#JKQTPlotterVectorFieldExample}
|
||||
This project (see [`vectorfield`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/vectorfield) demonstrates the use of JKQTPXYvectorfield to add labels to the datapoints of a graph.
|
||||
This project (see [`vectorfield`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/vectorfield) demonstrates the use of JKQTPVectorFieldGraph to visualize a vector field.
|
||||
|
||||
The source code of the main application is (see [`vectorfield.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/vectorfield/vectorfield.cpp).
|
||||
|
||||
|
@ -123,9 +123,9 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPBarGraphBase: public JKQTPXYBaselineGraph, pub
|
||||
/** \brief class constructor */
|
||||
JKQTPBarGraphBase(JKQTPlotter* parent);
|
||||
|
||||
/** \brief plots a key marker inside the specified rectangle \a rect */
|
||||
/** \copydoc JKQTPXYBaselineGraph::drawKeyMarker() */
|
||||
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, const QRectF& rect) override;
|
||||
/** \brief returns the color to be used for the key label */
|
||||
/** \copydoc JKQTPXYBaselineGraph::getKeyLabelColor() */
|
||||
virtual QColor getKeyLabelColor() const override;
|
||||
|
||||
|
||||
|
@ -111,7 +111,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPBoxplotVerticalGraph: public JKQTPBoxplotGraph
|
||||
|
||||
/** \brief plots the graph to the plotter object specified as parent */
|
||||
virtual void draw(JKQTPEnhancedPainter& painter) override;
|
||||
/** \brief plots a key marker inside the specified rectangle \a rect */
|
||||
/** \copydoc JKQTPBoxplotGraphBase::drawKeyMarker() */
|
||||
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, const QRectF& rect) override;
|
||||
|
||||
/** \copydoc JKQTPPlotElement::getXMinMax() */
|
||||
|
@ -270,6 +270,7 @@ JKQTPXYParametrizedScatterGraph::JKQTPXYParametrizedScatterGraph(JKQTBasePlotter
|
||||
symbolFillDerivationMode=JKQTPColorDerivationMode::JKQTPFFCMLighterColor;
|
||||
if (parent) {
|
||||
symbolFillDerivationMode=parent->getCurrentPlotterStyle().graphsStyle.defaultGraphStyle.fillColorDerivationMode;
|
||||
palette=parent->getCurrentPlotterStyle().graphsStyle.defaultPalette;
|
||||
}
|
||||
|
||||
clearSizeColumnFunctor();
|
||||
|
@ -39,7 +39,9 @@ JKQTPVectorFieldGraph::JKQTPVectorFieldGraph(JKQTBasePlotter *parent):
|
||||
m_lengthScaleFactor(1.0),
|
||||
m_anchorPoint(AnchorBottom),
|
||||
m_vectorLineWidthMode(DefaultVectorLineWidth),
|
||||
m_minLineWidth(0.001)
|
||||
m_minLineWidth(0.001),
|
||||
m_minVecLen(0),
|
||||
m_maxVecLen(0)
|
||||
{
|
||||
initDecoratedLineStyle(parent, parentPlotStyle, JKQTPPlotStyleType::Default);
|
||||
setTailDecoratorStyle(JKQTPNoDecorator);
|
||||
@ -75,13 +77,13 @@ void JKQTPVectorFieldGraph::draw(JKQTPEnhancedPainter &painter)
|
||||
int imin=0;
|
||||
double scale=1;
|
||||
if (getIndexRange(imin, imax)) {
|
||||
double minVecLen=0, maxVecLen=0;
|
||||
m_minVecLen=m_maxVecLen=0;
|
||||
// first determine (auto-scale) factor
|
||||
if (m_vectorLengthMode==AutoscaleLength || m_vectorLengthMode==IgnoreLength) {
|
||||
double avgVecLength=0;
|
||||
double NDatapoints=0;
|
||||
double xmin=0, xmax=0,ymin=0,ymax=0;
|
||||
QVector<double> lengths;
|
||||
std::vector<double> lengths;
|
||||
lengths.reserve(imax-imin);
|
||||
for (int iii=imin; iii<imax; iii++) {
|
||||
const int i=qBound(imin, getDataIndex(iii), imax);
|
||||
@ -89,20 +91,20 @@ void JKQTPVectorFieldGraph::draw(JKQTPEnhancedPainter &painter)
|
||||
const double yv=datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i));
|
||||
const QPointF vecv=getVectorDxDy(i);
|
||||
if (JKQTPIsOKFloat(xv) && JKQTPIsOKFloat(yv) && JKQTPIsOKFloat(vecv)) {
|
||||
const double l=sqrt(jkqtp_sqr(vecv.x())+jkqtp_sqr(vecv.y()));
|
||||
lengths<<l;
|
||||
const double l=getVectorMagnitude(vecv);
|
||||
lengths.push_back(l);
|
||||
avgVecLength+=l;
|
||||
if (NDatapoints==0) {
|
||||
xmin=xmax=xv;
|
||||
ymin=ymax=yv;
|
||||
minVecLen=maxVecLen=l;
|
||||
m_minVecLen=m_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);
|
||||
m_minVecLen=qMin(m_minVecLen,l);
|
||||
m_maxVecLen=qMax(m_maxVecLen,l);
|
||||
}
|
||||
NDatapoints++;
|
||||
}
|
||||
@ -127,7 +129,7 @@ void JKQTPVectorFieldGraph::draw(JKQTPEnhancedPainter &painter)
|
||||
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()));
|
||||
const double veclen=getVectorMagnitude(vecv);
|
||||
if (qFuzzyIsNull(veclen)) vec=QPointF(0,0);
|
||||
else vec/=veclen; // normalize vector
|
||||
}
|
||||
@ -143,14 +145,15 @@ void JKQTPVectorFieldGraph::draw(JKQTPEnhancedPainter &painter)
|
||||
}();
|
||||
if (JKQTPIsOKFloat(l) && l.length()>0) {
|
||||
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);
|
||||
if (m_vectorLineWidthMode==AutoscaleLineWidthFromLength) {
|
||||
const double vec_origlen=getVectorMagnitude(vec_orig);
|
||||
plw.setWidthF(m_minLineWidth+(vec_origlen-m_minVecLen)/(m_maxVecLen-m_minVecLen)*(lw-m_minLineWidth));
|
||||
actualLW=plw.widthF();
|
||||
}
|
||||
|
||||
plw.setColor(getLocalVectorColor(i,xv,yv,vec_orig.x(),vec_orig.y()));
|
||||
painter.setPen(plw);
|
||||
painter.setBrush(plw.color());
|
||||
JKQTPPlotDecoratedLine(painter,l, getTailDecoratorStyle(), calcTailDecoratorSize(actualLW), getHeadDecoratorStyle(), calcHeadDecoratorSize(actualLW));
|
||||
}
|
||||
}
|
||||
@ -234,3 +237,235 @@ double JKQTPVectorFieldGraph::getMinLineWIdth() const
|
||||
{
|
||||
return m_minLineWidth;
|
||||
}
|
||||
|
||||
QColor JKQTPVectorFieldGraph::getLocalVectorColor(int /*i*/, double /*x*/, double /*y*/, double /*dx*/, double /*dy*/) const
|
||||
{
|
||||
return getLineColor();
|
||||
}
|
||||
|
||||
JKQTPParametrizedVectorFieldGraph::JKQTPParametrizedVectorFieldGraph(JKQTBasePlotter *parent):
|
||||
JKQTPVectorFieldGraph(parent),
|
||||
JKQTPColorPaletteStyleAndToolsMixin(parent),
|
||||
m_colorColumn(-1),
|
||||
m_colorColumnContainsRGB(false),
|
||||
m_vectorColorMode(ColorFromMagnitude)
|
||||
{
|
||||
palette=JKQTPMathImageMATLAB;
|
||||
if (parent) {
|
||||
palette=parent->getCurrentPlotterStyle().graphsStyle.defaultPalette;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
JKQTPParametrizedVectorFieldGraph::JKQTPParametrizedVectorFieldGraph(JKQTPlotter *parent):
|
||||
JKQTPParametrizedVectorFieldGraph(parent->getPlotter())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void JKQTPParametrizedVectorFieldGraph::drawKeyMarker(JKQTPEnhancedPainter &painter, const QRectF &rect)
|
||||
{
|
||||
if (m_vectorColorMode==DefaultColor) {
|
||||
JKQTPVectorFieldGraph::drawKeyMarker(painter,rect);
|
||||
} else {
|
||||
QColor color1=getKeyLabelColor();
|
||||
QColor color2=getKeyLabelColor();
|
||||
|
||||
if (m_colorColumn>=0) {
|
||||
if (m_colorColumnContainsRGB) {
|
||||
color1=QColor("red");
|
||||
color2=QColor("blue");
|
||||
} else {
|
||||
QImage img;
|
||||
double colorval[]={0,1};
|
||||
JKQTPImageTools::array2image<double>(colorval, 2, 1, img, getColorPalette(), double(0.0), double(1.0));
|
||||
color1=img.pixel(0,0);
|
||||
color2=img.pixel(1,0);
|
||||
}
|
||||
}
|
||||
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
||||
QPen p=getKeyLinePen(painter, rect, parent);
|
||||
p.setColor(color1);
|
||||
painter.setPen(p);
|
||||
painter.setBrush(p.color());
|
||||
const QLineF l(rect.left(), rect.bottom(), rect.right(), (rect.top()+rect.bottom())/2.0);
|
||||
JKQTPPlotDecoratedLine(painter,l, getTailDecoratorStyle(), calcTailDecoratorSize(p.widthF()), getHeadDecoratorStyle(), calcHeadDecoratorSize(p.widthF()));
|
||||
|
||||
p=getKeyLinePen(painter, rect, parent);
|
||||
p.setColor(color2);
|
||||
painter.setPen(p);
|
||||
painter.setBrush(p.color());
|
||||
const QLineF l2(rect.left(), (rect.top()+rect.bottom())/2.0, rect.right(), rect.top());
|
||||
JKQTPPlotDecoratedLine(painter,l2, getTailDecoratorStyle(), calcTailDecoratorSize(p.widthF()), getHeadDecoratorStyle(), calcHeadDecoratorSize(p.widthF()));
|
||||
}
|
||||
}
|
||||
|
||||
void JKQTPParametrizedVectorFieldGraph::draw(JKQTPEnhancedPainter &painter)
|
||||
{
|
||||
cbGetDataMinMax(m_intColMin, m_intColMax);
|
||||
JKQTPVectorFieldGraph::draw(painter);
|
||||
}
|
||||
|
||||
void JKQTPParametrizedVectorFieldGraph::setParent(JKQTBasePlotter *parent)
|
||||
{
|
||||
JKQTPVectorFieldGraph::setParent(parent);
|
||||
cbSetParent(parent);
|
||||
}
|
||||
|
||||
void JKQTPParametrizedVectorFieldGraph::getOutsideSize(JKQTPEnhancedPainter &painter, int &leftSpace, int &rightSpace, int &topSpace, int &bottomSpace)
|
||||
{
|
||||
JKQTPVectorFieldGraph::getOutsideSize(painter, leftSpace, rightSpace, topSpace, bottomSpace);
|
||||
if (showColorBar&& m_colorColumn>=0 && !m_colorColumnContainsRGB) cbGetOutsideSize(painter, leftSpace, rightSpace, topSpace, bottomSpace);
|
||||
}
|
||||
|
||||
void JKQTPParametrizedVectorFieldGraph::drawOutside(JKQTPEnhancedPainter &painter, QRect leftSpace, QRect rightSpace, QRect topSpace, QRect bottomSpace)
|
||||
{
|
||||
JKQTPVectorFieldGraph::drawOutside(painter, leftSpace, rightSpace, topSpace, bottomSpace);
|
||||
if (showColorBar&& m_colorColumn>=0 && !m_colorColumnContainsRGB) cbDrawOutside(painter, leftSpace, rightSpace, topSpace, bottomSpace);
|
||||
}
|
||||
|
||||
void JKQTPParametrizedVectorFieldGraph::cbGetDataMinMax(double &dmin, double &dmax)
|
||||
{
|
||||
dmin=dmax=0;
|
||||
if (autoImageRange) {
|
||||
if (parent==nullptr) return;
|
||||
JKQTPDatastore* datastore=parent->getDatastore();
|
||||
if (datastore==nullptr) return;
|
||||
int imin=0, imax=0;
|
||||
if (getIndexRange(imin, imax)) {
|
||||
if (m_vectorColorMode==ColorFromCustomColumn) {
|
||||
if (m_colorColumn<0) return;
|
||||
bool first=true;
|
||||
for (int iii=imin; iii<imax; iii++) {
|
||||
const int i=qBound(imin, getDataIndex(iii), imax);
|
||||
const double xv=datastore->get(m_colorColumn,i);
|
||||
if (JKQTPIsOKFloat(xv)) {
|
||||
if (first) {
|
||||
dmin=dmax=xv;
|
||||
first=false;
|
||||
} else {
|
||||
dmin=qMin(xv, dmin);
|
||||
dmax=qMax(xv, dmax);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (m_vectorColorMode==ColorFromMagnitude) {
|
||||
bool first=true;
|
||||
for (int iii=imin; iii<imax; iii++) {
|
||||
const int i=qBound(imin, getDataIndex(iii), imax);
|
||||
const double vecLen=getVectorMagnitude(i);
|
||||
if (JKQTPIsOKFloat(vecLen)) {
|
||||
if (first) {
|
||||
dmin=dmax=vecLen;
|
||||
first=false;
|
||||
} else {
|
||||
dmin=qMin(vecLen, dmin);
|
||||
dmax=qMax(vecLen, dmax);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (m_vectorColorMode==ColorFromAngle) {
|
||||
bool first=true;
|
||||
for (int iii=imin; iii<imax; iii++) {
|
||||
const int i=qBound(imin, getDataIndex(iii), imax);
|
||||
const double vecAngle=getVectorAngle(i);
|
||||
if (JKQTPIsOKFloat(vecAngle)) {
|
||||
if (first) {
|
||||
dmin=dmax=vecAngle;
|
||||
first=false;
|
||||
} else {
|
||||
dmin=qMin(vecAngle, dmin);
|
||||
dmax=qMax(vecAngle, dmax);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dmin=imageMin;
|
||||
dmax=imageMax;
|
||||
}
|
||||
}
|
||||
|
||||
bool JKQTPParametrizedVectorFieldGraph::usesColumn(int c) const
|
||||
{
|
||||
return (c==m_colorColumn) || JKQTPVectorFieldGraph::usesColumn(c);
|
||||
}
|
||||
|
||||
void JKQTPParametrizedVectorFieldGraph::setColorColumn(int __value)
|
||||
{
|
||||
m_colorColumn = __value;
|
||||
if (__value<0) m_vectorColorMode=ColorFromMagnitude;
|
||||
else m_vectorColorMode=ColorFromCustomColumn;
|
||||
}
|
||||
|
||||
int JKQTPParametrizedVectorFieldGraph::getColorColumn() const
|
||||
{
|
||||
return m_colorColumn;
|
||||
}
|
||||
|
||||
void JKQTPParametrizedVectorFieldGraph::setColorColumn(size_t __value)
|
||||
{
|
||||
m_colorColumn = static_cast<int>(__value);
|
||||
m_vectorColorMode=ColorFromCustomColumn;
|
||||
}
|
||||
|
||||
void JKQTPParametrizedVectorFieldGraph::setColorColumnContainsRGB(bool __value)
|
||||
{
|
||||
m_colorColumnContainsRGB=__value;
|
||||
}
|
||||
|
||||
bool JKQTPParametrizedVectorFieldGraph::getColorColumnContainsRGB() const
|
||||
{
|
||||
return m_colorColumnContainsRGB;
|
||||
}
|
||||
|
||||
void JKQTPParametrizedVectorFieldGraph::setVectorColorMode(VectorColorMode __value)
|
||||
{
|
||||
m_vectorColorMode=__value;
|
||||
}
|
||||
|
||||
JKQTPParametrizedVectorFieldGraph::VectorColorMode JKQTPParametrizedVectorFieldGraph::getVectorColorMode() const
|
||||
{
|
||||
return m_vectorColorMode;
|
||||
}
|
||||
|
||||
QColor JKQTPParametrizedVectorFieldGraph::getLocalVectorColor(int i, double x, double y, double dx, double dy) const
|
||||
{
|
||||
if (parent==nullptr) return getLineColor();
|
||||
const JKQTPDatastore* datastore=parent->getDatastore();
|
||||
if (datastore==nullptr) return getLineColor();
|
||||
if (m_colorColumn<0 && m_vectorColorMode==ColorFromCustomColumn) return getLineColor();
|
||||
if (m_colorColumn>=0 && m_vectorColorMode==ColorFromCustomColumn && (i<0 || i>=(int64_t)datastore->getRows(m_colorColumn))) return getLineColor();
|
||||
|
||||
double colValue=0;
|
||||
double colMin=m_intColMin;
|
||||
double colMax=m_intColMax;
|
||||
switch(m_vectorColorMode) {
|
||||
case ColorFromCustomColumn:
|
||||
colValue=datastore->get(m_colorColumn,i);
|
||||
if (m_intColMin==m_intColMax) {
|
||||
colMin=0;
|
||||
colMax=datastore->getRows(m_colorColumn)-1;
|
||||
}
|
||||
break;
|
||||
case ColorFromMagnitude:
|
||||
colValue=getVectorMagnitude(QPointF(dx,dy));
|
||||
break;
|
||||
case ColorFromAngle:
|
||||
colValue=getVectorAngle(QPointF(dx,dy));
|
||||
break;
|
||||
case DefaultColor:
|
||||
return getLineColor();
|
||||
}
|
||||
|
||||
|
||||
if (m_colorColumnContainsRGB && m_vectorColorMode==ColorFromCustomColumn) {
|
||||
return QRgb(round(colValue));
|
||||
} else {
|
||||
QImage img;
|
||||
JKQTPImageTools::array2image(&colValue, 1, 1, img, palette, colMin, colMax);
|
||||
return img.pixel(0,0);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ class JKQTPDatastore;
|
||||
\image html JKQTPVectorFieldGraphIgnoreLengthAutoscaleLineWidthFromLength.png
|
||||
.
|
||||
|
||||
\see \ref JKQTPlotterVectorFieldExample , JKQTPGraphDecoratedLineStyleMixin , JKQTPXYAndVectorGraph
|
||||
\see \ref JKQTPlotterVectorFieldExample , JKQTPGraphDecoratedLineStyleMixin , JKQTPXYAndVectorGraph and JKQTPParametrizedVectorFieldGraph for a user-colored alternative
|
||||
|
||||
*/
|
||||
class JKQTPLOTTER_LIB_EXPORT JKQTPVectorFieldGraph: public JKQTPXYAndVectorGraph, public JKQTPGraphDecoratedLineStyleMixin {
|
||||
@ -129,11 +129,11 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPVectorFieldGraph: public JKQTPXYAndVectorGraph
|
||||
/** \brief class constructor */
|
||||
JKQTPVectorFieldGraph(JKQTPlotter* parent);
|
||||
|
||||
/** \brief plots the graph to the plotter object specified as parent */
|
||||
/** \copydoc JKQTPXYAndVectorGraph::draw() */
|
||||
virtual void draw(JKQTPEnhancedPainter& painter) override;
|
||||
/** \brief plots a key marker inside the specified rectangle \a rect */
|
||||
/** \copydoc JKQTPXYAndVectorGraph::drawKeyMarker() */
|
||||
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, const QRectF& rect) override;
|
||||
/** \brief returns the color to be used for the key label */
|
||||
/** \copydoc JKQTPXYAndVectorGraph::getKeyLabelColor() */
|
||||
virtual QColor getKeyLabelColor() const override;
|
||||
|
||||
/** \copydoc m_vectorLengthMode */
|
||||
@ -174,6 +174,17 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPVectorFieldGraph: public JKQTPXYAndVectorGraph
|
||||
Q_PROPERTY(double minLineWidth READ getMinLineWIdth WRITE setMinLineWidth )
|
||||
Q_PROPERTY(VectorLineWidthMode vectorLineWidthMode READ getVectorLineWidthMode WRITE setVectorLineWidthMode )
|
||||
protected:
|
||||
/** \brief internal color functor, a customization point for derived classes
|
||||
*
|
||||
* Overwrite this in a derived class to be able to color each vector differently */
|
||||
virtual QColor getLocalVectorColor(int i,double x,double y,double dx,double dy) const;
|
||||
/** \brief acess to internally calculated (before draw() actually draws) minimum vector length
|
||||
*/
|
||||
inline double getMinVecLen() const { return m_minVecLen; };
|
||||
/** \brief acess to internally calculated (before draw() actually draws) maximum vector length
|
||||
*/
|
||||
inline double getMaxVecLen() const { return m_maxVecLen; };
|
||||
|
||||
private:
|
||||
/** \brief indicates how the length of the drawn vectors are determined from the data
|
||||
*
|
||||
@ -221,9 +232,131 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPVectorFieldGraph: public JKQTPXYAndVectorGraph
|
||||
*/
|
||||
double m_minLineWidth;
|
||||
|
||||
/** \brief internally calculated (before draw() actually draws) minimum vector length
|
||||
* \internal
|
||||
*/
|
||||
double m_minVecLen;
|
||||
/** \brief internally calculated (before draw() actually draws) maximum vector length
|
||||
* \internal
|
||||
*/
|
||||
double m_maxVecLen;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*! \brief This graph plots a vector field, i.e. a set of vectors (dx,dy) or (angle,length) at positions (x,y).
|
||||
This class is an extension of JKQTPVectorFieldGraph and additionally supports setting the line-color
|
||||
from an additional data column.
|
||||
\ingroup jkqtplotter_vectorfieldgraphs
|
||||
|
||||
\note This type of plot is sometimes also refered to as <b>quiver plot</b> (e.g. in Matlab or matplotlib)
|
||||
|
||||
\image html JKQTPParametrizedVectorFieldGraph.png
|
||||
|
||||
To achieve this, use code like this:
|
||||
\code
|
||||
// 1. setup a plotter window and get a pointer to the internal datastore (for convenience)
|
||||
JKQTPlotter plot;
|
||||
JKQTPDatastore* ds=plot.getDatastore();
|
||||
|
||||
// 2. make up some arbitrary data to be used for plotting
|
||||
// this generates a 2D grid of x/y-coordinates and then calculates dx=cos(y)*sqrt(x/3.0) and dy=sin(x)*sqrt(x/3.0)
|
||||
const auto columnXY=ds->addLinearGridColumns(NX, 0, 6, NY, -3, 3,"x","y");
|
||||
const auto columnDX=ds->addCalculatedColumnFromColumn(columnXY.first, columnXY.second, [](double x,double y) { return sin(y)*sqrt(x/3.0); });
|
||||
const auto columnDY=ds->addCalculatedColumnFromColumn(columnXY.first, columnXY.second, [](double x,double y) { return cos(x)*sqrt(x/3.0); });
|
||||
|
||||
// 3. create JKQTPVectorFieldGraph to display the data:
|
||||
JKQTPVectorFieldGraph* graph1=new JKQTPVectorFieldGraph(&plot);
|
||||
graph1->setXYColumns(columnXY);
|
||||
graph1->setDxColumn(columnDX);
|
||||
graph1->setDyColumn(columnDY);
|
||||
graph1->setTitle(QObject::tr("$\\vec{f}(x,y)=\\bigl[\\sin(y)\\cdot\\sqrt{x/3}, \\cos(x)\\cdot\\sqrt{x/3}\\bigr]^\\mathrm{T}$"));
|
||||
|
||||
// 4. add the graphs to the plot, so it is actually displayed
|
||||
plot.addGraph(graph1);
|
||||
\endcode
|
||||
|
||||
Use setVectorColorMode() if you don't want to use a custom column, but just use the vector's magnitude/length or
|
||||
rotation angle as parameter for the color.
|
||||
|
||||
\see \ref JKQTPParametrizedVectorFieldGraphExample , JKQTPVectorFieldGraph , JKQTPColorPaletteStyleAndToolsMixin
|
||||
|
||||
*/
|
||||
class JKQTPLOTTER_LIB_EXPORT JKQTPParametrizedVectorFieldGraph: public JKQTPVectorFieldGraph, public JKQTPColorPaletteStyleAndToolsMixin {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/** \brief determines how the color of the vector is determined */
|
||||
enum VectorColorMode {
|
||||
DefaultColor, //!< \brief no color-coding, just use getLineColor() \image html JKQTPParametrizedVectorFieldGraphDefaultColor.png
|
||||
ColorFromMagnitude, //!< \brief color-coding by vector magnitude/length \image html JKQTPParametrizedVectorFieldGraphColorFromMagnitude.png
|
||||
ColorFromAngle, //!< \brief color-coding by vector angle \image html JKQTPParametrizedVectorFieldGraphColorFromAngle.png
|
||||
ColorFromCustomColumn //!< \brief color-coding from getColorColumn() column \image html JKQTPParametrizedVectorFieldGraph.png
|
||||
};
|
||||
Q_ENUM(VectorColorMode)
|
||||
|
||||
/** \brief class constructor */
|
||||
explicit JKQTPParametrizedVectorFieldGraph(JKQTBasePlotter* parent=nullptr);
|
||||
/** \brief class constructor */
|
||||
JKQTPParametrizedVectorFieldGraph(JKQTPlotter* parent);
|
||||
|
||||
/** \copydoc JKQTPVectorFieldGraph::drawKeyMarker() */
|
||||
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, const QRectF& rect) override;
|
||||
/** \copydoc JKQTPVectorFieldGraph::draw() */
|
||||
virtual void draw(JKQTPEnhancedPainter& painter) override;
|
||||
|
||||
/** \copydoc JKQTPGraph::setParent() */
|
||||
virtual void setParent(JKQTBasePlotter* parent) override;
|
||||
/** \copydoc JKQTPGraph::getOutsideSize() */
|
||||
virtual void getOutsideSize(JKQTPEnhancedPainter& painter, int& leftSpace, int& rightSpace, int& topSpace, int& bottomSpace) override;
|
||||
/** \copydoc JKQTPGraph::drawOutside() */
|
||||
virtual void drawOutside(JKQTPEnhancedPainter& painter, QRect leftSpace, QRect rightSpace, QRect topSpace, QRect bottomSpace) override;
|
||||
/** \brief determine min/max data value of the image */
|
||||
virtual void cbGetDataMinMax(double& imin, double& imax) override;
|
||||
/** \copydoc JKQTPGraph::usesColumn() */
|
||||
virtual bool usesColumn(int c) const override;
|
||||
|
||||
|
||||
/** \copydoc colorColumn */
|
||||
void setColorColumn(int __value);
|
||||
/** \copydoc colorColumn */
|
||||
int getColorColumn() const;
|
||||
/** \copydoc colorColumn */
|
||||
void setColorColumn (size_t __value);
|
||||
/** \copydoc colorColumnContainsRGB */
|
||||
void setColorColumnContainsRGB(bool __value);
|
||||
/** \copydoc colorColumnContainsRGB */
|
||||
bool getColorColumnContainsRGB() const;
|
||||
/** \copydoc m_vectorColorMode */
|
||||
void setVectorColorMode(VectorColorMode __value);
|
||||
/** \copydoc m_vectorColorMode */
|
||||
VectorColorMode getVectorColorMode() const;
|
||||
|
||||
protected:
|
||||
/** \copdydoc JKQTPVectorFieldGraph::getLocalVectorColor() */
|
||||
virtual QColor getLocalVectorColor(int i,double x,double y,double dx,double dy) const override;
|
||||
private:
|
||||
/** \brief this column contains the symbol color
|
||||
*
|
||||
* \see setColorColumn(), getColorColumn()
|
||||
*/
|
||||
int m_colorColumn;
|
||||
/** \brief if this is true, the value in the colorColumn is converted to an integer, representing a color in ARGB format (as in QRgb)
|
||||
*
|
||||
* \see setColorColumnContainsRGB(), getColorColumnContainsRGB()
|
||||
*/
|
||||
bool m_colorColumnContainsRGB;
|
||||
/** \brief internally used to store the range of the color column
|
||||
* \internal
|
||||
*/
|
||||
double m_intColMin;
|
||||
/** \brief internally used to store the range of the color column
|
||||
* \internal
|
||||
*/
|
||||
double m_intColMax;
|
||||
/** \brief indicates how color is determined from data (either from the vector or from m_colorColumn) */
|
||||
VectorColorMode m_vectorColorMode;
|
||||
|
||||
};
|
||||
|
||||
#endif // jkqtpvectorfield_H
|
||||
|
@ -960,7 +960,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPSingleColumnGraph: public JKQTPGraph {
|
||||
/** \brief This virtual JKQTPGraph descendent extends JKQTPXYGraph with two additional columns that encode for a vector starting at (x,y), i.e. either two distances along the x- and y-axis (\f$ \Delta x, \Delta y \f$), or a rotation angle \f$ \alpha \f$ and a vector length \f$ \l \f$ .
|
||||
* \ingroup jkqtplotter_basegraphs
|
||||
*
|
||||
* \see JKQTPVectorFieldGraph
|
||||
* \see JKQTPVectorFieldGraph, JKQTPParametrizedVectorFieldGraph
|
||||
*/
|
||||
class JKQTPLOTTER_LIB_EXPORT JKQTPXYAndVectorGraph: public JKQTPXYGraph {
|
||||
Q_OBJECT
|
||||
@ -1025,6 +1025,22 @@ public Q_SLOTS:
|
||||
/** \copydoc lengthColumn */
|
||||
void setLengthColumn(int col) ;
|
||||
protected:
|
||||
/** \brief calculates the magnitude/length of a vector \a v */
|
||||
static inline double getVectorMagnitude(const QPointF& v) {
|
||||
return sqrt(jkqtp_sqr(v.x())+jkqtp_sqr(v.y()));
|
||||
}
|
||||
inline double getVectorMagnitude(int i) const {
|
||||
return getVectorMagnitude(getVectorDxDy(i));
|
||||
}
|
||||
/** \brief calculates the rotation angle (3 o'clock is 0) in radians \f$ [0...2\pi] \f$ of a vector \a v */
|
||||
static inline double getVectorAngle(const QPointF& v) {
|
||||
double colValue=atan2(v.y(),v.x());
|
||||
if (colValue<0) colValue=2.0*JKQTPSTATISTICS_PI+colValue;
|
||||
return colValue;
|
||||
}
|
||||
inline double getVectorAngle(int i) const {
|
||||
return getVectorAngle(getVectorDxDy(i));
|
||||
}
|
||||
/** \brief this function interprets vectorDataLayout together with (dxColumn, dyColumn) or (angleColumn, lengthColumn) or ... and returns the \a i -th vectors \f$ \Delta x, \Delta y \f$ */
|
||||
QPointF getVectorDxDy(int i) const;
|
||||
|
||||
|
BIN
screenshots/paramvectorfield.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
screenshots/paramvectorfield_small.png
Normal file
After Width: | Height: | Size: 15 KiB |