new: Statistics library with functions to calculate histograms, regression, kernel density estimates, ... including a new example

new: iterator interface and improved documentation for JKQTPDatastore
reorganization of library (better separation of common code in jkqtpcommon and other code e.g. in jkqtplotter or jkqtmathtext)
This commit is contained in:
jkriege2 2019-05-29 22:40:02 +02:00
parent 212233aed6
commit 356cc34349
148 changed files with 8076 additions and 2775 deletions

View File

@ -4,9 +4,10 @@ SUBDIRS += jkqtplotterlib \
jkqtplotterlib_sharedlib \
jkqtmathtextlib \
jkqtmathtextlib_sharedlib \
jkqtpcommonlib \
jkqtpcommonlib_sharedlib \
jkqtfastplotterlib \
jkqtfastplotterlib_sharedlib \
jkqtphighrestimerlib \
jkqtmathtext_simpletest \
jkqtplot_test \
jkqtplotter_simpletest \
@ -20,13 +21,14 @@ jkqtplotterlib_sharedlib.file = sharedlib/jkqtplotterlib/jkqtplotterlib.pro
jkqtmathtextlib.file = staticlib/jkqtmathtextlib/jkqtmathtextlib.pro
jkqtmathtextlib_sharedlib.file = sharedlib/jkqtmathtextlib/jkqtmathtextlib.pro
jkqtpcommonlib.file = staticlib/jkqtpcommonlib/jkqtpcommonlib.pro
jkqtpcommonlib_sharedlib.file = sharedlib/jkqtpcommonlib/jkqtpcommonlib.pro
jkqtfastplotterlib.file = staticlib/jkqtfastplotterlib/jkqtfastplotterlib.pro
jkqtfastplotterlib_sharedlib.file = sharedlib/jkqtfastplotterlib/jkqtfastplotterlib.pro
jkqtphighrestimerlib.file = staticlib/jkqtphighrestimerlib/jkqtphighrestimerlib.pro
jkqtmathtext_simpletest.subdir = examples/jkqtmathtext_simpletest
jkqtmathtext_simpletest.depends = jkqtmathtextlib jkqtphighrestimerlib
jkqtmathtext_simpletest.depends = jkqtmathtextlib
jkqtmathtext_test.subdir = examples/jkqtmathtext_test
jkqtmathtext_test.depends = jkqtplotterlib

View File

@ -146,13 +146,16 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
</table>
\subsection jkqtp_extut_datamanagement Data Management
\subsection jkqtp_extut_datamanagement Data Management & Statistics
<table>
<tr><th> Screenshot <th> Description <th> Notes
<tr><td> \image html simpletest_datastore_small.png
<td> \subpage JKQTPlotterBasicJKQTPDatastore
<td> Basic Data Management with JKQTPDatastore <br/> Copying data into a JKQTPDatastore <br/> Editing data inside a JKQTPDatastore <br/> Editing Image Data in a JKQTPDatastore
<tr><td> \image html simpletest_datastore_statistics_small.png
<td> \subpage JKQTPlotterBasicJKQTPDatastoreStatistics
<td> Advanced 1-Dimensional Statistical Computation with JKQTPODatastore (and the internal statistics library, see \ref jkqtptools_math_statistics )
</table>

View File

@ -11,43 +11,108 @@ functionaly groups.
\defgroup jkqtptools_algorithms Diverse Algorithms
\ingroup jkqtptools
\defgroup jkqtptools_math Mathematical Computations & Equation Parsing
\defgroup jkqtptools_math Mathematical Computations & Expression Parsing
\ingroup jkqtptools
\defgroup jkqtptools_math_basic Basic Math Functions
\defgroup jkqtptools_math_basic Mathematical Functions & Tools
\ingroup jkqtptools_math
\defgroup jkqtptools_math_statistics Tools for Statistical Computations
\ingroup jkqtptools_math
This group assembles a variety of mathematical tool functions that are used in different places.
\defgroup jkqtptools_math_array Data Array Tools
\ingroup jkqtptools_math
Functions in this group form the basis for the statistics (\ref jkqtptools_math_statistics ) and linear algebra libraries (\ref jkqtptools_math_linalg ), by providing allocation and freeing of (aligned) memory arrays.
\seeJKQTPlotterBasicJKQTPDatastoreStatistics
\defgroup jkqtptools_math_linalg Linear Algebra Tools
\ingroup jkqtptools_math
This group assembles a basic set of linear algebra methods, including matrix inversion, which are required e.g. by the statistics library (\ref jkqtptools_math_statistics )
\defgroup jkqtptools_math_statistics Statistical Computations
\ingroup jkqtptools_math
This group contains a statistics library, which offers several basic methods and is based on an iterator interface:
- \ref jkqtptools_math_statistics_basic
- \ref jkqtptools_math_statistics_regression
- \ref jkqtptools_math_statistics_1dhist
- \ref jkqtptools_math_statistics_2dhist
- \ref jkqtptools_math_statistics_1dkde
- \ref jkqtptools_math_statistics_2dkde
.
All statistics functions use an iterator-based interface, comparable to the interface of the <a href="http://www.cplusplus.com/reference/algorithm/">algorithms in the C++ standard template library</a>. To this end, the class `JKQTPDatastore` provides an iterator interface to its columns, using the functions `JKQTPDatastore::begin()` and `JKQTPDatastore::end()`. Both functions simply receive the column ID as parameter and exist in a const and a mutable variant. the latter allows to also edit the data. In addition the function `JKQTPDatastore::backInserter()` returns a back-inserter iterator (like generated for STL containers with `std::back_inserter(container)`) that also allows to append to the column.
Note that the iterator interface allows to use these functions with any container that provides such iterators (e.g. `std::vector<double>`, `std::list<int>`, `std::set<float>`, `QVector<double>`...).
Code using one of these statistics functions therefore may look e.g. like this:
\code
// mean of a column in a JKQTPDatastore:
double mean=jkqtpstatAverage(datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1));
// mean of a std::vector
std::vector<double> data {1,2,4,5,7,8,10,2,1,3,5};
double meanvec=jkqtpstatAverage(data.begin(), data.end());
\endcode
All statistics functions use all values in the given range and convert each value to a `double`, using `jkqtp_todouble()`. The return values is always a dohble. Therefore you can use these functions to calculate statistics of ranges of any type that can be converted to `double`. Values that do not result in a valid `double`are not used in calculating the statistics. Therefore you can exclude values by setting them `JKQTP_DOUBLE_NAN` (i.e. "not a number").
\see see for detailed examples: \ref JKQTPlotterBasicJKQTPDatastoreStatistics
\defgroup jkqtptools_math_statistics_basic Basic statistics
\ingroup jkqtptools_math_statistics
\defgroup jkqtptools_math_statistics_regression Regression Analysis
\ingroup jkqtptools_math_statistics
\defgroup jkqtptools_math_statistics_1dhist 1-dimensional Histograms
\ingroup jkqtptools_math_statistics
\defgroup jkqtptools_math_statistics_2dhist 2-dimensional Histograms
\ingroup jkqtptools_math_statistics
\defgroup jkqtptools_math_statistics_1dkde 1-dimensional Kernel Density Estimates
\ingroup jkqtptools_math_statistics
\defgroup jkqtptools_math_statistics_2dkde 2-dimensional Kernel Density Estimates
\ingroup jkqtptools_math_statistics
\defgroup jkqtptools_string String/String-Conversion Tool Functions
\ingroup jkqtptools
Offers diverse function to convert different datatypes (e.g. double, int, diverse enums) to and from strings and for string manipulation.
\defgroup jkqtptools_qt Additional Tools for Qt
\ingroup jkqtptools
\defgroup jkqtptools_qtwidgets Additional Widgets for Qt
\ingroup jkqtptools
\defgroup jkqtptools_drawing Drawing & Graphics Tools
\ingroup jkqtptools
Specialized drawing functions used by the plotters and LaTeX renderers.
\defgroup jkqtptools_debugging Debugging Tools
\ingroup jkqtptools
Functions that help during debugging (e.g. an assert function/macro).
\defgroup jkqtptools_codestructuring Code Structuring Tools
\ingroup jkqtptools
Classes and functions that help to structure the code (e.g. RAII constructs)
\defgroup jkqtptools_enums Enums for JKQTPlotter (including String Conversion)
\ingroup jkqtptools
Assembles diverse ENUMs required by JKQTPlotter.
@ -150,7 +215,7 @@ With these there are usually two variants of one type of graph: One without erro
This approach allows to keep interfaces and appearance recognizeable over different graph classes and locates the source code
for a feature like error indicators in a single/in few class(es).
Another example of such a class is JKQTPColorPaletteTools, which provides functions that allow to use color palettes. It is
Another example of such a class is JKQTPColorPaletteStyleAndToolsMixin, which provides functions that allow to use color palettes. It is
mainly used for the \ref jkqtplotter_imagelots "Image/Matrix graphs", but also by e.g. JKQTPXYParametrizedScatterGraph.

View File

@ -44,6 +44,8 @@ Changes, compared to \ref page_whatsnew_V2018_08 "v2018.08" include:
<li> new: advanced styling options for boxplots + example for the styling: \ref JKQTPlotterBoxplotStyling </li>
<li> new: notched boxplots, see: \ref JKQTPlotterBoxplotStyling </li>
<li> new: several new plot symbols, see: JKQTPGraphSymbols </li>
<li> new: Statistics library with functions to calculate histograms, regression, kernel density estimates, ... see: \ref jkqtptools_statistics </li>
<li> new: iterator interface and improved documentation for JKQTPDatastore </li>
<li> changed: removed old selection-code and replaced by general highlighting feature </li>
<li> changed: JKQTPStepHorizontalGraph has been renamed to JKQTPSpecialLineHorizontalGraph (vertical variants also) and have gained additional features (baseline for filling and drawing of symbols) </li>
<li> changed: filled curve graphs (e.g. JKQTPSpecialLineHorizontalGraph) are now merely a specializedly initialized JKQTPSpecialLineHorizontalGraph </li>

View File

@ -59,22 +59,12 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
## Data Management
## Data Management (Tutorials) & Statistics
| Screenshot | Description | Notes |
|:-------------:| ------------- | ------------- |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/simpletest_datastore_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore) | [Tutorial: Basic Usage of JKQTPDatastore](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore) | Basic Data Management with JKQTPDatastore <br/> Copying data into a JKQTPDatastore <br/> Editing data inside a JKQTPDatastore <br/> Editing Image Data in a JKQTPDatastore |
## More Complex Examples
| Screenshot | Description | Notes |
|:-------------:| ------------- | ------------- |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/test_multiplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/test_multiplot) | [Layouting Several Plots](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/test_multiplot) | Combining plots in Qt Layouts <br> linking plot axes <br> copy data from a `std::map` int the datastore <br> print plots/print preview |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/test_distributionplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/test_distributionplot) | [Plotting a Statistical Distribution of Data](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/test_distributionplot) | Combines several different graphs to draw random values, their distribution and some statistical properties |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/simpletest_datastore_statistics_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics) | [Tutorial: Advanced 1-Dimensional Statistics with JKQTPDatastore](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics) | Advanced 1-Dimensional Statistical Computation with JKQTPDatastore (and the internal statistics library) |
## More Complex Examples

View File

@ -39,13 +39,9 @@ DEPENDPATH += ../../lib ../../staticlib/jkqtmathtextlib
INCLUDEPATH += ../../lib
CONFIG (debug, debug|release) {
DEPENDPATH += ../../staticlib/jkqtmathtextlib/debug
DEPENDPATH += ../../staticlib/jkqtphighrestimerlib/debug
LIBS += -L../../staticlib/jkqtmathtextlib/debug -ljkqtmathtextlib_debug
LIBS += -L../../staticlib/jkqtphighrestimerlib/debug -ljkqtphighrestimerlib_debug
} else {
DEPENDPATH += ../../staticlib/jkqtmathtextlib/release
DEPENDPATH += ../../staticlib/jkqtphighrestimerlib/release
LIBS += -L../../staticlib/jkqtmathtextlib/release -ljkqtmathtextlib
LIBS += -L../../staticlib/jkqtphighrestimerlib/release -ljkqtphighrestimerlib
}
message("LIBS = $$LIBS")

View File

@ -1,9 +1,8 @@
TEMPLATE = subdirs
SUBDIRS += jkqtmathtextlib jkqtphighrestimerlib jkqtmathtext_test
SUBDIRS += jkqtmathtextlib jkqtmathtext_test
jkqtmathtextlib.file = ../../staticlib/jkqtmathtextlib/jkqtmathtextlib.pro
jkqtphighrestimerlib.file = ../../staticlib/jkqtphighrestimerlib/jkqtphighrestimerlib.pro
jkqtmathtext_test.file=$$PWD/jkqtmathtext_test.pro
jkqtmathtext_test.depends = jkqtmathtextlib jkqtphighrestimerlib
jkqtmathtext_test.depends = jkqtmathtextlib

View File

@ -4,7 +4,7 @@
#include <QWidget>
#include <QStringList>
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtplottertools/jkqtphighrestimer.h"
#include "jkqtcommon/jkqtphighrestimer.h"
#include <QPainter>
#include <QTreeWidget>

View File

@ -17,7 +17,7 @@
#include "jkqtplotter/jkqtpgraphsparsedfunction.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplottergui/jkqtpgraphsmodel.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#define N1 200
#define N2 50

View File

@ -18,7 +18,7 @@
#include "jkqtplotter/jkqtpgraphsparsedfunction.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplottergui/jkqtpgraphsmodel.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#define N1 200
#define N2 50

View File

@ -17,7 +17,7 @@
#include "jkqtplotter/jkqtpgraphsparsedfunction.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplottergui/jkqtpgraphsmodel.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#define N1 200
#define N2 50

View File

@ -18,7 +18,7 @@
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplottergui/jkqtpgraphsmodel.h"
#include "jkqtplottergui/jkqtpcomboboxes.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#define N1 200
#define N2 50

View File

@ -17,7 +17,7 @@
#include "jkqtplotter/jkqtpgraphsparsedfunction.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplottergui/jkqtpgraphsmodel.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#define N1 200
#define N2 50

View File

@ -17,7 +17,7 @@
#include "jkqtplotter/jkqtpgraphsparsedfunction.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplottergui/jkqtpgraphsmodel.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#define N1 200
#define N2 50

View File

@ -17,7 +17,7 @@
#include "jkqtplotter/jkqtpgraphsparsedfunction.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplottergui/jkqtpgraphsmodel.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#define N1 200
#define N2 50

View File

@ -17,7 +17,7 @@
#include "jkqtplotter/jkqtpgraphsparsedfunction.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplottergui/jkqtpgraphsmodel.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"

View File

@ -17,7 +17,7 @@
#include "jkqtplotter/jkqtpgraphsparsedfunction.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplottergui/jkqtpgraphsmodel.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#define N1 200
#define N2 50

View File

@ -18,7 +18,7 @@
#include "jkqtplotter/jkqtpgraphsparsedfunction.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplottergui/jkqtpgraphsmodel.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#define N1 200
#define N2 50

View File

@ -1,6 +1,6 @@
# Tutorial (JKQTPlotter): Basic Usage of JKQTPDatastore {#JKQTPlotterBasicJKQTPDatastore}
This project (see `./examples/simpletest_datastore/`) explains several advanced options of JKQTPDatastore, which is the class used to centrally store the data for (most) graphs on a JKQTPlotter widget.
This tutorial project (see `./examples/simpletest_datastore/`) explains several options of JKQTPDatastore, which is the class used to centrally store the data for (most) graphs on a JKQTPlotter widget.
[TOC]
@ -140,6 +140,22 @@ Plotting these two columns versus each other results in a simple sine graph:
![simpletest_datastore_sine](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/simpletest_datastore_sine.png)
## Iterator Interface
Alternatively you can also access the column via a C++ iterator:
```.cpp
auto itX=datastore->begin(colX))
auto itY=datastore->begin(colY))
for (; itX!=datastore->end(colX); ++itX, ++itY) {
const double x=double(i)/double(Ndata)*8.0*M_PI;
*itX=x;
*itY=sin(x);
}
```
This, together with `JKQTPDatastore::backInserter()` allows to use `JKQTDatastore` together with algorithms from the C++ standard template libarary and other templated algorithms based on the same iterator-based interfaces (e.g. in boost).
## Generating Columns Preinitialized Columns
@ -177,6 +193,15 @@ You can use the methods `JKQTPDatastore::appendToColumn()` and `JKQTPDatastore::
```
Note that this operation changes the column length (number of rows). If the memory was externally managed before, it will be internally managed afterwards! If the first append is called on a column that cannot be extended, the contents will be copied and the column will reference the new, internally managed, memory afterwards.
Alterantively there is also a `std::back_inserter`-like interface to append to a column:
```.cpp
auto it=datastore->backInserter(columnID);
for (double ii=10; ii<=20; ii++) *++it=ii;
```
This, together with `JKQTPDatastore::begin()` and `JKQTPDatatstore::end()` allows to use `JKQTDatastore` together with algorithms from the C++ standard template libarary and other templated algorithms based on the same iterator-based interfaces (e.g. in boost).
## Using Data from one Column to Calculate Another

View File

@ -0,0 +1,235 @@
# Tutorial (JKQTPlotter): Advanced 1-Dimensional Statistics with JKQTPDatastore {#JKQTPlotterBasicJKQTPDatastoreStatistics}
This tutorial project (see `./examples/simpletest_datastore_statistics/`) explains several advanced functions of JKQTPDatastore in combination with the statistics library conatined in JKQTPlotter.
[TOC]
The source code of the main application can be found in [`jkqtplotter_simpletest_datastore_statistics.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics/jkqtplotter_simpletest_datastore_statistics.cpp).
This tutorial cites only parts of this code to demonstrate different ways of working with data for the graphs.
## Generating different sets of random numbers
The code segments below will fill four instances of JKQTPlotter with different statistical plots. All these plots are based on three sets of random numbers generated as shown here:
```.cpp
size_t randomdatacol1=datastore1->addColumn("random data 1");
size_t randomdatacol2=datastore1->addColumn("random data 2");
size_t randomdatacol3=datastore1->addColumn("random data 3");
std::random_device rd; // random number generators:
std::mt19937 gen{rd()};
std::uniform_int_distribution<> ddecide(0,1);
std::normal_distribution<> d1{0,1};
std::normal_distribution<> d2{6,1.2};
for (size_t i=0; i<150; i++) {
double v=0;
const int decide=ddecide(gen);
if (decide==0) v=d1(gen);
else v=d2(gen);
datastore1->appendToColumn(randomdatacol1, v);
if (decide==0) datastore1->appendToColumn(randomdatacol2, v);
else datastore1->appendToColumn(randomdatacol3, v);
}
```
The column `randomdatacol1` will contain 150 random numbers. Each one is drawn either from a normal dirstribution N(0,1) (`d1`) or N(6,1.2) (`d2`). the decision, which of the two to use is based on the result of a third random distribution ddecide, which only returns 0 or 1. The two columns `randomdatacol2` and `randomdatacol3` only collect the random numbers drawn from `d1` or `d2` respectively.
The three columns are generated empyt by calling `JKQTPDatastore::addColumn()` with only a name. Then the actual values are added by calling `JKQTPDatastore::appendToColumn()`.
## Basic Statistics
The three sets of random numbers from above can be visualized e.g. by a `JKQTPPeakStreamGraph` graph with code as follows:
```.cpp
JKQTPPeakStreamGraph* gData1;
plot1box->addGraph(gData1=new JKQTPPeakStreamGraph(plot1box));
gData1->setDataColumn(randomdatacol1);
gData1->setBaseline(-0.1);
gData1->setPeakHeight(-0.05);
gData1->setDrawBaseline(false);
```
This (if repeated for all three columns) results in a plot like this:
![jkqtplotter_simpletest_datastore_statistics_dataonly](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_dataonly.png)
Based on the raw data we can now use JKQTPlotter's statistics library to calculate some basic properties, like the average (`jkqtpstatAverage()`) or the standard deviation (`jkqtpstatStdDev()`):
```.cpp
size_t N=0;
double mean=jkqtpstatAverage(datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), &N);
double std=jkqtpstatStdDev(datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1));
```
Both statistics functions (the same as all statistics functions in the library) use an iterator-based interface, comparable to the interface of the algorithms in the C++ standard template library. To this end, the class `JKQTPDatastore` provides an iterator interface to its columns, using the functions `JKQTPDatastore::begin()` and `JKQTPDatastore::end()`. Both functions simply receive the column ID as parameter and exist in a const and a mutable variant. the latter allows to also edit the data. In addition the function `JKQTPDatastore::backInserter()` returns a back-inserter iterator (like generated for STL containers with `std::back_inserter(container)`) that also allows to append to the column.
note that the iterator interface allows to use these functions with any container that provides such iterators (e.g. `std::vector<double>`, `std::list<int>`, `std::set<float>`, `QVector<double>`...).
The output of these functions is shown in the image above in the plot legend/key.
Of course, several other functions exist that calculate basic statistics from a column, e.g.:
- average/mean: `jkqtpstatAverage()`, `jkqtpstatWeightedAverage()`
- number of usable values in a range:`jkqtpstatCount()`
- minimum/maximum: `jkqtpstatMinMax()`, `jkqtpstatMin()`, `jkqtpstatMax()`
- sum: `jkqtpstatSum()`
- variance: `jkqtpstatVariance()`, `jkqtpstatWeightedVariance()`
- standard deviation: `jkqtpstatStdDev()`, `jkqtpstatWeightedStdDev()`
- skewnes`jkqtpstatSkewness()`
- statistical moments: `jkqtpstatCentralMoment()`, `jkqtpstatMoment()`
- correlation coefficients: `jkqtpstatCorrelationCoefficient()`
- median: `jkqtpstatMedian()`
- quantile: `jkqtpstatQuantile()`
- (N)MAD: `jkqtpstatMAD()`, `jkqtpstatNMAD()`
- 5-Number Summary (e.g. for boxplots): `jkqtpstat5NumberStatistics()`, `jkqtpstat5NumberStatisticsAndOutliers()`, `jkqtpstat5NumberStatisticsOfSortedVector()`, `jkqtpstat5NumberStatisticsAndOutliersOfSortedVector()`
All these functions use all values in the given range and convert each value to a `double`, using `jkqtp_todouble()`. The return values is always a dohble. Therefore you can use these functions to calculate statistics of ranges of any type that can be converted to `double`. Values that do not result in a valid `double`are not used in calculating the statistics. Therefore you can exclude values by setting them `JKQTP_DOUBLE_NAN` (i.e. "not a number").
## Boxplots
### Standard Boxplots
As mentioned above and shown in several other examples, JKQTPlotter supports [Boxplots](https://en.wikipedia.org/wiki/Box_plot) with the classes `JKQTPBoxplotHorizontalElement`, `JKQTPBoxplotVerticalElement`, as well as `JKQTPBoxplotHorizontal` and `JKQTPBoxplotVertical`. You can then use the 5-Number Summray functions from the statistics library to calculate the data for such a boxplot (e.g. `jkqtpstat5NumberStatistics()`) and set it up by hand. Code would look roughly like this:
```.cpp
JKQTPStat5NumberStatistics stat=jkqtpstat5NumberStatistics(data.begin(), data.end(), 0.25, .5);
JKQTPBoxplotVerticalElement* res=new JKQTPBoxplotVerticalElement(plotter);
res->setMin(stat.minimum);
res->setMax(stat.maximum);
res->setMedian(stat.median);
res->setMean(jkqtpstatAverage(first, last));
res->setPercentile25(stat.quantile1);
res->setPercentile75(stat.quantile2);
res->setMedianConfidenceIntervalWidth(stat.IQRSignificanceEstimate());
res->setDrawMean(true);
res->setDrawNotch(true);
res->setDrawMedian(true);
res->setDrawMinMax(true);
res->setDrawBox(true);
res->setPos(boxposX);
plotter->addGraph(res);
```
In order to save you the work of writing out this code, the statistics library provides "adaptors", such as `jkqtpstatAddVBoxplot()`, which basically implements the code above. Then drawing a boxplot is reduced to:
```.cpp
JKQTPBoxplotHorizontalElement* gBox2=jkqtpstatAddHBoxplot(plot1box->getPlotter(), datastore1->begin(randomdatacol2), datastore1->end(randomdatacol2), -0.25);
gBox2->setColor(gData2->getKeyLabelColor());
gBox2->setBoxWidthAbsolute(16);
```
Here `-0.25`indicates the location (on the y-axis) of the boxplot. and the plot is calculated for the data in the `JKQTPDatastore` column `randomdatacol2`.
![jkqtplotter_simpletest_datastore_statistics_boxplots_simple](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_boxplots_simple.png)
### Boxplots with Outliers
Usually the boxplot draws its whiskers at the minimum and maximum value of the dataset. But if your data contains a lot of outliers, it may make sense to draw them e.g. at the 3% and 97% quantiles and the draw the outliers as additional data points. This can also be done with `jkqtpstat5NumberStatistics()`, as you can specify the minimum and maximum quantile (default is 0 and 1, i.e. the true minimum and maximum) and the resulting object contains a vector with the outlier values. Then you could add them to the JKQTPDatastore and add a scatter plot that displays them. Also this task is sped up by an "adaptor". Simply call
```.cpp
std::pair<JKQTPBoxplotHorizontalElement*,JKQTPSingleColumnSymbolsGraph*> gBox1;
gBox1=jkqtpstatAddHBoxplotAndOutliers(plot1box->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -0.3,
0.25, 0.75, // 1. and 3. Quartile for the boxplot box
0.03, 0.97 // Quantiles for the boxplot box whiskers' ends
);
```
As you can see this restuns the `JKQTPBoxplotHorizontalElement` and in addition a `JKQTPSingleColumnSymbolsGraph` for the display of the outliers. The result looks like this:
![jkqtplotter_simpletest_datastore_statistics_boxplots_outliers](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_boxplots_outliers.png)
## Histograms
Calculating 1D-Histograms is supported by several functions from the statistics library, e.g. `jkqtpstatHistogram1DAutoranged()`. You can use the result to fill new columns in a `JKQTPDatastore`, which can then be used to draw the histogram (here wit 15 bins, spanning the full data range):
```.cpp
size_t histcolX=plotter->getDatastore()->addColumn(histogramcolumnBaseName+", bins");
size_t histcolY=plotter->getDatastore()->addColumn(histogramcolumnBaseName+", values");
jkqtpstatHistogram1DAutoranged(first, last, plotter->getDatastore()->backInserter(histcolX), plotter->getDatastore()->backInserter(histcolY), 15);
JKQTPBarVerticalGraph* resO=new JKQTPBarVerticalGraph(plotter);
resO->setXColumn(histcolX);
resO->setYColumn(histcolY);
resO->setTitle(histogramcolumnBaseName);
plotter->addGraph(resO);
```
Again there are "adaptors" which significanty reduce the amount of coude you have to type:
```.cpp
JKQTPBarVerticalGraph* hist1=jkqtpstatAddHHistogram1DAutoranged(plot1->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), 15);
```
The resulting plot looks like this (the distributions used to generate the random data are also shown as line plots!):
![jkqtplotter_simpletest_datastore_statistics_hist](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_hist.png)
## Kernel Density Estimates (KDE)
Especially when only few samples from a distribution are available, histograms are not good at representing the underlying data distribution. In such cases, [Kernel Density Estimates (KDE)](https://en.wikipedia.org/wiki/Kernel_density_estimation) can help, which are basically a smoothed variant of a histogram. The statistics library supports calculating them via e.g. `jkqtpstatKDE1D()`:
```.cpp
size_t kdecolX=plotter->getDatastore()->addColumn(KDEcolumnBaseName+", bins");
size_t kdecolY=plotter->getDatastore()->addColumn(KDEcolumnBaseName+", values");
jkqtpstatKDE1D(first, last, -5.0,0.01,10.0, plotter->getDatastore()->backInserter(kdecolX), plotter->getDatastore()->backInserter(kdecolY), kernel, kdeBandwidth);
JKQTPXYLineGraph* resO=new JKQTPXYLineGraph(plotter);
resO->setXColumn(kdecolX);
resO->setYColumn(kdecolY);
resO->setTitle(KDEcolumnBaseName);
resO->setDrawLine(true);
resO->setSymbolType(JKQTPNoSymbol);
plotter->addGraph(resO);
```
The function accepts different kernel functions (any C++ functor `double f(double x)`) and provides a set of default kernels, e.g.
- `jkqtpstatKernel1DEpanechnikov()`
- `jkqtpstatKernel1DGaussian()`
- `jkqtpstatKernel1DUniform()`
- ...
The three parameters `-5.0, 0.01, 10.0` tell the function `jkqtpstatKDE1D()` to evaluate the KDE at positions between -5 and 10, in steps of 0.01.
Finally the bandwidth constrols the smoothing and the statistics library provides a simple function to estimate it automatically from the data:
```.cpp
double kdeBandwidth=jkqtpstatEstimateKDEBandwidth(datastore1->begin(randomdatacol1subset), datastore1->end(randomdatacol1subset));
```
Again a shortcut "adaptor" simplifies this task:
```.cpp
JKQTPXYLineGraph* kde2=jkqtpstatAddHKDE1D(plot1kde->getPlotter(), datastore1->begin(randomdatacol1subset), datastore1->end(randomdatacol1subset),
// evaluate at locations between -5 and 10, in steps of 0.01 (equivalent to the line above, but without pre-calculating a vector)
-5.0,0.01,10.0,
// use a gaussian kernel
&jkqtpstatKernel1DEpanechnikov,
// estimate the bandwidth
kdeBandwidth);
```
Plots that result from such calls look like this:
![jkqtplotter_simpletest_datastore_statistics_kde](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_kde.png)
## Cummulative Histograms and KDEs
Both histograms and KDEs support a parameter `bool cummulative`, which allows to accumulate the data after calculation and drawing cummulative histograms/KDEs:
```.cpp
JKQTPBarVerticalGraph* histcum2=jkqtpstatAddHHistogram1DAutoranged(plot1cum->getPlotter(), datastore1->begin(randomdatacol2), datastore1->end(randomdatacol2),
// bin width
0.1,
// normalized, cummulative
false, true);
```
![jkqtplotter_simpletest_datastore_statistics_cumhistkde](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_cumhistkde.png)
## Screenshot of the full Program
The output of the full test program [`jkqtplotter_simpletest_datastore_statistics.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics/jkqtplotter_simpletest_datastore_statistics.cpp) looks like this:
![jkqtplotter_simpletest_datastore_statistics](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics.png)

View File

@ -0,0 +1,289 @@
/** \example jkqtplotter_simpletest_datastore_statistics.cpp
* Explains how to use the internal statistics library (see \ref jkqtptools_statistics ) together with JKQTPDatastore to generate advanced plots for 1-dimensional data.
*
* \ref JKQTPlottersimpletest_datastore_statistics
*/
#include <QApplication>
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/jkqtpgraphspeakstream.h"
#include "jkqtplotter/jkqtpgraphsboxplot.h"
#include "jkqtplotter/jkqtpgraphsstatisticsadaptors.h"
#include "jkqtplotter/jkqtpgraphsevaluatedfunction.h"
#include "jkqtcommon/jkqtpstatisticstools.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include <random>
#include <cmath>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
// 1. create a window with several plotters and get a pointer to the internal datastores (for convenience)
QWidget mainWidget;
QGridLayout* lay;
mainWidget.setLayout(lay=new QGridLayout);
JKQTPlotter* plot1=new JKQTPlotter(&mainWidget);
plot1->getPlotter()->setPlotLabel("Histograms and KDE");
JKQTPDatastore* datastore1=plot1->getDatastore();
lay->addWidget(plot1,1,0);
JKQTPlotter* plot1cum=new JKQTPlotter(datastore1, &mainWidget);
plot1cum->getPlotter()->setPlotLabel("Cummulative Histogram");
lay->addWidget(plot1cum,1,1);
JKQTPlotter* plot1kde=new JKQTPlotter(datastore1, &mainWidget);
plot1kde->getPlotter()->setPlotLabel("Kernel Density Estimate");
lay->addWidget(plot1kde,0,1);
JKQTPlotter* plot1box=new JKQTPlotter(datastore1, &mainWidget);
plot1box->getPlotter()->setPlotLabel("Boxplots");
lay->addWidget(plot1box,0,0);
// 2. Now we create two vectors with random values
// vector 1: The values are drawn from two different normal distributions d1 and d2,
// where for each datapoint the distribution is chosen randomly (by ddecide)
// vector 2: same values as in vector 1, if the value is drawn from d1
// vector 3: same values as in vector 1, if the value is drawn from d2
size_t randomdatacol1=datastore1->addColumn("random data 1");
size_t randomdatacol2=datastore1->addColumn("random data 2");
size_t randomdatacol3=datastore1->addColumn("random data 3");
std::random_device rd; // random number generators:
std::mt19937 gen{rd()};
std::uniform_int_distribution<> ddecide(0,1);
std::normal_distribution<> d1{0,1};
std::normal_distribution<> d2{6,1.2};
for (size_t i=0; i<150; i++) {
double v=0;
const int decide=ddecide(gen);
if (decide==0) v=d1(gen);
else v=d2(gen);
datastore1->appendToColumn(randomdatacol1, v);
if (decide==0) datastore1->appendToColumn(randomdatacol2, v);
else datastore1->appendToColumn(randomdatacol3, v);
}
QString d1_latex="$\\mathcal{N}("+jkqtp_floattolatexqstr(d1.mean(), 1)+","+jkqtp_floattolatexqstr(d1.stddev(), 1)+")$";
QString d2_latex="$\\mathcal{N}("+jkqtp_floattolatexqstr(d2.mean(), 1)+","+jkqtp_floattolatexqstr(d2.stddev(), 1)+")$";
// 3.1. To visualize the data, a simple JKQTPPeakStreamGraph is used:
JKQTPPeakStreamGraph* gData1;
plot1box->addGraph(gData1=new JKQTPPeakStreamGraph(plot1box));
gData1->setDataColumn(randomdatacol1);
gData1->setBaseline(-0.1);
gData1->setPeakHeight(-0.05);
gData1->setDrawBaseline(false);
// 3.2. We calculate some basic statistics of that column and display it in the graph legend (via the graph title):
// Here we use functions of the statistics library for the first time. The statistics library uses an iterator interface
// scheme, much like the algorithms of the C++ standard library. Therefore we the iterator interface of JKQTPDatastore
// when calling the statistics functions.
size_t N=0;
double mean=jkqtpstatAverage(datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), &N);
double std=jkqtpstatStdDev(datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1));
gData1->setTitle(QString("random data $"+d1_latex+"+"+d2_latex+"$: $\\overline{X_1}=%1, \\sigma_{X_1}=%2, N_{X_3}=%3$").arg(jkqtp_floattolatexqstr(mean, 2)).arg(jkqtp_floattolatexqstr(std, 2)).arg(N));
// 3.3. same as 3.1-3.2, but for the second and thirdcolumn of data:
JKQTPPeakStreamGraph* gData2;
plot1box->addGraph(gData2=new JKQTPPeakStreamGraph(plot1box));
gData2->setDataColumn(randomdatacol2);
gData2->setBaseline(-0.1);
gData2->setPeakHeight(0.05);
gData2->setDrawBaseline(false);
N=0;
mean=jkqtpstatAverage(datastore1->begin(randomdatacol2), datastore1->end(randomdatacol2), &N);
std=jkqtpstatStdDev(datastore1->begin(randomdatacol2), datastore1->end(randomdatacol2));
gData2->setTitle(QString("random data subset $"+d1_latex+"$: $\\overline{X_2}=%1, \\sigma_{X_3}=%2, N_{X_3}=%3$").arg(jkqtp_floattolatexqstr(mean, 2)).arg(jkqtp_floattolatexqstr(std, 2)).arg(N));
JKQTPPeakStreamGraph* gData3;
plot1box->addGraph(gData3=new JKQTPPeakStreamGraph(plot1box));
gData3->setDataColumn(randomdatacol3);
gData3->setBaseline(-0.15);
gData3->setPeakHeight(-0.05);
gData3->setDrawBaseline(false);
N=0;
mean=jkqtpstatAverage(datastore1->begin(randomdatacol3), datastore1->end(randomdatacol3), &N);
std=jkqtpstatStdDev(datastore1->begin(randomdatacol3), datastore1->end(randomdatacol3));
gData3->setTitle(QString("random data subset $"+d2_latex+"$: $\\overline{X_3}=%1, \\sigma_{X_3}=%2, N_{X_3}=%3$").arg(jkqtp_floattolatexqstr(mean, 2)).arg(jkqtp_floattolatexqstr(std, 2)).arg(N));
// 3.4. Now we calculate a 5-Value Summary of the two datasets and use it to plot corresponding boxplots
// This can be done by hand, or you can call jkqtpstatAddHBoxplot() which saves some typing. This function
// uses jkqtpstat5NumberStatistics() internally to calculate the statistics.
JKQTPBoxplotHorizontalElement* gBox2=jkqtpstatAddHBoxplot(plot1box->getPlotter(), datastore1->begin(randomdatacol2), datastore1->end(randomdatacol2), -0.25);
gBox2->setColor(gData2->getKeyLabelColor());
gBox2->setBoxWidthAbsolute(16);
JKQTPBoxplotHorizontalElement* gBox3=jkqtpstatAddHBoxplot(plot1box->getPlotter(), datastore1->begin(randomdatacol3), datastore1->end(randomdatacol3), -0.35);
gBox3->setColor(gData3->getKeyLabelColor());
gBox3->setBoxWidthAbsolute(16);
// 3.5. In addition to jkqtpstatAddHBoxplot() there is also jkqtpstatAddHBoxplotAndOutliers(), which generates two graphs:
// one JKQTPBoxplotHorizontalElement for the boxplot and one JKQTPSingleColumnSymbolsGraph for the outliers
// Note that this function generates additional data columns in the datastore of the provided plotter to represent
// the outlier locations.
// jkqtpstatAddHBoxplotAndOutliers() calculates the 3% and 97% Quantiles for the boxplots whiskers' ends. You can change that
// by supplying other quantiles to the call
std::pair<JKQTPBoxplotHorizontalElement*,JKQTPSingleColumnSymbolsGraph*> gBox1=jkqtpstatAddHBoxplotAndOutliers(plot1box->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -0.3);
// jkqtpstatAddHBoxplotAndOutliers() calculates the 3% and 97% Quantiles for the boxplots whiskers' ends. You can change that
// by supplying other quantiles to the call
//std::pair<JKQTPBoxplotHorizontalElement*,JKQTPXYLineGraph*> gBox1=jkqtpstatAddHBoxplotAndOutliers(plot1box->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -0.3,
// 0.25, 0.75, // 1. and 3. Quartile for the boxplot box
// 0.05, 0.95 // Quantiles for the boxplot box whiskers' ends
// );
gBox1.first->setColor(gData1->getKeyLabelColor());
gBox1.second->setColor(gData1->getKeyLabelColor());
gBox1.second->setSymbolType(JKQTPGraphSymbols::JKQTPCircle);
gBox1.second->setSymbolSize(7);
gBox1.first->setBoxWidthAbsolute(16);
// the simple alternative would have been:
//JKQTPBoxplotHorizontalElement* gBox1;
//plot1box->addGraph(gBox1=jkqtpstatAddHBoxplot(plot1box->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1)));
//gBox1->setPos(-0.3);
//gBox1->setColor(gData1->getKeyLabelColor());
//gBox1->setBoxWidthAbsolute(16);
// 4.1. We repeat the JKQTPPeakStreamGraph visualization from above:
plot1->addGraph(gData1=new JKQTPPeakStreamGraph(plot1));
gData1->setDataColumn(randomdatacol1);
gData1->setBaseline(-0.1);
gData1->setPeakHeight(-0.05);
gData1->setDrawBaseline(false);
gData1->setTitle("random data $"+d1_latex+"+"+d2_latex+"$");
// 4.2. same as 3.1-3.2, but for the second and thirdcolumn of data:
plot1->addGraph(gData2=new JKQTPPeakStreamGraph(plot1));
gData2->setDataColumn(randomdatacol2);
gData2->setBaseline(-0.1);
gData2->setPeakHeight(0.05);
gData2->setDrawBaseline(false);
gData2->setTitle("random data subset $"+d1_latex+"$");
plot1->addGraph(gData3=new JKQTPPeakStreamGraph(plot1));
gData3->setDataColumn(randomdatacol3);
gData3->setBaseline(-0.15);
gData3->setPeakHeight(-0.05);
gData3->setDrawBaseline(false);
gData3->setTitle("random data subset $"+d2_latex+"$");
// 4.3. for comparison we add plots of the initial distributions:
plot1->addGraph(new JKQTPXFunctionLineGraph(std::bind(&jkqtp_gaussdist, std::placeholders::_1, d1.mean(), d1.stddev()), d1_latex, plot1));
plot1->addGraph(new JKQTPXFunctionLineGraph(std::bind(&jkqtp_gaussdist, std::placeholders::_1, d2.mean(), d2.stddev()), d2_latex, plot1));
// 4.1. next we calculate a histogram of the data and add a plot to the graph:
JKQTPBarVerticalGraph* hist1=jkqtpstatAddHHistogram1DAutoranged(plot1->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), 15);
// here the bins are defined by the full range of the data and the bin count (15) is specified
// alternatively you could specify the bin width and the number would be calculated automatically:
//JKQTPBarVerticalGraph* hist1=jkqtpstatAddHHistogram1DAutoranged(plot1->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), 0.5);
// a third option is to define the bins via a vector of values (lower borders):
//std::vector<double> bins{-2,-1.5,-1,-0.75,-0.5,-0.25,0,0.25,0.5,0.75,1,1.5,2,2.5,3,4,5,6,7,8,9,10};
//JKQTPBarVerticalGraph* hist1=jkqtpstatAddHHistogram1D(plot1->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), bins.begin(), bins.end());
hist1->setColor(QColorWithAlphaF(gData1->getKeyLabelColor(), 0.5)); // use same color as gData1, but with alpha set to 0.5 (50% transparency)
// 5.1. instead of histograms, it can also make sense to calculate Kernel Density Estimates, especially when only few datapoints are available.
// To demonstrate this, we first calculate take a subset of the values in randomdatacol1 as a small test dataset.
size_t randomdatacol1subset=datastore1->copyColumn(randomdatacol1, 1, 7, "subset of "+datastore1->getColumnName(randomdatacol1));
JKQTPPeakStreamGraph* gData2kde;
plot1kde->addGraph(gData2kde=new JKQTPPeakStreamGraph(plot1kde));
gData2kde->setDataColumn(randomdatacol1subset);
gData2kde->setBaseline(-0.05);
gData2kde->setPeakHeight(-0.1);
gData2kde->setDrawBaseline(false);
gData2kde->setTitle("data");
// first we plot the histogram of this dataset, with 0.5 bin width:
JKQTPBarVerticalGraph* hist1kde=jkqtpstatAddHHistogram1DAutoranged(plot1kde->getPlotter(), datastore1->begin(randomdatacol1subset), datastore1->end(randomdatacol1subset), 0.5);
hist1kde->setTitle("histogram");
hist1kde->setColor(QColorWithAlphaF(gData2kde->getKeyLabelColor(), 0.25)); // use same color as gData1, but with alpha set to 0.5 (50% transparency)
// 5.2. now we first extimate the bandwidth:
double kdeBandwidth=jkqtpstatEstimateKDEBandwidth(datastore1->begin(randomdatacol1subset), datastore1->end(randomdatacol1subset));
// and generate a vector of positions, where we want to evaluate the KDE:
std::vector<double> xKDE;
for (double x=-5; x<=10; x+=0.01) xKDE.push_back(x);
// now the KDE can be added (gaussian kernel, evaluated at the positions in xKDE):
JKQTPXYLineGraph* kde1=jkqtpstatAddHKDE1D(plot1kde->getPlotter(), datastore1->begin(randomdatacol1subset), datastore1->end(randomdatacol1subset),
// evaluate at locations in xKDE
xKDE.begin(), xKDE.end(),
// use a gaussian kernel
&jkqtpstatKernel1DGaussian,
// estimate the bandwidth
kdeBandwidth);
kde1->setTitle("KDE, gaussian, $\\mbox{BW}="+jkqtp_floattolatexqstr(kdeBandwidth, 3)+"$");
JKQTPXYLineGraph* kde11=jkqtpstatAddHKDE1D(plot1kde->getPlotter(), datastore1->begin(randomdatacol1subset), datastore1->end(randomdatacol1subset),
// evaluate at locations in xKDE
xKDE.begin(), xKDE.end(),
// use a gaussian kernel
&jkqtpstatKernel1DGaussian,
// a very small bandwidth
0.1);
kde11->setTitle("KDE, gaussian, $\\mbox{BW}="+jkqtp_floattolatexqstr(0.1, 3)+"$");
// here a second KDE with a different kernel (Epanechnikov) and the range of evaluation positions defined via three numbers:
JKQTPXYLineGraph* kde2=jkqtpstatAddHKDE1D(plot1kde->getPlotter(), datastore1->begin(randomdatacol1subset), datastore1->end(randomdatacol1subset),
// evaluate at locations between -5 and 10, in steps of 0.01 (equivalent to the line above, but without pre-calculating a vector)
-5.0,0.01,10.0,
// use a gaussian kernel
&jkqtpstatKernel1DEpanechnikov,
// estimate the bandwidth
kdeBandwidth);
kde2->setTitle("KDE, epanechnikov, $\\mbox{BW}="+jkqtp_floattolatexqstr(kdeBandwidth, 3)+"$");
kde1->setColor(QColorWithAlphaF(gData2kde->getKeyLabelColor(), 0.5)); // use same color as gData1, but with alpha set to 0.5 (50% transparency)
// 5.3. for comparison we add plots of the initial distributions:
plot1kde->addGraph(new JKQTPXFunctionLineGraph(std::bind(&jkqtp_gaussdist, std::placeholders::_1, d1.mean(), d1.stddev()), d1_latex, plot1));
plot1kde->addGraph(new JKQTPXFunctionLineGraph(std::bind(&jkqtp_gaussdist, std::placeholders::_1, d2.mean(), d2.stddev()), d2_latex, plot1));
// 6.1. now we calculate a cummulative histogram:
JKQTPPeakStreamGraph* gData2com;
plot1cum->addGraph(gData2com=new JKQTPPeakStreamGraph(plot1cum));
gData2com->setDataColumn(randomdatacol2);
gData2com->setBaseline(-1);
gData2com->setPeakHeight(-10);
gData2com->setDrawBaseline(false);
JKQTPBarVerticalGraph* histcum2=jkqtpstatAddHHistogram1DAutoranged(plot1cum->getPlotter(), datastore1->begin(randomdatacol2), datastore1->end(randomdatacol2),
// bin width
0.1,
// normalized, cummulative
false, true);
histcum2->setColor(QColorWithAlphaF(gData2com->getKeyLabelColor(), 0.2)); // use same color as gData1, but with alpha set to 0.5 (50% transparency)
// 6.2. also a kernel density estimate can be accumulated:
JKQTPXYLineGraph* kdecum2=jkqtpstatAddHKDE1D(plot1cum->getPlotter(), datastore1->begin(randomdatacol2), datastore1->end(randomdatacol2),
// evaluate at locations between -3.5 and 3.5, in steps of 0.01
-3.5,0.01,3.5,
// use a uniform/box kernel
&jkqtpstatKernel1DUniform,
// estimate the bandwidth
jkqtpstatEstimateKDEBandwidth(datastore1->begin(randomdatacol2), datastore1->end(randomdatacol2)),
// cummulative KDE:
true);
kdecum2->setColor(gData2com->getKeyLabelColor()); // use same color as gData1, but with alpha set to 0.5 (50% transparency)
// autoscale the plot so the graph is contained
plot1->zoomToFit();
plot1->setGrid(false);
plot1->getXAxis()->setShowZeroAxis(false);
plot1->getPlotter()->setKeyBackgroundColor(QColorWithAlphaF("white", 0.25), Qt::SolidPattern);
plot1->setY(-0.25, 0.45);
plot1cum->zoomToFit();
plot1cum->setGrid(false);
plot1cum->getXAxis()->setShowZeroAxis(false);
plot1cum->getPlotter()->setKeyBackgroundColor(QColorWithAlphaF("white", 0.25), Qt::SolidPattern);
plot1kde->zoomToFit();
plot1kde->setGrid(false);
plot1kde->getXAxis()->setShowZeroAxis(false);
plot1kde->getPlotter()->setKeyBackgroundColor(QColorWithAlphaF("white", 0.25), Qt::SolidPattern);
plot1kde->setY(-0.155, 0.45);
plot1box->zoomToFit();
plot1box->setGrid(false);
plot1box->getXAxis()->setShowZeroAxis(false);
plot1box->getPlotter()->setKeyBackgroundColor(QColorWithAlphaF("white", 0.25), Qt::SolidPattern);
plot1box->setY(-0.4, 0.0);
// show plotter and make it a decent size
mainWidget.show();
mainWidget.resize(1200,800);
return app.exec();
}

View File

@ -0,0 +1,26 @@
# source code for this simple demo
SOURCES = jkqtplotter_simpletest_datastore_statistics.cpp
# configure Qt
CONFIG += link_prl qt
QT += core gui xml svg
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
# output executable name
TARGET = jkqtplotter_simpletest_datastore_statistics
# include JKQTPlotter source headers and link against library
DEPENDPATH += ../../lib ../../staticlib/jkqtplotterlib
INCLUDEPATH += ../../lib
CONFIG (debug, debug|release) {
LIBS += -L../../staticlib/jkqtplotterlib/debug -ljkqtplotterlib_debug
} else {
LIBS += -L../../staticlib/jkqtplotterlib/release -ljkqtplotterlib
}
message("LIBS = $$LIBS")
win32-msvc*: DEFINES += _USE_MATH_DEFINES

View File

@ -0,0 +1,8 @@
TEMPLATE = subdirs
SUBDIRS += jkqtplotterlib jkqtplotter_simpletest_datastore_statistics
jkqtplotterlib.file = ../../staticlib/jkqtplotterlib/jkqtplotterlib.pro
jkqtplotter_simpletest_datastore_statistics.file=$$PWD/jkqtplotter_simpletest_datastore_statistics.pro
jkqtplotter_simpletest_datastore_statistics.depends = jkqtplotterlib

View File

@ -12,7 +12,7 @@
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/jkqtpgraphsscatter.h"
#include "jkqtplotter/jkqtpgraphsgeometric.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/jkqtpgraphsfilledcurve.h"
void drawWithDateAxis(JKQTPlotter& plot) {

View File

@ -7,7 +7,7 @@
#include <QApplication>
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/jkqtpgraphsscatter.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
int main(int argc, char* argv[])

View File

@ -8,7 +8,7 @@
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/jkqtpgraphsscatter.h"
#include "jkqtplotter/jkqtpgraphsgeometric.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#define sqr(x) ((x)*(x))

View File

@ -10,7 +10,7 @@ Adding an evaluated funtion to a graph is very simple:
parsedFunc->setFunction("sin(x*8)*exp(-x/4)");
parsedFunc->setTitle("user function");
```
As you can see a graph of the type `JKQTPXParsedFunctionLineGraph` is used, which plots a function that depends on the variable `x`. The given function is parsed and evaluated (see [`lib/jkqtplottertools/jkqtpmathparser.h`](https://github.com/jkriege2/JKQTPlotter/blob/master/lib/jkqtplottertools/jkqtpmathparser.h) for details on the features of the math parser). An intelligent drawing algorithm chooses the number of control points for drawing a smooth graph, with sufficient amount of details, by evaluating locally the slope of the function.
As you can see a graph of the type `JKQTPXParsedFunctionLineGraph` is used, which plots a function that depends on the variable `x`. The given function is parsed and evaluated (see [`lib/jkqtcommon/jkqtpmathparser.h`](https://github.com/jkriege2/JKQTPlotter/blob/master/lib/jkqtcommon/jkqtpmathparser.h) for details on the features of the math parser). An intelligent drawing algorithm chooses the number of control points for drawing a smooth graph, with sufficient amount of details, by evaluating locally the slope of the function.
In the example in [`test/simpletest_parsedfunctionplot/simpletest_parsedfunctionplot.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_parsedfunctionplot/simpletest_parsedfunctionplot.cpp) we do not simply set a fixed function, but add a `QLineEdit` which allows to edit the function and redraws it, once ENTER is pressed:
```.cpp

View File

@ -8,7 +8,7 @@
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/jkqtpgraphsscatter.h"
#include "jkqtplotter/jkqtpgraphsspecialline.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
int main(int argc, char* argv[])
{

View File

@ -8,7 +8,7 @@
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/jkqtpgraphsscatter.h"
#include "jkqtplotter/jkqtpgraphsspecialline.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
int main(int argc, char* argv[])
{

View File

@ -7,7 +7,7 @@
#include <QApplication>
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/jkqtpgraphsscatter.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
int main(int argc, char* argv[])

View File

@ -7,6 +7,7 @@ If you use QMake and simply want to include all necessary files into your projec
- `jkqtplotter.pri` contains all files in this library, including `JKQTFastPlotter` and `JKQTMathText`
- `jkqtfastplotter.pri` contains only those files from this directory which are necessary to build `JKQTFastPlotter`
- `jkqtmathtext.pri` contains only those files from this directory which are necessary to build `JKQTMathText`
- `jkqtpcommon.pri` common support library for all libraries above (math tools, basic drawing tools, ...)
### Build static libraries
In the directory [`../staticlib`](../staticlib) you will find several Project files that build a static library of the full JKQTPlotter (including JKQTFastPlotter and JKMathText), or of subsets of this library. You can then link against these libs in your project.

View File

@ -1,33 +0,0 @@
!win32-msvc* {
QMAKE_CXXFLAGS += -fexceptions
} else {
QMAKE_CXXFLAGS += /EHsc
# /std:c++14
# To enable M_PI, M_E,...
DEFINES += _USE_MATH_DEFINES
# To fix error: C2338: va_start argument must not
# have reference type and must not be parenthesized
DEFINES += _CRT_NO_VA_START_VALIDATION
}
HEADERS += $$PWD/jkqtcommon/jkqtp_imexport.h \
$$PWD/jkqtcommon/jkqtptools.h \
$$PWD/jkqtcommon/jkqtptoolsdebugging.h \
$$PWD/jkqtcommon/jkqtpcommonmathtools.h \
$$PWD/jkqtcommon/jkqtpalgorithms.h \
$$PWD/jkqtcommon/jkqtpstringtools.h
SOURCES += $$PWD/jkqtcommon/jkqtptools.cpp \
$$PWD/jkqtcommon/jkqtptoolsdebugging.cpp \
$$PWD/jkqtcommon/jkqtpcommonmathtools.cpp \
$$PWD/jkqtcommon/jkqtpalgorithms.cpp \
$$PWD/jkqtcommon/jkqtpstringtools.cpp
INCLUDEPATH += $$PWD
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
CONFIG += c++11

View File

@ -0,0 +1,24 @@
/*
Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>)
last modification: $LastChangedDate$ (revision $Rev$)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License (LGPL) as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License (LGPL) for more details.
You should have received a copy of the GNU Lesser General Public License (LGPL)
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "jkqtparraytools.h"

View File

@ -0,0 +1,223 @@
/*
Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>)
last modification: $LastChangedDate$ (revision $Rev$)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License (LGPL) as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License (LGPL) for more details.
You should have received a copy of the GNU Lesser General Public License (LGPL)
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef JKQTPARRAYTOOLS_H_INCLUDED
#define JKQTPARRAYTOOLS_H_INCLUDED
#include <stdint.h>
#include <cmath>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <stdio.h>
#include <limits>
#include <vector>
#include <utility>
#include <cfloat>
#include <ostream>
#include <iomanip>
#include <sstream>
#include "jkqtcommon/jkqtp_imexport.h"
#ifdef _OPENMP
# include <omp.h>
#endif
#ifndef __LINUX__
# if defined(linux)
# define __LINUX__
# endif
#endif
#ifdef __LINUX__
#include <malloc.h>
#include <stdlib.h>
#endif
#ifndef JKQTP_ALIGNMENT_BYTES
#define JKQTP_ALIGNMENT_BYTES 32
#endif
/*! \brief malloc() for use herein (aligned on some systems!)
\ingroup jkqtptools_math_array
*/
inline void* jkqtpArrayMalloc(size_t size) {
// std::cout<<"statisticsMalloc("<<size<<")\n";
#ifdef STATISTICS_TOOLS_USE_QFTOOLS_H
return qfMalloc(size);
#else
if (size<=0) return nullptr;
#ifdef __LINUX__
#if !defined(QF_DONT_USE_ALIGNED_MALLOC)
return aligned_alloc(JKQTP_ALIGNMENT_BYTES, size);
#else
return malloc(size);
#endif
#else
#if !defined(QF_DONT_USE_ALIGNED_MALLOC)
return _aligned_malloc(size, JKQTP_ALIGNMENT_BYTES);
#else
return malloc(size);
#endif
#endif
#endif
}
/*! \brief calloc() for use herein (aligned on some systems!)
\ingroup jkqtptools_math_array
*/
inline void* jkqtpArrayCalloc(size_t num, size_t size) {
// std::cout<<"statisticsCalloc("<<num<<", "<<size<<")\n";
#ifdef STATISTICS_TOOLS_USE_QFTOOLS_H
return qfCalloc(num,size);
#else
if (size*size<=0) return nullptr;
void* res=jkqtpArrayMalloc(num*size);
memset(res, 0, num*size);
return res;
#endif
}
/*! \brief free() for use herein (aligned on some systems!)
\ingroup jkqtptools_math_array
*/
inline void jkqtpArrayFree(void* data) {
#ifdef STATISTICS_TOOLS_USE_QFTOOLS_H
qfFree(data);
#else
if (!data) return;
#ifdef __LINUX__
#if !defined(QF_DONT_USE_ALIGNED_MALLOC)
free(data);
#else
free(data);
#endif
#else
#if !defined(QF_DONT_USE_ALIGNED_MALLOC)
_aligned_free(data);
#else
free(data);
#endif
#endif
#endif
}
/*! \brief swap two elements \a l and \a r in an array \a a
\ingroup jkqtptools_math_array
*/
template <class T>
inline void jkqtpArraySwap(T* a, long long l, long long r){
const T tmp=a[l];
a[l]=a[r];
a[r]=tmp;
}
/*! \brief swap two elements \a l and \a r in an array \a a
\ingroup jkqtptools_math_array
*/
template <class T>
inline void jkqtpArraySwapV(std::vector<T>& a, long long l, long long r){
const T tmp=a[l];
a[l]=a[r];
a[r]=tmp;
}
/*! \brief duplicate an array of data
\ingroup jkqtptools_math_array
\note use jkqtpArrayFree() to free the memory!!!
*/
template <class T>
inline T* jkqtpArrayDuplicate(const T* dataIn, long long N) {
// std::cout<<"statisticsDuplicateArray("<<dataIn<<", "<<N<<")\n";
if (N<=0 || !dataIn) return nullptr;
T* out=static_cast<T*>(jkqtpArrayMalloc(N*sizeof(T)));
if (out) memcpy(out, dataIn, N*sizeof(T));
return out;
}
/*! \brief this class ensures that the given pointer is jkqtpArrayFreed when the class is destroyed.
\ingroup jkqtptools_math_array
*/
template<typename T>
class JKQTPArrayScopedPointer {
public:
inline explicit JKQTPArrayScopedPointer(T* pnt) {
pntr=pnt;
}
inline explicit JKQTPArrayScopedPointer() {
pntr=nullptr;
}
inline explicit JKQTPArrayScopedPointer(const JKQTPArrayScopedPointer& other) {
pntr=other.pntr;
}
~JKQTPArrayScopedPointer() {
if (pntr) jkqtpArrayFree(pntr);
}
inline JKQTPArrayScopedPointer<T>& operator=(T* p) {
pntr=p;
return *this;
}
inline JKQTPArrayScopedPointer<T>& operator=(const JKQTPArrayScopedPointer<T>& p) {
pntr=p.pntr;
return *this;
}
inline T& operator*() const { return *pntr; }
inline T* operator->() const { return pntr; }
inline T* data() const { return pntr; }
inline T& operator[](long long i) {
return pntr[i];
}
inline const T& operator[](long long i) const {
return pntr[i];
}
private:
T* pntr;
};
#endif // JKQTPARRAYTOOLS_H_INCLUDED

View File

@ -17,16 +17,11 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "jkqtplottertools/jkqtpimagetools.h"
#include "jkqtcommon/jkqtpbasicimagetools.h"
#include <QPainter>
#include <QApplication>
#include <QDir>
#include <QFileInfo>
#ifndef NO_JKQTPLOTTER
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplotter/jkqtpbaseplotter.h"
#include "jkqtplottertools/jkqtpdrawingtools.h"
#endif
#ifdef QT_XML_LIB
# include <QtXml/QtXml>
#endif
@ -1821,323 +1816,6 @@ QImage JKQTPMathImageGetAlphaPaletteImage(int *lut, int lut_size, int width, int
#ifndef NO_JKQTPLOTTER
JKQTPColorPaletteTools::JKQTPColorPaletteTools(JKQTBasePlotter *parent)
{
cbParent=parent;
colorBarRightAxis=new JKQTPVerticalIndependentAxis(0, 100, 0, 100, parent);
colorBarRightAxis->setDrawMode1(JKQTPCADMLine);
colorBarRightAxis->setDrawMode2(JKQTPCADMcomplete);
colorBarRightAxis->setAxisLabel("");
colorBarRightAxis->setMinTicks(3);
colorBarRightAxis->setShowZeroAxis(false);
colorBarRightAxis->setMinorTicks(0);
colorBarRightAxis->setTickOutsideLength(0);
colorBarRightAxis->setMinorTickOutsideLength(0);
colorBarTopAxis=new JKQTPHorizontalIndependentAxis(0, 100, 0, 100, parent);
colorBarTopAxis->setDrawMode1(JKQTPCADMLine);
colorBarTopAxis->setDrawMode2(JKQTPCADMcomplete);
colorBarTopAxis->setAxisLabel("");
colorBarTopAxis->setMinTicks(3);
colorBarTopAxis->setShowZeroAxis(false);
colorBarTopAxis->setMinorTicks(0);
colorBarTopAxis->setTickOutsideLength(0);
colorBarTopAxis->setMinorTickOutsideLength(0);
this->palette=JKQTPMathImageMATLAB;
this->imageNameFontName=parent->getDefaultTextFontName();
this->imageNameFontSize=parent->getDefaultTextSize();
this->imageName="";
this->showColorBar=true;
this->colorBarWidth=14;
this->colorBarRelativeHeight=0.75;
this->autoImageRange=true;
this->imageMin=0;
this->imageMax=1;
this->colorBarOffset=4;
this->rangeMinFailAction=JKQTPMathImageLastPaletteColor;
this->rangeMaxFailAction=JKQTPMathImageLastPaletteColor;
this->rangeMinFailColor=QColor("black");
this->rangeMaxFailColor=QColor("black");
this->nanColor=QColor("black");
this->infColor=QColor("black");
this->colorBarTopVisible=false;
this->colorBarRightVisible=true;
if (parent) this->palette=parent->getCurrentPlotterStyle().defaultPalette;
}
JKQTPColorPaletteTools::~JKQTPColorPaletteTools()
= default;
void JKQTPColorPaletteTools::cbGetOutsideSize(JKQTPEnhancedPainter& painter, int& leftSpace, int& rightSpace, int& topSpace, int& bottomSpace) {
Q_UNUSED(leftSpace);
Q_UNUSED(bottomSpace);
if (showColorBar) {
double internalDataMin=getInternalDataMin();
double internalDataMax=getInternalDataMax();
cbGetDataMinMax(internalDataMin, internalDataMax);
if (colorBarRightVisible) {
rightSpace+=cbParent->pt2px(painter, colorBarWidth+colorBarOffset);
colorBarRightAxis->setRange(internalDataMin, internalDataMax);
colorBarRightAxis->setAxisWidth(colorBarRelativeHeight*cbParent->getPlotHeight());
QSizeF s1=colorBarRightAxis->getSize2(painter);
QSizeF s2=colorBarRightAxis->getSize1(painter);
QSizeF names=cbParent->getTextSizeSize(imageNameFontName, imageNameFontSize*cbParent->getFontSizeMultiplier(), imageName, painter);
rightSpace+=qMax(static_cast<double>(s1.width()+s2.width()), static_cast<double>(names.width()));
}
if (colorBarTopVisible) {
//topSpace+=cbParent->pt2px(painter, colorBarWidth+colorBarOffset);
colorBarTopAxis->setRange(internalDataMin, internalDataMax);
colorBarTopAxis->setAxisWidth(colorBarRelativeHeight*cbParent->getPlotWidth());
QSizeF s1=colorBarTopAxis->getSize2(painter);
QSizeF s2=colorBarTopAxis->getSize1(painter);
QSizeF names=cbParent->getTextSizeSize(imageNameFontName, imageNameFontSize*cbParent->getFontSizeMultiplier(), imageName, painter);
topSpace+=cbParent->pt2px(painter, colorBarWidth+colorBarOffset)+qMax(static_cast<double>(s1.height()+s2.height()), static_cast<double>(names.height()));
}
}
}
void JKQTPColorPaletteTools::cbDrawOutside(JKQTPEnhancedPainter& painter, QRect leftSpace, QRect rightSpace, QRect topSpace, QRect bottomSpace) {
Q_UNUSED(leftSpace);
Q_UNUSED(bottomSpace);
if (showColorBar) {
double internalDataMin=getInternalDataMin();
double internalDataMax=getInternalDataMax();
cbGetDataMinMax(internalDataMin, internalDataMax);
if (colorBarRightVisible) {
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
static const uint8_t h=1;
static const uint8_t dSize = 200*h;
uint8_t d[dSize];//, dd[200*h];
for (int i=0; i<200; i++) {
for (int j=0; j<h; j++) {
d[i*h+j]=i;
//dd[i*h+j]=j;
}
}
QImage b(h, 200, QImage::Format_ARGB32);
JKQTPImagePlot_array2image<uint8_t>(d, h, 200, b, palette, 0, 199);
QSizeF names=cbParent->getTextSizeSize(imageNameFontName, imageNameFontSize*cbParent->getFontSizeMultiplier(), imageName, painter);
double icolorBarRelativeHeight=colorBarRelativeHeight;
int barHeight=rightSpace.height()*icolorBarRelativeHeight;
if (barHeight<1) barHeight=1;
// find a height for the bar that allows to show the image name
while ((barHeight>1) && ((rightSpace.height()-barHeight)/2<names.height())) {
barHeight--;
}
//qDebug()<<"r: "<<imageName<<rightSpace;
QRect cb(rightSpace.x()+cbParent->pt2px(painter, colorBarOffset), rightSpace.top()+(rightSpace.height()-barHeight)/2, cbParent->pt2px(painter, colorBarWidth), barHeight);
painter.drawImage(cb, b.mirrored(true, false));
QPen p=painter.pen();
p.setColor(colorBarRightAxis->getAxisColor());
p.setWidthF(qMax(JKQTPlotterDrawingTools::ABS_MIN_LINEWIDTH, cbParent->pt2px(painter, colorBarRightAxis->getLineWidth()*cbParent->getLineWidthMultiplier())));
painter.setPen(p);
painter.drawRect(cb);
colorBarRightAxis->setRange(internalDataMin, internalDataMax);
colorBarRightAxis->setAxisWidth(cb.height());
colorBarRightAxis->setAxisOffset(cb.top());
colorBarRightAxis->setOtherAxisOffset(cb.left());
colorBarRightAxis->setOtherAxisWidth(cb.width());
colorBarRightAxis->drawAxes(painter);
cbParent->getMathText()->setFontSize(imageNameFontSize*cbParent->getFontSizeMultiplier());
cbParent->getMathText()->setFontRomanOrSpecial(imageNameFontName);
cbParent->getMathText()->parse(imageName);
cbParent->getMathText()->draw(painter, Qt::AlignHCenter|Qt::AlignVCenter, QRect(rightSpace.x(), rightSpace.y(), rightSpace.width(), (rightSpace.height()-barHeight)/2));
}
if (colorBarTopVisible) {
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
static const uint8_t h=1;
static const uint8_t dSize = 200*h;
uint8_t d[dSize];//, dd[200*h];
for (int i=0; i<200; i++) {
for (int j=0; j<h; j++) {
d[i*h+j]=i;
//dd[i*h+j]=j;
}
}
QImage b(h,200, QImage::Format_ARGB32);
JKQTPImagePlot_array2image<uint8_t>(d,h,200, b, palette, 0, 199);
QSizeF names=cbParent->getTextSizeSize(imageNameFontName, imageNameFontSize*cbParent->getFontSizeMultiplier(), imageName, painter);
double icolorBarRelativeHeight=colorBarRelativeHeight;
int barWidth=topSpace.width()*icolorBarRelativeHeight;
if (barWidth<1) barWidth=1;
// find a height for the bar that allows to show the image name
while ((barWidth>1) && ((topSpace.width()-barWidth)/2<names.width())) {
barWidth--;
}
QRect cb(topSpace.x()+(topSpace.width()-barWidth)/2, topSpace.bottom()-cbParent->pt2px(painter, colorBarOffset+(colorBarWidth)), barWidth, cbParent->pt2px(painter, colorBarWidth));
//qDebug()<<"t: "<<imageName<<topSpace<<topSpace.bottom()<<colorBarOffset<<"\n "<<cb;
QMatrix rm;
rm.rotate(90);
painter.drawImage(cb, b.transformed(rm));
QPen p=painter.pen();
p.setColor(colorBarTopAxis->getAxisColor());
p.setWidthF(qMax(JKQTPlotterDrawingTools::ABS_MIN_LINEWIDTH, cbParent->pt2px(painter, colorBarTopAxis->getLineWidth()*cbParent->getLineWidthMultiplier())));
painter.setPen(p);
painter.drawRect(cb);
colorBarTopAxis->setRange(internalDataMin, internalDataMax);
colorBarTopAxis->setAxisWidth(cb.width());
colorBarTopAxis->setAxisOffset(cb.left());
colorBarTopAxis->setOtherAxisOffset(cb.top());
colorBarTopAxis->setOtherAxisWidth(cb.height());
colorBarTopAxis->drawAxes(painter);
cbParent->getMathText()->setFontSize(imageNameFontSize*cbParent->getFontSizeMultiplier());
cbParent->getMathText()->setFontRomanOrSpecial(imageNameFontName);
cbParent->getMathText()->parse(imageName);
cbParent->getMathText()->draw(painter, Qt::AlignHCenter|Qt::AlignVCenter, QRect(topSpace.right()-(topSpace.width()-barWidth)/2, topSpace.y(), (topSpace.width()-barWidth)/2, topSpace.height()));
}
}
}
QStringList JKQTPColorPaletteTools::getPalettes() {
return JKQTPImagePlot_getPredefinedPalettes();
}
int JKQTPColorPaletteTools::getPalettesCount()
{
return getPalettes().size();
}
QIcon JKQTPColorPaletteTools::getPaletteIcon(int i) {
QImage img=getPaletteImage(i, JKQTPImageTools::PALETTE_ICON_WIDTH);
QPixmap pix(JKQTPImageTools::PALETTE_ICON_WIDTH,8);
QRect r(0,0,JKQTPImageTools::PALETTE_ICON_WIDTH-1,7);
QPainter p(&pix);
p.drawImage(r, img);
p.setPen(QPen(QColor("black")));
p.drawRect(r);
p.end();
return QIcon(pix);
}
QIcon JKQTPColorPaletteTools::getPaletteIcon(JKQTPMathImageColorPalette palette) {
return getPaletteIcon(static_cast<int>(palette));
}
QImage JKQTPColorPaletteTools::getPaletteImage(int i, int width)
{
QImage img;
double* pic=static_cast<double*>(malloc(width*sizeof(double)));
for (int j=0; j<width; j++) {
pic[j]=j;
}
JKQTPImagePlot_array2image<double>(pic, width, 1, img, (JKQTPMathImageColorPalette)i, 0, width-1);
free(pic);
return img;
}
QImage JKQTPColorPaletteTools::getPaletteImage(JKQTPMathImageColorPalette palette, int width)
{
return getPaletteImage(static_cast<int>(palette), width);
}
QIcon JKQTPColorPaletteTools::getPaletteKeyIcon(int i)
{
QImage img=getPaletteKeyImage(i, JKQTPImageTools::PALETTE_ICON_WIDTH, JKQTPImageTools::PALETTE_IMAGEICON_HEIGHT);
QPixmap pix(JKQTPImageTools::PALETTE_ICON_WIDTH,JKQTPImageTools::PALETTE_IMAGEICON_HEIGHT);
QRect r(0,0,JKQTPImageTools::PALETTE_ICON_WIDTH-1,JKQTPImageTools::PALETTE_IMAGEICON_HEIGHT-1);
QPainter p(&pix);
p.drawImage(r, img);
p.setPen(QPen(QColor("black")));
p.drawRect(r);
p.end();
return QIcon(pix);
}
QIcon JKQTPColorPaletteTools::getPaletteKeyIcon(JKQTPMathImageColorPalette palette)
{
return getPaletteIcon(static_cast<int>(palette));
}
QImage JKQTPColorPaletteTools::getPaletteKeyImage(int i, int width, int height)
{
QImage img;
const double x01=double(width)/3.0;
const double y01=double(height)/3.0*2.0;
const double w1x=double(width*width)/(5.0*5.0);
const double w1y=double(height*height)/(2.0*2.0);
const double x02=double(width)/3.0*2.0;
const double y02=double(height)/4.0;
const double w2x=double(width*width)/(8.0*8.0);
const double w2y=double(height*height)/(8.0*8.0);
double* pic=static_cast<double*>(malloc(width*height*sizeof(double)));
double mmax=0;
for (int j=0; j<width*height; j++) {
const int x=j%width;
const int y=j/width;
pic[j]=exp(-0.5*(double((x-x01)*double(x-x01))/w1x+double((y-y01)*double(y-y01))/w1y))+0.7*exp(-0.5*(double((x-x02)*double(x-x02))/w2x+double((y-y02)*double(y-y02))/w2y));
if (pic[j]>mmax) mmax=pic[j];
}
JKQTPImagePlot_array2image<double>(pic, width, height, img, (JKQTPMathImageColorPalette)i, 0, mmax);
free(pic);
return img;
}
QImage JKQTPColorPaletteTools::getPaletteKeyImage(JKQTPMathImageColorPalette palette, int width, int height)
{
return getPaletteKeyImage(static_cast<int>(palette), width, height);
}
void JKQTPColorPaletteTools::setPalette(int pal) {
palette=(JKQTPMathImageColorPalette)pal;
}
void JKQTPColorPaletteTools::cbSetParent(JKQTBasePlotter* parent) {
cbParent=parent;
colorBarRightAxis->setParent(parent);
colorBarTopAxis->setParent(parent);
}
double JKQTPColorPaletteTools::getInternalDataMin() const
{
return 0;
}
double JKQTPColorPaletteTools::getInternalDataMax() const
{
return 0;
}
#endif
QString JKQTPMathImageColorPalette2String(JKQTPMathImageColorPalette p)
{

View File

@ -18,8 +18,8 @@
*/
#ifndef JKQTPIMAGETOOLS_H
#define JKQTPIMAGETOOLS_H
#ifndef JKQTPBASICIMAGETOOLS_H
#define JKQTPBASICIMAGETOOLS_H
#include <QIcon>
#include <QDebug>
#include <QImage>
@ -29,15 +29,6 @@
#include <cfloat>
#include <stdint.h>
#include <QColor>
#include "jkqtcommon/jkqtptools.h"
#ifndef NO_JKQTPLOTTER
#include "jkqtcommon/jkqtptools.h"
class JKQTPVerticalIndependentAxis; // forward
class JKQTPHorizontalIndependentAxis; // forward
class JKQTBasePlotter; // forward
#endif
/*! \brief tool structure that summarizes several static properties
\ingroup jkqtptools_qt
@ -807,333 +798,4 @@ QIcon JKQTP_LIB_EXPORT JKQTPMathImageGetPaletteIcon(JKQTPMathImageColorPalette p
#ifndef NO_JKQTPLOTTER
/*! \brief if a class is derived from this class, it may use color bars
\ingroup jkqtplotter_imagelots_tools
*/
class JKQTP_LIB_EXPORT JKQTPColorPaletteTools {
public:
JKQTPColorPaletteTools(JKQTBasePlotter *parent);
virtual ~JKQTPColorPaletteTools();
/*! \brief get list with all available palettes */
static QStringList getPalettes() ;
/*! \brief get list with all available palettes */
static int getPalettesCount() ;
/*! \brief get QIcon representing the given palette */
static QIcon getPaletteIcon(int i) ;
/*! \brief get QIcon representing the given palette */
static QIcon getPaletteIcon(JKQTPMathImageColorPalette palette) ;
/*! \brief get QIcon representing the given palette */
static QImage getPaletteImage(int i, int width) ;
/*! \brief get QIcon representing the given palette */
static QImage getPaletteImage(JKQTPMathImageColorPalette palette, int width) ;
/*! \brief get QIcon representing the given palette */
static QIcon getPaletteKeyIcon(int i) ;
/*! \brief get QIcon representing the given palette */
static QIcon getPaletteKeyIcon(JKQTPMathImageColorPalette palette) ;
/*! \brief get QIcon representing the given palette */
static QImage getPaletteKeyImage(int i, int width, int height) ;
/*! \brief get QIcon representing the given palette */
static QImage getPaletteKeyImage(JKQTPMathImageColorPalette palette, int width, int height) ;
void setPalette(int pal);
/*! \brief if the graph plots outside the actual plot field of view (e.g. color bars, scale bars, ...)
\note If you want to draw outside, then you'll also have to implement drawOutside()
*/
void cbGetOutsideSize(JKQTPEnhancedPainter& painter, int& leftSpace, int& rightSpace, int& topSpace, int& bottomSpace);
/*! \brief plots outside the actual plot field of view (e.g. color bars, scale bars, ...)
\note If you want to draw outside, then you'll also have to implement getOutsideSize(), so enough space is reserved
The four value supplied tell the method where to draw (inside one of the rectangles).
*/
void cbDrawOutside(JKQTPEnhancedPainter& painter, QRect leftSpace, QRect rightSpace, QRect topSpace, QRect bottomSpace);
void cbSetParent(JKQTBasePlotter* parent);
/** \brief determine min/max data value of the image */
virtual void cbGetDataMinMax(double& imin, double& imax)=0;
virtual double getInternalDataMin() const ;
virtual double getInternalDataMax() const ;
protected:
JKQTBasePlotter* cbParent;
/** \brief top color bar visible */
bool colorBarTopVisible;
/** \brief right color bar visible */
bool colorBarRightVisible;
/** \brief name of the image displayed above color bar (may contain LaTeX markup!) */
QString imageName;
/** \brief font name when displaying imageName */
QString imageNameFontName;
/** \brief font size in points when displaying imageName */
double imageNameFontSize;
/** \brief palette for plotting an image */
JKQTPMathImageColorPalette palette;
/** \brief indicate whether to display a color bar */
bool showColorBar;
/** \brief width of the color bar */
int colorBarWidth;
/** \brief height of the color bar, as multiple of plotHeight */
double colorBarRelativeHeight;
/** \brief indicates whether to estimate min/max of the image automatically */
bool autoImageRange;
/** \brief image value range minimum */
double imageMin;
/** \brief image value range maximum */
double imageMax;
/** \brief offset between outside space border and color bar */
int colorBarOffset;
/** \brief which action to take if a color is below \a imageMin and \a autoImageRange \c ==false */
JKQTPMathImageColorRangeFailAction rangeMinFailAction;
/** \brief which action to take if a color is above \a imageMax and \a autoImageRange \c ==false */
JKQTPMathImageColorRangeFailAction rangeMaxFailAction;
/** \brief color to use for some settings of \a rangeMinFailAction */
QColor rangeMinFailColor;
/** \brief color to use for some settings of \a rangeMaxFailAction */
QColor rangeMaxFailColor;
/** \brief color to use for a not-a-number value */
QColor nanColor;
/** \brief color to use for an infinity value */
QColor infColor;
/** \brief object used for color bar axes
*
* \note this axis has some kind of a special role. It is used to format color bar axes
*/
JKQTPVerticalIndependentAxis* colorBarRightAxis;
JKQTPHorizontalIndependentAxis* colorBarTopAxis;
public:
/*! \copydoc palette */
inline virtual void setPalette(const JKQTPMathImageColorPalette & __value)
{
this->palette = __value;
}
/*! \copydoc palette */
inline virtual JKQTPMathImageColorPalette getPalette() const
{
return this->palette;
}
/*! \copydoc rangeMinFailAction */
inline virtual void setRangeMinFailAction(const JKQTPMathImageColorRangeFailAction & __value)
{
this->rangeMinFailAction = __value;
}
/*! \copydoc rangeMinFailAction */
inline virtual JKQTPMathImageColorRangeFailAction getActionRangeMinFail() const
{
return this->rangeMinFailAction;
}
/*! \copydoc rangeMaxFailAction */
inline virtual void setRangeMaxFailAction(const JKQTPMathImageColorRangeFailAction & __value)
{
this->rangeMaxFailAction = __value;
}
/*! \copydoc rangeMaxFailAction */
inline virtual JKQTPMathImageColorRangeFailAction getActionRangeMaxFail() const
{
return this->rangeMaxFailAction;
}
/*! \copydoc rangeMinFailColor */
inline virtual void setRangeMinFailColor(const QColor & __value)
{
this->rangeMinFailColor = __value;
}
/*! \copydoc rangeMinFailColor */
inline virtual QColor getRangeMinFailColor() const
{
return this->rangeMinFailColor;
}
/*! \copydoc rangeMaxFailColor */
inline virtual void setRangeMaxFailColor(const QColor & __value)
{
this->rangeMaxFailColor = __value;
}
/*! \copydoc rangeMaxFailColor */
inline virtual QColor getRangeMaxFailColor() const
{
return this->rangeMaxFailColor;
}
/*! \copydoc nanColor */
inline virtual void setNanColor(const QColor & __value)
{
this->nanColor = __value;
}
/*! \copydoc nanColor */
inline virtual QColor getNanColor() const
{
return this->nanColor;
}
/*! \copydoc infColor */
inline virtual void setInfColor(const QColor & __value)
{
this->infColor = __value;
}
/*! \copydoc infColor */
inline virtual QColor getInfColor() const
{
return this->infColor;
}
/*! \copydoc showColorBar */
inline virtual void setShowColorBar(bool __value)
{
this->showColorBar = __value;
}
/*! \copydoc showColorBar */
inline virtual bool getShowColorBar() const
{
return this->showColorBar;
}
/*! \copydoc colorBarWidth */
inline virtual void setColorBarWidth(int __value)
{
this->colorBarWidth = __value;
}
/*! \copydoc colorBarWidth */
inline virtual int getColorBarWidth() const
{
return this->colorBarWidth;
}
/*! \copydoc colorBarOffset */
inline virtual void setColorBarOffset(int __value)
{
this->colorBarOffset = __value;
}
/*! \copydoc colorBarOffset */
inline virtual int getColorBarOffset() const
{
return this->colorBarOffset;
}
/*! \copydoc colorBarRelativeHeight */
inline virtual void setColorBarRelativeHeight(double __value)
{
this->colorBarRelativeHeight = __value;
}
/*! \copydoc colorBarRelativeHeight */
inline virtual double getColorBarRelativeHeight() const
{
return this->colorBarRelativeHeight;
}
/*! \copydoc imageMin */
inline virtual void setImageMin(double __value)
{
this->imageMin = __value;
}
/*! \copydoc imageMin */
inline virtual double getImageMin() const
{
return this->imageMin;
}
/*! \copydoc imageMax */
inline virtual void setImageMax(double __value)
{
this->imageMax = __value;
}
/*! \copydoc imageMax */
inline virtual double getImageMax() const
{
return this->imageMax;
}
/*! \copydoc autoImageRange */
inline virtual void setAutoImageRange(bool __value)
{
this->autoImageRange = __value;
}
/*! \copydoc autoImageRange */
inline virtual bool getAutoImageRange() const
{
return this->autoImageRange;
}
/*! \copydoc imageName */
inline virtual void setImageName(const QString & __value)
{
this->imageName = __value;
}
/*! \copydoc imageName */
inline virtual QString getImageName() const
{
return this->imageName;
}
/*! \copydoc imageNameFontName */
inline virtual void setImageNameFontName(const QString & __value)
{
this->imageNameFontName = __value;
}
/*! \copydoc imageNameFontName */
inline virtual QString getImageNameFontName() const
{
return this->imageNameFontName;
}
/*! \copydoc imageNameFontSize */
inline virtual void setImageNameFontSize(double __value)
{
this->imageNameFontSize = __value;
}
/*! \copydoc imageNameFontSize */
inline virtual double getImageNameFontSize() const
{
return this->imageNameFontSize;
}
/*! \copydoc colorBarRightAxis */
inline JKQTPVerticalIndependentAxis* getColorBarRightAxis() {
return this->colorBarRightAxis;
}
/*! \copydoc colorBarTopAxis */
inline JKQTPHorizontalIndependentAxis* getColorBarTopAxis() {
return this->colorBarTopAxis;
}
/*! \copydoc colorBarRightAxis */
inline const JKQTPVerticalIndependentAxis* getColorBarRightAxis() const {
return this->colorBarRightAxis;
}
/*! \copydoc colorBarTopAxis */
inline const JKQTPHorizontalIndependentAxis* getColorBarTopAxis() const {
return this->colorBarTopAxis;
}
/*! \copydoc colorBarTopVisible */
inline virtual void setColorBarTopVisible(bool __value)
{
this->colorBarTopVisible = __value;
}
/*! \copydoc colorBarTopVisible */
inline virtual bool getColorBarTopVisible() const
{
return this->colorBarTopVisible;
}
/*! \copydoc colorBarRightVisible */
inline virtual void setColorBarRightVisible(bool __value)
{
this->colorBarRightVisible = __value;
}
/*! \copydoc colorBarRightVisible */
inline virtual bool getColorBarRightVisible() const
{
return this->colorBarRightVisible;
}
};
#endif
#endif // JKQTPIMAGETOOLS_H
#endif // JKQTPBASICIMAGETOOLS_H

View File

@ -0,0 +1,24 @@
/*
Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License (LGPL) as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License (LGPL) for more details.
You should have received a copy of the GNU Lesser General Public License (LGPL)
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "jkqtcommon/jkqtpcodestructuring.h"

View File

@ -0,0 +1,124 @@
/*
Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>, <j.krieger@dkfz.de>)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef JKQTPCODESTRUCTURING_H_INCLUDED
#define JKQTPCODESTRUCTURING_H_INCLUDED
#include <functional>
/** \brief C++11 finally construct (executes a callable-object when the edestructor is executed)
* \ingroup jkqtptools_codestructuring
*
* Typical usage:
* \code
* {
* // the instruction 'painter.restore()' will be executed at the end
* // of the block, when __finalpaint is destroyed (see (*) below)
* JKQTPFinalAct __finalpaint([&painter]() { painter.restore(); });
*
* // ...
* // do something ...
* // ...
*
* } // (*) 'painter.restore()' is executed before the end of this block!
* \endcode
*
* \see JKQTPFinally()
*/
template <class F>
class JKQTPFinalAct
{
public:
explicit JKQTPFinalAct(F f) noexcept
: f_(std::move(f)), invoke_(true) {}
JKQTPFinalAct(JKQTPFinalAct&& other) noexcept
: f_(std::move(other.f_)),
invoke_(other.invoke_)
{
other.invoke_ = false;
}
JKQTPFinalAct(const JKQTPFinalAct&) = delete;
JKQTPFinalAct& operator=(const JKQTPFinalAct&) = delete;
~JKQTPFinalAct() noexcept
{
if (invoke_) f_();
}
private:
F f_;
bool invoke_;
};
/** \brief C++11 finally construct (executes a callable-object at the end of a scope)
* \ingroup jkqtptools_codestructuring
*
* Typical usage:
* \code
* {
* // the instruction 'painter.restore()' will be executed at the end
* // of the block, when __finalpaint is destroyed (see (*) below)
* auto __finalpaint=JKQTPFinally([&painter]() { painter.restore(); });
*
* // ...
* // do something ...
* // ...
*
* } // (*) 'painter.restore()' is executed before the end of this block!
* \endcode
*
* \see JKQTPFinalAct
*/
template <class F>
inline JKQTPFinalAct<F> JKQTPFinally(const F& f) noexcept
{
return JKQTPFinalAct<F>(f);
}
/** \brief C++11 finally construct (executes a callable-object at the end of a scope)
* \ingroup jkqtptools_codestructuring
*
* Typical usage:
* \code
* {
* // the instruction 'painter.restore()' will be executed at the end
* // of the block, when __finalpaint is destroyed (see (*) below)
* auto __finalpaint=JKQTPFinally([&painter]() { painter.restore(); });
*
* // ...
* // do something ...
* // ...
*
* } // (*) 'painter.restore()' is executed before the end of this block!
* \endcode
*
* \see JKQTPFinalAct
*/
template <class F>
inline JKQTPFinalAct<F> JKQTPFinally(F&& f) noexcept
{
return JKQTPFinalAct<F>(std::forward<F>(f));
}
#endif // JKQTPCODESTRUCTURING_H_INCLUDED

View File

@ -1,159 +0,0 @@
/*
Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>, <j.krieger@dkfz.de>)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef JKQTPCOMMONMATHTOOLS_H_INCLUDED
#define JKQTPCOMMONMATHTOOLS_H_INCLUDED
#include "jkqtcommon/jkqtp_imexport.h"
#include <cmath>
#include <QPoint>
#include <QPointF>
#include <vector>
/*! \brief \f$ \sqrt{\pi}=2.50662827463 \f$
\ingroup jkqtptools_math_basic
*/
#define JKQTPSTATISTICS_SQRT_2PI 2.50662827463
/** \brief double-value NotANumber
* \ingroup jkqtptools_math_basic
*/
#define JKQTP_DOUBLE_NAN (std::numeric_limits<double>::signaling_NaN())
/** \brief float-value NotANumber
* \ingroup jkqtptools_math_basic
*/
#define JKQTP_FLOAT_NAN (std::numeric_limits<float>::signaling_NaN())
/** \brief double-value NotANumber
* \ingroup jkqtptools_math_basic
*/
#define JKQTP_NAN JKQTP_DOUBLE_NAN
/** \brief wandelt einen Datentyp in einen double um, wird von JKQTPDatastore zur Wandlung benutzt
* \ingroup jkqtptools_math_basic
*
* Diese Funktion nutzt per default static_cast<double>(), kann aber für spezielle Datentypen überschrieben werden, etwa für bool
*/
template<typename T>
inline constexpr double jkqtp_todouble(const T& d) {
return static_cast<double>(d);
}
/** \brief wandelt einen boolean in einen double um, wird von JKQTPDatastore zur Wandlung benutzt,
* Spezialisierung für bool (true -> 1.0, false -> 0.0)
* \ingroup jkqtptools_math_basic */
template<>
inline constexpr double jkqtp_todouble(const bool& d) {
return static_cast<double>((d)?1.0:0.0);
}
/** \brief round a double using round() and convert it to a specified type T (static_cast!)
* \ingroup jkqtptools_math_basic */
template<typename T>
inline T jkqtp_roundTo(const double& v) {
return static_cast<T>(round(v));
}
/** \brief compare two floats \a a and \a b for euqality, where any difference smaller than \a epsilon is seen as equality
* \ingroup jkqtptools_math_basic */
inline bool jkqtp_approximatelyEqual(float a, float b, float epsilon=2.0*std::numeric_limits<float>::epsilon())
{
return fabsf(a - b) <= epsilon;
}
/** \brief compare two doubles \a a and \a b for euqality, where any difference smaller than \a epsilon is seen as equality
* \ingroup jkqtptools_math_basic */
inline bool jkqtp_approximatelyEqual(double a, double b, double epsilon=2.0*std::numeric_limits<double>::epsilon())
{
return fabs(a - b) <= epsilon;
}
/** \brief returns the quare of the value \a v, i.e. \c v*v
* \ingroup jkqtptools_math_basic */
template<typename T>
inline T jkqtp_sqr(const T& v) {
return v*v;
}
/*! \brief 4-th power of a number
\ingroup jkqtptools_math_basic
*/
template <class T>
inline T jkqtp_pow4(T x) {
const T xx=x*x;
return xx*xx;
}
/*! \brief cube of a number
\ingroup jkqtptools_math_basic
*/
template <class T>
inline T jkqtp_cube(T x) {
return x*x*x;
}
/*! \brief calculates the sign of number \a x
\ingroup jkqtptools_math_basic
*/
template <class T>
inline T jkqtp_sign(T x) {
if (x<0) return -1;
//else if (x==0) return 0;
else return 1;
}
/** \brief calculate the distance between two QPointF points
* \ingroup jkqtptools_math_basic
*
*/
inline double jkqtp_distance(const QPointF& p1, const QPointF& p2){
return sqrt(jkqtp_sqr<double>(p1.x()-p2.x())+jkqtp_sqr<double>(p1.y()-p2.y()));
}
/** \brief calculate the distance between two QPoint points
* \ingroup jkqtptools_math_basic
*
*/
inline double jkqtp_distance(const QPoint& p1, const QPoint& p2){
return sqrt(jkqtp_sqr<double>(p1.x()-p2.x())+jkqtp_sqr<double>(p1.y()-p2.y()));
}
/** \brief check whether the dlotaing point number is OK (i.e. non-inf, non-NAN)
* \ingroup jkqtptools_math_basic
*/
template <typename T>
inline bool JKQTPIsOKFloat(T v) {
return std::isfinite(v)&&(!std::isinf(v))&&(!std::isnan(v));
}
#endif // JKQTPCOMMONMATHTOOLS_H_INCLUDED

View File

@ -0,0 +1,406 @@
/*
Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License (LGPL) as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License (LGPL) for more details.
You should have received a copy of the GNU Lesser General Public License (LGPL)
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "jkqtcommon/jkqtpdrawingtools.h"
#include "jkqtcommon/jkqtpenhancedpainter.h"
#include <QDebug>
const double JKQTPlotterDrawingTools::ABS_MIN_LINEWIDTH= 0.02;
QString JKQTPGraphSymbols2String(JKQTPGraphSymbols pos) {
switch(pos) {
case JKQTPDot: return "symbol_dot";
case JKQTPCross: return "symbol_cross";
case JKQTPPlus: return "symbol_plus";
case JKQTPCircle: return "symbol_circle";
case JKQTPFilledCircle: return "symbol_filled_circle";
case JKQTPRect: return "symbol_rect";
case JKQTPFilledRect: return "symbol_filled_rect";
case JKQTPTriangle: return "symbol_triangle";
case JKQTPFilledTriangle: return "symbol_filled_triangle";
case JKQTPDownTriangle: return "symbol_down_triangle";
case JKQTPFilledDownTriangle: return "symbol_filled_down_triangle";
case JKQTPTarget: return "symbol_target";
case JKQTPstar: return "symbol_star";
case JKQTPFilledStar: return "symbol_filled_star";
case JKQTPDiamond: return "symbol_diamond";
case JKQTPFilledDiamond: return "symbol_filled_diamond";
case JKQTPPentagon: return "symbol_pentagon";
case JKQTPAsterisc: return "symbol_asterisc";
case JKQTPAsterisc6: return "symbol_asterisc6";
case JKQTPAsterisc8: return "symbol_asterisc8";
case JKQTPFilledPentagon: return "symbol_filled_pentagon";
case JKQTPHexagon: return "symbol_hexagon";
case JKQTPFilledHexagon: return "symbol_filled_hexagon";
case JKQTPOctagon: return "symbol_octagon";
case JKQTPFilledOctagon: return "symbol_filled_octagon";
case JKQTPRectCross: return "symbol_rect_cross";
case JKQTPRectPlus: return "symbol_rect_plus";
case JKQTPNoSymbol: return "none";
case JKQTPDiamondPlus: return "symbol_diamond_plus";
case JKQTPDiamondCross: return "symbol_diamond_cross";
case JKQTPCircleCross: return "symbol_circle_cross";
case JKQTPCirclePlus: return "symbol_circle_plus";
case JKQTPUpDownTriangle: return "symbol_updowntriangle";
case JKQTPFilledUpDownTriangle: return "symbol_filled_updowntriangle";
case JKQTPSantaClauseHouse: return "symbol_santaclause";
case JKQTPFilledSantaClauseHouse: return "symbol_filled_santaclause";
case JKQTPHourglass: return "symbol_hourglass";
case JKQTPFilledHourglass: return "symbol_filled_hourglass";
case JKQTPHorizontalHourglass: return "symbol_horizontal_hourglass";
case JKQTPFilledHorizontalHourglass: return "symbol_filled_horizontal_hourglass";
case JKQTPRectTriangle: return "symbol_rect_triangle";
case JKQTPRectDownTriangle: return "symbol_rect_downtriangle";
case JKQTPRectLeftTriangle: return "symbol_rect_lefttriangle";
case JKQTPRectRightTriangle: return "symbol_rect_righttriangle";
case JKQTPLeftTriangle: return "symbol_left_triangle";
case JKQTPFilledLeftTriangle: return "symbol_filled_left_triangle";
case JKQTPRightTriangle: return "symbol_right_triangle";
case JKQTPFilledRightTriangle: return "symbol_filled_right_triangle";
case JKQTPTripod: return "symbol_tripod";
case JKQTPDownTripod: return "symbol_down_tripod";
case JKQTPLeftTripod: return "symbol_left_tripod";
case JKQTPRightTripod: return "symbol_right_tripod";
case JKQTPFilledCurvedTriangle: return "symbol_filled_curved_triangle";
case JKQTPFilledDownCurvedTriangle: return "symbol_filled_down_curved_triangle";
case JKQTPFilledLeftCurvedTriangle: return "symbol_filled_left_curved_triangle";
case JKQTPFilledRightCurvedTriangle: return "symbol_filled_right_curved_triangle";
case JKQTPCurvedTriangle: return "symbol_curved_triangle";
case JKQTPDownCurvedTriangle: return "symbol_down_curved_triangle";
case JKQTPLeftCurvedTriangle: return "symbol_left_curved_triangle";
case JKQTPRightCurvedTriangle: return "symbol_right_curved_triangle";
case JKQTPPeace: return "symbol_peace";
case JKQTPFemale: return "symbol_female";
case JKQTPMale: return "symbol_male";
case JKQTPCirclePeace: return "symbol_circle_peace";
case JKQTPSymbolCount: JKQTPGraphSymbols2String(JKQTPMaxSymbolID);
}
return "";
}
QString JKQTPGraphSymbols2NameString(JKQTPGraphSymbols pos) {
switch(pos) {
case JKQTPDot: return QObject::tr("dot");
case JKQTPCross: return QObject::tr("cross");
case JKQTPPlus: return QObject::tr("plus");
case JKQTPCircle: return QObject::tr("circle");
case JKQTPFilledCircle: return QObject::tr("filled circle");
case JKQTPRect: return QObject::tr("rectangle");
case JKQTPFilledRect: return QObject::tr("filled rectangle");
case JKQTPTriangle: return QObject::tr("triangle");
case JKQTPFilledTriangle: return QObject::tr("filled triangle");
case JKQTPDownTriangle: return QObject::tr("down triangle");
case JKQTPFilledDownTriangle: return QObject::tr("filled down triangle");
case JKQTPstar: return QObject::tr("star");
case JKQTPFilledStar: return QObject::tr("filled star");
case JKQTPDiamond: return QObject::tr("diamond");
case JKQTPFilledDiamond: return QObject::tr("filled diamond");
case JKQTPPentagon: return QObject::tr("pentagon");
case JKQTPFilledPentagon: return QObject::tr("filled pentagon");
case JKQTPHexagon: return QObject::tr("hexagon");
case JKQTPFilledHexagon: return QObject::tr("filled hexagon");
case JKQTPOctagon: return QObject::tr("octagon");
case JKQTPFilledOctagon: return QObject::tr("filled octagon");
case JKQTPTarget: return QObject::tr("target");
case JKQTPAsterisc: return QObject::tr("asterisc, 5-arm");
case JKQTPAsterisc6: return QObject::tr("asterisc, 6-arm");
case JKQTPAsterisc8: return QObject::tr("asterisc, 8-arm");
case JKQTPRectCross: return QObject::tr("square with cross");
case JKQTPRectPlus: return QObject::tr("square with plus");
case JKQTPNoSymbol: return QObject::tr("none");
case JKQTPDiamondPlus: return QObject::tr("diamond with plus");
case JKQTPDiamondCross: return QObject::tr("diamond with cross");
case JKQTPCircleCross: return QObject::tr("circled cross");
case JKQTPCirclePlus: return QObject::tr("circled plus");
case JKQTPUpDownTriangle: return QObject::tr("up/down triangle");
case JKQTPFilledUpDownTriangle: return QObject::tr("filled up/down triangle");
case JKQTPSantaClauseHouse: return QObject::tr("santa clause");
case JKQTPFilledSantaClauseHouse: return QObject::tr("filled santa clause");
case JKQTPHourglass: return QObject::tr("hourglass");
case JKQTPFilledHourglass: return QObject::tr("filled hourglass");
case JKQTPHorizontalHourglass: return QObject::tr("horizontal hourglass");
case JKQTPFilledHorizontalHourglass: return QObject::tr("filled horizontal hourglass");
case JKQTPRectTriangle: return QObject::tr("rectangle with triangle");
case JKQTPRectDownTriangle: return QObject::tr("rectangle with downwards triangle");
case JKQTPRectLeftTriangle: return QObject::tr("rectangle with leftwards triangle");
case JKQTPRectRightTriangle: return QObject::tr("rectangle with rightwards triangle");
case JKQTPLeftTriangle: return QObject::tr("left triangle");
case JKQTPFilledLeftTriangle: return QObject::tr("filled left triangle");
case JKQTPRightTriangle: return QObject::tr("right triangle");
case JKQTPFilledRightTriangle: return QObject::tr("filled right triangle");
case JKQTPTripod: return QObject::tr("tripod");
case JKQTPDownTripod: return QObject::tr("down tripod");
case JKQTPLeftTripod: return QObject::tr("left tripod");
case JKQTPRightTripod: return QObject::tr("right tripod");
case JKQTPFilledCurvedTriangle: return QObject::tr("filled curved triangle");
case JKQTPFilledDownCurvedTriangle: return QObject::tr("filled down curved triangle");
case JKQTPFilledLeftCurvedTriangle: return QObject::tr("filled left curved triangle");
case JKQTPFilledRightCurvedTriangle: return QObject::tr("filled right curved triangle");
case JKQTPCurvedTriangle: return QObject::tr("curved triangle");
case JKQTPDownCurvedTriangle: return QObject::tr("down curved triangle");
case JKQTPLeftCurvedTriangle: return QObject::tr("left curved triangle");
case JKQTPRightCurvedTriangle: return QObject::tr("right curved triangle");
case JKQTPPeace: return QObject::tr("peace");
case JKQTPFemale: return QObject::tr("female");
case JKQTPMale: return QObject::tr("male");
case JKQTPCirclePeace: return QObject::tr("circled peace");
case JKQTPSymbolCount: JKQTPGraphSymbols2NameString(JKQTPMaxSymbolID);
}
return "";
}
JKQTPGraphSymbols String2JKQTPGraphSymbols(const QString& pos) {
QString s=pos.trimmed().toLower();
if (s=="symbol_dot"||s=="dot"||s==".") return JKQTPDot;
if (s=="symbol_cross"||s=="cross"||s=="x") return JKQTPCross;
if (s=="symbol_plus"||s=="plus"||s=="+") return JKQTPPlus;
if (s=="symbol_circle"||s=="circle"||s=="o") return JKQTPCircle;
if (s=="symbol_filled_circle"||s=="filled_circle"||s=="fo") return JKQTPFilledCircle;
if (s=="symbol_rect"||s=="rect"||s=="r") return JKQTPRect;
if (s=="symbol_filled_rect"||s=="filled_rect"||s=="fr") return JKQTPFilledRect;
if (s=="symbol_triangle"||s=="triangle"||s=="^") return JKQTPTriangle;
if (s=="symbol_filled_triangle"||s=="filled_triangle"||s=="f^") return JKQTPFilledTriangle;
if (s=="symbol_down_triangle"||s=="down_triangle"||s=="v") return JKQTPDownTriangle;
if (s=="symbol_filles_down_triangle"||s=="filles_down_triangle"||s=="symbol_filled_down_triangle"||s=="filled_down_triangle"||s=="fv") return JKQTPFilledDownTriangle;
if (s=="symbol_target"||s=="target"||s=="t") return JKQTPTarget;
if (s=="symbol_star"||s=="star"||s=="s") return JKQTPstar;
if (s=="symbol_filled_star"||s=="filled_star"||s=="fs") return JKQTPFilledStar;
if (s=="symbol_diamond"||s=="diamond"||s=="d") return JKQTPDiamond;
if (s=="symbol_filled_diamond"||s=="filled_diamond"||s=="fd") return JKQTPFilledDiamond;
if (s=="symbol_pentagon"||s=="pentagon"||s=="p") return JKQTPPentagon;
if (s=="symbol_filled_pentagon"||s=="filled_pentagon"||s=="fp") return JKQTPFilledPentagon;
if (s=="symbol_hexagon"||s=="hexagon"||s=="h") return JKQTPHexagon;
if (s=="symbol_filled_hexagon"||s=="filled_hexagon"||s=="fh") return JKQTPFilledHexagon;
if (s=="symbol_octagon"||s=="octagon"||s=="h") return JKQTPOctagon;
if (s=="symbol_filled_octagon"||s=="filled_octagon"||s=="fh") return JKQTPFilledOctagon;
if (s=="symbol_asterisc"||s=="asterisc"||s=="*") return JKQTPAsterisc;
if (s=="symbol_asterisc6"||s=="asterisc6"||s=="*6") return JKQTPAsterisc6;
if (s=="symbol_asterisc8"||s=="asterisc8"||s=="*8") return JKQTPAsterisc8;
if (s=="symbol_rect_cross"||s=="rect_cross"||s=="rx") return JKQTPRectCross;
if (s=="symbol_rect_plus"||s=="rect_plus"||s=="r+") return JKQTPRectPlus;
if (s=="symbol_diamond_plus" || s=="diamond_plus") return JKQTPDiamondPlus;
if (s=="symbol_diamond_cross" || s=="diamond_cross") return JKQTPDiamondCross;
if (s=="symbol_circle_cross" || s=="circle_cross") return JKQTPCircleCross;
if (s=="symbol_circle_plus" || s=="circle_plus") return JKQTPCirclePlus;
if (s=="symbol_updowntriangle" || s=="updowntriangle") return JKQTPUpDownTriangle;
if (s=="symbol_filled_updowntriangle" || s=="filled_updowntriangle") return JKQTPFilledUpDownTriangle;
if (s=="symbol_santaclause" || s=="santaclause") return JKQTPSantaClauseHouse;
if (s=="symbol_filled_santaclause" || s=="filled_santaclause") return JKQTPFilledSantaClauseHouse;
if (s=="symbol_hourglass" || s=="hourglass") return JKQTPHourglass;
if (s=="symbol_filled_hourglass" || s=="filled_hourglass") return JKQTPFilledHourglass;
if (s=="symbol_horizontal_hourglass" || s=="horizontal_hourglass") return JKQTPHorizontalHourglass;
if (s=="symbol_filled_horizontal_hourglass" || s=="filled_horizontal_hourglass") return JKQTPFilledHorizontalHourglass;
if (s=="symbol_rect_triangle" || s=="rect_triangle") return JKQTPRectTriangle;
if (s=="symbol_rect_downtriangle" || s=="rect_downtriangle") return JKQTPRectDownTriangle;
if (s=="symbol_rect_lefttriangle" || s=="rect_lefttriangle") return JKQTPRectLeftTriangle;
if (s=="symbol_rect_righttriangle" || s=="rect_righttriangle") return JKQTPRectRightTriangle;
if (s=="symbol_left_triangle" || s=="left_triangle") return JKQTPLeftTriangle;
if (s=="symbol_filled_left_triangle" || s=="filled_left_triangle") return JKQTPFilledLeftTriangle;
if (s=="symbol_right_triangle" || s=="right_triangle") return JKQTPRightTriangle;
if (s=="symbol_filled_right_triangle" || s=="filled_right_triangle") return JKQTPFilledRightTriangle;
if (s=="symbol_tripod" || s=="tripod") return JKQTPTripod;
if (s=="symbol_down_tripod" || s=="down_tripod") return JKQTPDownTripod;
if (s=="symbol_left_tripod" || s=="left_tripod") return JKQTPLeftTripod;
if (s=="symbol_right_tripod" || s=="right_tripod") return JKQTPRightTripod;
if (s=="symbol_filled_curved_triangle" || s=="filled_curved_triangle") return JKQTPFilledCurvedTriangle;
if (s=="symbol_filled_down_curved_triangle" || s=="filled_down_curved_triangle") return JKQTPFilledDownCurvedTriangle;
if (s=="symbol_filled_left_curved_triangle" || s=="filled_left_curved_triangle") return JKQTPFilledLeftCurvedTriangle;
if (s=="symbol_filled_right_curved_triangle" || s=="filled_right_curved_triangle") return JKQTPFilledRightCurvedTriangle;
if (s=="symbol_curved_triangle" || s=="curved_triangle") return JKQTPCurvedTriangle;
if (s=="symbol_down_curved_triangle" || s=="down_curved_triangle") return JKQTPDownCurvedTriangle;
if (s=="symbol_left_curved_triangle" || s=="left_curved_triangle") return JKQTPLeftCurvedTriangle;
if (s=="symbol_right_curved_triangle" || s=="right_curved_triangle") return JKQTPRightCurvedTriangle;
if (s=="symbol_peace" || s=="peace") return JKQTPPeace;
if (s=="symbol_circle_peace" || s=="circle_peace") return JKQTPCirclePeace;
if (s=="symbol_female" || s=="female") return JKQTPFemale;
if (s=="symbol_male" || s=="male") return JKQTPMale;
return JKQTPNoSymbol;
}
QPolygonF jkqtpRotateRect(QRectF r, double angle) {
QPolygonF p;
QMatrix m;
m.rotate(angle);
p.append(m.map(r.bottomLeft()));
p.append(m.map(r.bottomRight()));
p.append(m.map(r.topRight()));
p.append(m.map(r.topLeft()));
return p;
}
;
QVector<QPointF> JKQTPDrawEllipse(double x, double y, double a, double b, double angle_start, double angle_end, double alpha, int controlPoints, QPointF* x_start, QPointF* x_end) {
QVector<QPointF> result;
double start=angle_start*M_PI/180.0;
double stop=angle_end*M_PI/180.0;
double step=(stop-start)/static_cast<double>(controlPoints);
while (fabs(stop-start)/step<10) step=step/2.0;
double sina=sin(1.0*alpha/180.0*M_PI);
double cosa=cos(1.0*alpha/180.0*M_PI);
QPointF xp(x+a*cos(start)*cosa-b*sin(start)*sina, y+a*cos(start)*sina+b*sin(start)*cosa);
result.append(xp);
if (x_start) *x_start = xp;
double t=start+step;
for (int i=1; i<controlPoints; i++) {
double cost=cos(t);
double sint=sin(t);
xp=QPointF( x+a*cost*cosa-b*sint*sina, y+a*cost*sina+b*sint*cosa);
result.append(xp);
//std::cout<<"t="<<t/M_PI*180.0<<": sin(al)="<<sina<<" cos(al)="<<cosa<<" sin(t)="<<sint<<" cos(t)="<<cost<<" a="<<a<<" b="<<b<<": ("<<x+a*cost*cosa-b*sint*sina<<", "<<y+a*cost*sina+b*sint*cosa<<") = ("<<xp.x()<<", "<<xp.y()<<") \n";
t=t+step;
}
if (x_end) *x_end=xp;
return result;
}
QVector<QPolygonF> JKQTPUnifyLinesToPolygons(const QVector<QLineF> &lines, double distanceThreshold, int searchMaxSurroundingElements)
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTPUnifyLinesToPolygons(%1, %2, %3)").arg(lines.size()).arg(distanceThreshold).arg(searchMaxSurroundingElements));
#endif
QList<QPolygonF> res;
res.reserve(lines.size());
// first simply convert all lines to polygons
for (const QLineF& l: lines) {
QPolygonF p;
p<<l.p1()<<l.p2();
res<<p;
}
//return res.toVector();
// clean the resulting polygon
for (QPolygonF& p: res) {
p=JKQTPCleanPolygon(p, distanceThreshold);
}
int maxIterations=100;
int iter=0;
bool found=true;
//qDebug()<<" iter "<<-1<<" -> polygons start "<<res.size();
while (found && iter<maxIterations) {
found=false;
int i=0;
while (i<res.size()-1) {
int j=i+1;
while (j<res.size() && j<i+searchMaxSurroundingElements) {
if (jkqtp_distance(res[i].first(),res[j].first())<=distanceThreshold) {
found=true;
for (int k=1; k<res[j].size(); k++) {
res[i].prepend(res[j].at(k));
}
res.removeAt(j);
} else if (jkqtp_distance(res[i].first(),res[j].last())<=distanceThreshold) {
found=true;
for (int k=res[j].size()-2; k>=0; k--) {
res[i].prepend(res[j].at(k));
}
res.removeAt(j);
} else if (jkqtp_distance(res[i].last(),res[j].first())<=distanceThreshold) {
found=true;
for (int k=1; k<res[j].size(); k++) {
res[i].append(res[j].at(k));
}
res.removeAt(j);
} else if (jkqtp_distance(res[i].last(),res[j].last())<=distanceThreshold) {
found=true;
for (int k=res[j].size()-2; k>=0; k--) {
res[i].append(res[j].at(k));
}
res.removeAt(j);
} else {
j++;
}
}
res[i]=JKQTPCleanPolygon(res[i], distanceThreshold);
i++;
}
//qDebug()<<" iter "<<iter<<" -> polygons left "<<res.size();
iter++;
}
return res.toVector();
}
QPolygonF JKQTPCleanPolygon(const QPolygonF &poly, double distanceThreshold)
{
if (poly.size()<=2) return poly;
QPolygonF p;
QPointF p0=poly[0];
p<<p0;
QVector<QPointF> inbetween;
int i=1;
while (i<poly.size()) {
if ((jkqtp_distance(poly[i], p0)<=distanceThreshold)) {
inbetween<<poly[i];
} else {
QPointF pmean(0,0);
if (inbetween.size()>0) {
for (const QPointF& pi: inbetween) {
pmean=QPointF(pmean.x()+pi.x()/static_cast<double>(inbetween.size()), pmean.y()+pi.y()/static_cast<double>(inbetween.size()));
}
} else {
pmean=poly[i];
}
p<<pmean;
p0=pmean;
inbetween.clear();
}
i++;
}
// maybe we have something left to add
QPointF pmean(0,0);
if (inbetween.size()>0) {
for (const QPointF& pi: inbetween) {
pmean=QPointF(pmean.x()+pi.x()/static_cast<double>(inbetween.size()), pmean.y()+pi.y()/static_cast<double>(inbetween.size()));
}
} else {
pmean=p0;
}
if (jkqtp_distance(pmean, poly.last())>distanceThreshold) {
p<<pmean<<poly.last();
} else {
if (p.last()!=poly.last()) p<<poly.last();
}
return p;
}
void JKQTPPlotSymbol(QPaintDevice &paintDevice, double x, double y, JKQTPGraphSymbols symbol, double size, double symbolLineWidth, QColor color, QColor fillColor) {
JKQTPEnhancedPainter p(&paintDevice);
JKQTPPlotSymbol(p, x, y, symbol, size, symbolLineWidth, color, fillColor);
}

View File

@ -0,0 +1,875 @@
/*
Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>, <j.krieger@dkfz.de>)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef JKQTPDRAWINGTOOLS_H_INCLUDED
#define JKQTPDRAWINGTOOLS_H_INCLUDED
#include "jkqtcommon/jkqtp_imexport.h"
#include <QPaintDevice>
#include <QPainter>
#include <QPolygonF>
#include <QPolygon>
#include <QRectF>
#include <QRect>
#include <QLineF>
#include <QLine>
#include <QPainterPath>
#include <QColor>
#include <QVector>
#include <vector>
#include <cmath>
#include "jkqtcommon/jkqtpmathtools.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
class JKQTPEnhancedPainter; // forward
/*! \brief tool class with static values used by JKQTPlotter/JKQTBasePlotter
\ingroup jkqtptools_drawing
*/
JKQTP_LIB_EXPORT struct JKQTPlotterDrawingTools {
/** \brief smallest linewidth any line in JKQTPlotter/JKQTBasePlotter may have
*/
static const double ABS_MIN_LINEWIDTH;
};
/** \brief symbols that can be used to plot a datapoint for a graph
* \ingroup jkqtptools_drawing
*/
enum JKQTPGraphSymbols {
JKQTPNoSymbol=0, /*!< \brief plots no symbol at all (usefull together with error bars) */
JKQTPDot, /*!< \brief a small dot \image html symbols/symbol_dot.png */
JKQTPCross, /*!< \brief a X cross \image html symbols/symbol_cross.png */
JKQTPPlus, /*!< \brief a + cross \image html symbols/symbol_plus.png */
JKQTPCircle, /*!< \brief an unfilled circle \image html symbols/symbol_circle.png */
JKQTPFilledCircle, /*!< \brief a filled circle \image html symbols/symbol_filled_circle.png */
JKQTPRect, /*!< \brief an unfilled rectangle \image html symbols/symbol_rect.png */
JKQTPFilledRect, /*!< \brief a filled rectangle \image html symbols/symbol_filled_rect.png */
JKQTPTriangle, /*!< \brief an unfilled triangle (tip at top) \image html symbols/symbol_triangle.png */
JKQTPFilledTriangle, /*!< \brief a filled triangle (tip at top) \image html symbols/symbol_filled_triangle.png */
JKQTPDiamond, /*!< \brief an unfilled diamond \image html symbols/symbol_diamond.png */
JKQTPFilledDiamond, /*!< \brief a filled diamond \image html symbols/symbol_filled_diamond.png */
JKQTPstar, /*!< \brief an unfilled diamond \image html symbols/symbol_star.png */
JKQTPFilledStar, /*!< \brief a filled diamond \image html symbols/symbol_filled_star.png */
JKQTPPentagon, /*!< \brief an unfilled pentagon \image html symbols/symbol_pentagon.png */
JKQTPFilledPentagon, /*!< \brief a filled pentagon \image html symbols/symbol_filled_pentagon.png */
JKQTPAsterisc, /*!< \brief an asterisc star with 5 arms \image html symbols/symbol_asterisc.png */
JKQTPHourglass, /*!< \brief an hour glass symbol \image html symbols/symbol_hourglass.png */
JKQTPFilledHourglass, /*!< \brief a filled hour glass symbol \image html symbols/symbol_filled_hourglass.png */
JKQTPCurvedTriangle, /*!< \brief a curved triangle\image html symbols/symbol_curved_triangle.png */
JKQTPFilledCurvedTriangle, /*!< \brief a filled curved triangle\image html symbols/symbol_filled_curved_triangle.png */
JKQTPHexagon, /*!< \brief an unfilled hexagon \image html symbols/symbol_hexagon.png */
JKQTPFilledHexagon, /*!< \brief a filled hexagon \image html symbols/symbol_filled_hexagon.png */
JKQTPRectCross, /*!< \brief a square symbol with a cross inside \image html symbols/symbol_rect_cross.png */
JKQTPRectPlus, /*!< \brief a square symbol with a plus inside \image html symbols/symbol_rect_plus.png */
JKQTPRectTriangle, /*!< \brief a square symbol with a triangle inside \image html symbols/symbol_rect_triangle.png */
JKQTPRectDownTriangle, /*!< \brief a square symbol with a triangle (tip to the bottom) inside \image html symbols/symbol_rect_downtriangle.png */
JKQTPRectLeftTriangle, /*!< \brief a square symbol with a triangle (tip to the left) inside \image html symbols/symbol_rect_lefttriangle.png */
JKQTPRectRightTriangle, /*!< \brief a square symbol with a triangle (tip to the right) inside \image html symbols/symbol_rect_righttriangle.png */
JKQTPCircleCross, /*!< \brief a circle symbol with a cross inside \image html symbols/symbol_circle_cross.png */
JKQTPCirclePlus, /*!< \brief a circle symbol with a plus inside \image html symbols/symbol_circle_plus.png */
JKQTPCirclePeace, /*!< \brief a circled peace symbol \image html symbols/symbol_circle_peace.png */
JKQTPDiamondPlus, /*!< \brief a diamond symbol with a plus inside \image html symbols/symbol_diamond_plus.png */
JKQTPDiamondCross, /*!< \brief a diamond symbol with a cross inside \image html symbols/symbol_diamond_cross.png */
JKQTPTripod, /*!< \brief a tripod symbol \image html symbols/symbol_tripod.png */
JKQTPDownTripod, /*!< \brief a tripod symbol, pointing down \image html symbols/symbol_down_tripod.png */
JKQTPLeftTripod, /*!< \brief a tripod symbol, pointing to the left \image html symbols/symbol_left_tripod.png */
JKQTPRightTripod, /*!< \brief a tripod symbol, pointing to the right \image html symbols/symbol_right_tripod.png */
JKQTPAsterisc6, /*!< \brief an asterisc star with 6 arms \image html symbols/symbol_asterisc6.png */
JKQTPAsterisc8, /*!< \brief an asterisc star with 8 arms \image html symbols/symbol_asterisc8.png */
JKQTPPeace, /*!< \brief a peace symbol \image html symbols/symbol_peace.png */
JKQTPTarget, /*!< \brief a target symbol (circle with cross) \image html symbols/symbol_target.png */
JKQTPDownTriangle, /*!< \brief an unfilled triangle (tip at bottom) \image html symbols/symbol_down_triangle.png */
JKQTPFilledDownTriangle, /*!< \brief a filled triangle (tip at bottom) \image html symbols/symbol_filled_down_triangle.png */
JKQTPLeftTriangle, /*!< \brief an unfilled triangle (tip to the left) \image html symbols/symbol_left_triangle.png */
JKQTPFilledLeftTriangle, /*!< \brief a filled triangle (tip to the left) \image html symbols/symbol_filled_left_triangle.png */
JKQTPRightTriangle, /*!< \brief an unfilled triangle (tip to the right) \image html symbols/symbol_right_triangle.png */
JKQTPFilledRightTriangle, /*!< \brief a filled triangle (tip to the right) \image html symbols/symbol_filled_right_triangle.png */
JKQTPDownCurvedTriangle, /*!< \brief a curved triangle, pointing down \image html symbols/symbol_down_curved_triangle.png */
JKQTPFilledDownCurvedTriangle, /*!< \brief a filled curved triangle, pointing down \image html symbols/symbol_filled_down_curved_triangle.png */
JKQTPLeftCurvedTriangle, /*!< \brief a curved triangle, pointing to the left \image html symbols/symbol_left_curved_triangle.png */
JKQTPFilledLeftCurvedTriangle, /*!< \brief a filled curved triangle, pointing to the left \image html symbols/symbol_filled_left_curved_triangle.png */
JKQTPRightCurvedTriangle, /*!< \brief a curved triangle, pointing to the right \image html symbols/symbol_right_curved_triangle.png */
JKQTPFilledRightCurvedTriangle, /*!< \brief a filled curved triangle, pointing to the right \image html symbols/symbol_filled_right_curved_triangle.png */
JKQTPOctagon, /*!< \brief an unfilled octagon \image html symbols/symbol_octagon.png */
JKQTPFilledOctagon, /*!< \brief a filled octagon \image html symbols/symbol_filled_octagon.png */
JKQTPUpDownTriangle, /*!< \brief a overlay of an up and a down triangle symbol \image html symbols/symbol_updowntriangle.png */
JKQTPFilledUpDownTriangle, /*!< \brief a filled version of the overlay of an up and a down triangle \image html symbols/symbol_filled_updowntriangle.png */
JKQTPHorizontalHourglass, /*!< \brief a horizontal hour glass symbol \image html symbols/symbol_horizontal_hourglass.png */
JKQTPFilledHorizontalHourglass, /*!< \brief a filled horizontal hour glass symbol \image html symbols/symbol_filled_horizontal_hourglass.png */
JKQTPSantaClauseHouse, /*!< \brief a small house symbol ("Das is das haus vom Nicolaus") \image html symbols/symbol_santaclause.png */
JKQTPFilledSantaClauseHouse, /*!< \brief a filled small house symbol ("Das is das haus vom Nicolaus") \image html symbols/symbol_filled_santaclause.png */
JKQTPMale, /*!< \brief a male symbol \image html symbols/symbol_male.png */
JKQTPFemale, /*!< \brief a female symbol \image html symbols/symbol_female.png */
JKQTPSymbolCount, /*!< \brief can be used to iterate over all symbols using: <code>for (int i=0; i<static_cast<int>(JKQTPSymbolCount); i++) { JKQTPGraphSymbols s=static_cast<JKQTPGraphSymbols>(i); ... }</code> */
JKQTPMaxSymbolID=JKQTPSymbolCount-1, /*!< \brief points to the last available symbol, can be used to iterate over all symbols: <code>for (int i=0; i<=static_cast<int>(JKQTPMaxSymbolID); i++) { JKQTPGraphSymbols s=static_cast<JKQTPGraphSymbols>(i); ... }</code> */
JKQTPDefaultSymbol=JKQTPCross, /*!< \brief a default symbol used for plotting */
};
/** \brief converts a JKQTPGraphSymbols variable into a identifier string
* \ingroup jkqtptools_drawing
*/
JKQTP_LIB_EXPORT QString JKQTPGraphSymbols2String(JKQTPGraphSymbols pos);
/** \brief converts a JKQTPGraphSymbols variable into a human-readable string
* \ingroup jkqtptools_drawing
*/
JKQTP_LIB_EXPORT QString JKQTPGraphSymbols2NameString(JKQTPGraphSymbols pos);
/** \brief converts a String into a JKQTPGraphSymbols
* \ingroup jkqtptools_drawing
*/
JKQTP_LIB_EXPORT JKQTPGraphSymbols String2JKQTPGraphSymbols(const QString& pos);
/** \brief rotate a rectangle by given angle (rotates all points around the center of the rectangle and returns it as a QPolygonF)
* \ingroup jkqtptools_drawing
*/
JKQTP_LIB_EXPORT QPolygonF jkqtpRotateRect(QRectF r, double angle);
/*! \brief plot the specified symbol at pixel position x,y
\ingroup jkqtptools_drawing
\tparam TPainter Type of \a painter: A class like JKQTPEnhancedPainter or <a href="http://doc.qt.io/qt-5/qpainter.html">QPainter</a>
\param painter the <a href="http://doc.qt.io/qt-5/qpainter.html">QPainter</a> to draw to
\param x x-coordinate of the symbol center
\param y y-coordinate of the symbol center
\param symbol type of the symbol to plot, see JKQTPGraphSymbols
\param size size (width/height) of the symbol around (\a x , \a y)
\param symbolLineWidth width of the lines used to draw the symbol
\param color color of the symbol lines
\param fillColor color of the symbol filling
*/
template <class TPainter>
inline void JKQTPPlotSymbol(TPainter& painter, double x, double y, JKQTPGraphSymbols symbol, double size, double symbolLineWidth, QColor color, QColor fillColor);
/*! \brief plot the specified symbol at pixel position x,y
\ingroup jkqtptools_drawing
\param paintDevice the paint device to draw on
\param x x-coordinate of the symbol center
\param y y-coordinate of the symbol center
\param symbol type of the symbol to plot, see JKQTPGraphSymbols
\param size size (width/height) of the symbol around (\a x , \a y)
\param symbolLineWidth width of the lines used to draw the symbol
\param color color of the symbol lines
\param fillColor color of the symbol filling
*/
JKQTP_LIB_EXPORT void JKQTPPlotSymbol(QPaintDevice& paintDevice, double x, double y, JKQTPGraphSymbols symbol, double size, double symbolLineWidth, QColor color, QColor fillColor);
/*! \brief plot an arrow between positions (x1,y1) and (x2,y2)
\ingroup jkqtptools_drawing
\param painter the <a href="http://doc.qt.io/qt-5/qpainter.html">QPainter</a> to draw to
\param x1 first x-coordinate of the arrow
\param y1 first y-coordinate of the arrow
\param x2 second x-coordinate of the arrow
\param y2 second y-coordinate of the arrow
\param symbol type of the symbol to plot, see JKQTPGraphSymbols
\param size size (width/height) of the symbol around (\a x , \a y)
\param symbolLineWidth width of the lines used to draw the symbol
\param color color of the symbol lines
\param fillColor color of the symbol filling
*/
//JKQTP_LIB_EXPORT void JKQTPPlotArrow(JKQTPEnhancedPainter& painter, int x, int y, JKQTPGraphSymbols symbol, double size, double symbolLineWidth, QColor color, QColor fillColor);
/*! \brief draw an ellipse without setting pen or brush, or saving the painter!
\ingroup jkqtptools_drawing
\return a QVector<QPointF> with points that may be used for drawing
\param x center of ellipse (x-coordinate)
\param y center of ellipse (y-coordinate)
\param a half axis in x-direction
\param b half axis in y-direction
\param angle_start starting angle of ellipse section
\param angle_end ending angle of ellipse section
\param alpha rotation angle of ellipse
\param controlPoints the number of points to use for drawing
\param[out] x_start first point of ellipse
\param[out] x_end last point of ellipse
\note all angles are given in degrees [0..360]
*/
JKQTP_LIB_EXPORT QVector<QPointF> JKQTPDrawEllipse(double x, double y, double a, double b, double angle_start=0, double angle_end=360, double alpha=0, int controlPoints=180, QPointF* x_start=nullptr, QPointF* x_end=nullptr);
/*! \brief draw a tooltip, using the current brush and pen of the provided painter
\ingroup jkqtptools_drawing
\tparam TPainter Type of \a painter: A class like JKQTPEnhancedPainter or <a href="http://doc.qt.io/qt-5/qpainter.html">QPainter</a>
\param painter QPainter-like object to use for painting
\param x x-coordinate of position the tooltip points to
\param y y-coordinate of position the tooltip points to
\param rect rectangle of the main tooltip area
*/
template <class TPainter>
inline void JKQTPDrawTooltip(TPainter& painter, double x, double y, const QRectF& rect);
/** \brief cleans a polygon by uniting all consecutive points that were closer than distanceThreshold are united
* \ingroup jkqtptools_drawing
*
* \param poly polygon to clean
* \param distanceThreshold if two end-points are closer together as this value, they are united to a single point
* \return a cleaned polygon, where all consecutive points that were closer than distanceThreshold are united
*/
JKQTP_LIB_EXPORT QPolygonF JKQTPCleanPolygon(const QPolygonF& poly, double distanceThreshold=0.3);
/** \brief takes a list of QLineF objesct \a lines and tries to combine as many of them as possible to QPolygonF objects.
* <b>Note: This method implements an incomplete algorithm with \a searchMaxSurroundingElements>0, as solving
* the complete problem is very time-consuming (cubic runtime)
* \ingroup jkqtptools_drawing
*
* \param lines line segments to unify
* \param distanceThreshold if two end-points are closer together as this value, they are united to a single point
* \param searchMaxSurroundingElements limits the search for a connected polygon to at most this number of neighbors
* \return a vector of QPolygonF objects, which contain longer line-segments formed from \a lines
*/
JKQTP_LIB_EXPORT QVector<QPolygonF> JKQTPUnifyLinesToPolygons(const QVector<QLineF>& lines, double distanceThreshold=0.3, int searchMaxSurroundingElements=10);
template <class TPainter>
inline void JKQTPPlotSymbol(TPainter& painter, double x, double y, JKQTPGraphSymbols symbol, double symbolSize, double symbolLineWidth, QColor color, QColor fillColor) {
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
QPen p=painter.pen();
p.setColor(color);
p.setWidthF(qMax(JKQTPlotterDrawingTools::ABS_MIN_LINEWIDTH, symbolLineWidth));
p.setStyle(Qt::SolidLine);
p.setCapStyle(Qt::FlatCap);
painter.setPen(p);
QBrush b=painter.brush();
b.setColor(fillColor);
b.setStyle(Qt::SolidPattern);
const double w=symbolSize;
const double w2=w/2.0;
const double w45=fabs(w*cos(45.0/180.0*M_PI));
const double w3=w/3.0;
// calculate star cordinates as static values
static int star5_items=0;
static double star5cordsx[10];
static double star5cordsy[10];
if (star5_items==0) {
star5_items=5;
double angle=360.0/double(star5_items)/180.0*M_PI;
for (int i=0; i<star5_items; i++) {
double a=(static_cast<double>(i)+0.5)*angle;
star5cordsx[i*2]=sin(a);
star5cordsx[i*2+1]=0.5*sin(a+angle/2.0);
star5cordsy[i*2]=cos(a);
star5cordsy[i*2+1]=0.5*cos(a+angle/2.0);
}
}
static int star6_items=0;
static double star6cordsx[12];
static double star6cordsy[12];
if (star6_items==0) {
star6_items=6;
double angle=360.0/double(star6_items)/180.0*M_PI;
for (int i=0; i<star6_items; i++) {
double a=(static_cast<double>(i)+0.5)*angle;
star6cordsx[i*2]=sin(a);
star6cordsx[i*2+1]=0.5*sin(a+angle/2.0);
star6cordsy[i*2]=cos(a);
star6cordsy[i*2+1]=0.5*cos(a+angle/2.0);
}
}
static int star8_items=0;
static double star8cordsx[16];
static double star8cordsy[16];
if (star8_items==0) {
star8_items=8;
double angle=360.0/double(star8_items)/180.0*M_PI;
for (int i=0; i<star8_items; i++) {
double a=(static_cast<double>(i)+0.5)*angle;
star8cordsx[i*2]=sin(a);
star8cordsx[i*2+1]=0.5*sin(a+angle/2.0);
star8cordsy[i*2]=cos(a);
star8cordsy[i*2+1]=0.5*cos(a+angle/2.0);
}
}
switch(symbol) {
case JKQTPDot:
painter.drawPoint(QPointF(x,y));
break;
case JKQTPCross:{
QPainterPath path;
path.moveTo(x-w2,y-w2);
path.lineTo(x+w2,y+w2);
path.moveTo(x-w2,y+w2);
path.lineTo(x+w2,y-w2);
painter.drawPath(path);
}
break;
case JKQTPPlus:{
QVector<QLineF> lines;
lines<<QLineF(x,y-w2,x,y+w2);
lines<<QLineF(x-w2,y,x+w2,y);
painter.drawLines(lines);
}
break;
case JKQTPCircle:{
QRectF rectangle(x-w2, y-w2, w, w);
painter.drawEllipse(rectangle);
}
break;
case JKQTPCircleCross:{
QRectF rectangle(x-w2, y-w2, w, w);
painter.drawEllipse(rectangle);
QVector<QLineF> lines;
lines<<QLineF(x-w45/2.0,y-w45/2.0,x+w45/2.0,y+w45/2.0);
lines<<QLineF(x-w45/2.0,y+w45/2.0,x+w45/2.0,y-w45/2.0);
painter.drawLines(lines);
}
break;
case JKQTPCirclePlus:{
QRectF rectangle(x-w2, y-w2, w, w);
painter.drawEllipse(rectangle);
QVector<QLineF> lines;
lines<<QLineF(x,y-w2,x,y+w2);
lines<<QLineF(x-w2,y,x+w2,y);
painter.drawLines(lines);
}
break;
case JKQTPCirclePeace:{
QRectF rectangle(x-w2, y-w2, w, w);
painter.drawEllipse(rectangle);
QVector<QLineF> lines;
lines<<QLineF(x,y-w2,x,y+w2);
lines<<QLineF(x,y,x+w45/2.0,y+w45/2.0);
lines<<QLineF(x,y,x-w45/2.0,y+w45/2.0);
painter.drawLines(lines);
}
break;
case JKQTPPeace:{
QVector<QLineF> lines;
lines<<QLineF(x,y-w2,x,y+w2);
lines<<QLineF(x,y,x+w45/2.0,y+w45/2.0);
lines<<QLineF(x,y,x-w45/2.0,y+w45/2.0);
painter.drawLines(lines);
}
break;
case JKQTPTarget:{
QPainterPath path;
QRectF rectangle3(x-w3, y-w3, 2.0*w3, 2.0*w3);
path.addEllipse(rectangle3);
path.moveTo(QPointF(x,y-w2));
path.lineTo(QPointF(x,y+w2));
path.moveTo(QPointF(x-w2,y));
path.lineTo(QPointF(x+w2,y));
painter.drawPath(path);
}
break;
case JKQTPFemale:{
QPainterPath path;
QRectF rectangle3(x-w2/2.0, y-w2, w2, w2);
path.addEllipse(rectangle3);
path.moveTo(QPointF(x,y));
path.lineTo(QPointF(x,y+w2));
path.moveTo(QPointF(x-w2/3.0,y+w2/2.0));
path.lineTo(QPointF(x+w2/3.0,y+w2/2.0));
painter.drawPath(path);
}
break;
case JKQTPMale:{
QPainterPath path;
QRectF rectangle3(x-w2/2.0, y-w2/2.0, w2, w2);
path.addEllipse(rectangle3);
path.moveTo(QPointF(x+w2/2.0*cos(45.0/180.0*M_PI),y-w2/2.0*cos(45.0/180.0*M_PI)));
path.lineTo(QPointF(x+w2,y-w2));
path.moveTo(QPointF(x+w2-w2/2.0,y-w2));
path.lineTo(QPointF(x+w2,y-w2));
path.lineTo(QPointF(x+w2,y-w2+w2/2.0));
painter.drawPath(path);
}
break;
case JKQTPFilledCircle:{
painter.setBrush(b);
QRectF rectangle(x-w2, y-w2, w, w);
painter.drawEllipse(rectangle);
}
break;
case JKQTPRect:{
painter.setBrush(QColor(Qt::transparent));
QRectF rectangle(x-w2, y-w2, w, w);
painter.drawRect(rectangle);
}
break;
case JKQTPRectCross:{
painter.setBrush(QColor(Qt::transparent));
QPainterPath path;
path.moveTo(x-w2,y-w2);
path.lineTo(x+w2,y+w2);
path.moveTo(x-w2,y+w2);
path.lineTo(x+w2,y-w2);
painter.drawPath(path);
QRectF rectangle(x-w2, y-w2, w, w);
painter.drawRect(rectangle);
}
break;
case JKQTPFilledCurvedTriangle:{
painter.save();
painter.translate(x,y);
painter.setBrush(b);
QPainterPath path;
path.moveTo(0,0-w2);
path.quadTo(0-w/10.0,0+w/4.0, 0-w2,0+w2);
path.quadTo(0,0+w/4.0, 0+w2,0+w2);
path.quadTo(0+w/10.0,0+w/4.0, 0,0-w2);
painter.drawPath(path);
painter.restore();
}
break;
case JKQTPCurvedTriangle:{
painter.save();
painter.translate(x,y);
painter.setBrush(QColor(Qt::transparent));
QPainterPath path;
path.moveTo(0,0-w2);
path.quadTo(0-w/10.0,0+w/4.0, 0-w2,0+w2);
path.quadTo(0,0+w/4.0, 0+w2,0+w2);
path.quadTo(0+w/10.0,0+w/4.0, 0,0-w2);
painter.drawPath(path);
painter.restore();
}
break;
case JKQTPFilledDownCurvedTriangle:{
painter.save();
painter.translate(x,y);
painter.rotate(180);
painter.setBrush(b);
QPainterPath path;
path.moveTo(0,0-w2);
path.quadTo(0-w/10.0,0+w/4.0, 0-w2,0+w2);
path.quadTo(0,0+w/4.0, 0+w2,0+w2);
path.quadTo(0+w/10.0,0+w/4.0, 0,0-w2);
painter.drawPath(path);
painter.restore();
}
break;
case JKQTPDownCurvedTriangle:{
painter.save();
painter.translate(x,y);
painter.rotate(180);
painter.setBrush(QColor(Qt::transparent));
QPainterPath path;
path.moveTo(0,0-w2);
path.quadTo(0-w/10.0,0+w/4.0, 0-w2,0+w2);
path.quadTo(0,0+w/4.0, 0+w2,0+w2);
path.quadTo(0+w/10.0,0+w/4.0, 0,0-w2);
painter.drawPath(path);
painter.restore();
}
break;
case JKQTPFilledLeftCurvedTriangle:{
painter.save();
painter.translate(x,y);
painter.rotate(-90);
painter.setBrush(b);
QPainterPath path;
path.moveTo(0,0-w2);
path.quadTo(0-w/10.0,0+w/4.0, 0-w2,0+w2);
path.quadTo(0,0+w/4.0, 0+w2,0+w2);
path.quadTo(0+w/10.0,0+w/4.0, 0,0-w2);
painter.drawPath(path);
painter.restore();
}
break;
case JKQTPLeftCurvedTriangle:{
painter.save();
painter.translate(x,y);
painter.rotate(-90);
painter.setBrush(QColor(Qt::transparent));
QPainterPath path;
path.moveTo(0,0-w2);
path.quadTo(0-w/10.0,0+w/4.0, 0-w2,0+w2);
path.quadTo(0,0+w/4.0, 0+w2,0+w2);
path.quadTo(0+w/10.0,0+w/4.0, 0,0-w2);
painter.drawPath(path);
painter.restore();
}
break;
case JKQTPFilledRightCurvedTriangle:{
painter.save();
painter.translate(x,y);
painter.rotate(90);
painter.setBrush(b);
QPainterPath path;
path.moveTo(0,0-w2);
path.quadTo(0-w/10.0,0+w/4.0, 0-w2,0+w2);
path.quadTo(0,0+w/4.0, 0+w2,0+w2);
path.quadTo(0+w/10.0,0+w/4.0, 0,0-w2);
painter.drawPath(path);
painter.restore();
}
break;
case JKQTPRightCurvedTriangle:{
painter.save();
painter.translate(x,y);
painter.rotate(90);
painter.setBrush(QColor(Qt::transparent));
QPainterPath path;
path.moveTo(0,0-w2);
path.quadTo(0-w/10.0,0+w/4.0, 0-w2,0+w2);
path.quadTo(0,0+w/4.0, 0+w2,0+w2);
path.quadTo(0+w/10.0,0+w/4.0, 0,0-w2);
painter.drawPath(path);
painter.restore();
}
break;
case JKQTPRectTriangle:{
painter.setBrush(QColor(Qt::transparent));
QPolygonF poly;
poly<<QPointF(x-w2, y+w2)<<QPointF(x, y-w2)<<QPointF(x+w2, y+w2)<<QPointF(x-w2, y+w2)<<QPointF(x-w2, y-w2)<<QPointF(x+w2, y-w2)<<QPointF(x+w2, y+w2);
painter.drawConvexPolygon(poly);
}
break;
case JKQTPRectDownTriangle:{
painter.setBrush(QColor(Qt::transparent));
QPolygonF poly;
poly<<QPointF(x-w2, y-w2)<<QPointF(x, y+w2)<<QPointF(x+w2, y-w2)<<QPointF(x-w2, y-w2)<<QPointF(x-w2, y+w2)<<QPointF(x+w2, y+w2)<<QPointF(x+w2, y-w2);
painter.drawConvexPolygon(poly);
}
break;
case JKQTPRectLeftTriangle:{
painter.setBrush(QColor(Qt::transparent));
QPolygonF poly;
poly<<QPointF(x+w2, y-w2)<<QPointF(x-w2, y)<<QPointF(x+w2, y+w2)<<QPointF(x-w2, y+w2)<<QPointF(x-w2, y-w2)<<QPointF(x+w2, y-w2)<<QPointF(x+w2, y+w2);
painter.drawConvexPolygon(poly);
}
break;
case JKQTPRectRightTriangle:{
painter.setBrush(QColor(Qt::transparent));
QPolygonF poly;
poly<<QPointF(x-w2, y-w2)<<QPointF(x+w2, y)<<QPointF(x-w2, y+w2)<<QPointF(x+w2, y+w2)<<QPointF(x+w2, y-w2)<<QPointF(x-w2, y-w2)<<QPointF(x-w2, y+w2);
painter.drawConvexPolygon(poly);
}
break;
case JKQTPRectPlus:{
painter.setBrush(QColor(Qt::transparent));
QVector<QLineF> lines;
lines<<QLineF(x,y-w2,x,y+w2);
lines<<QLineF(x-w2,y,x+w2,y);
painter.drawLines(lines);
QRectF rectangle(x-w2, y-w2, w, w);
painter.drawRect(rectangle);
}
break;
case JKQTPFilledRect:{
painter.setBrush(b);
QRectF rectangle(x-w2, y-w2, w, w);
painter.drawRect(rectangle);
}
break;
case JKQTPTriangle: {
painter.setBrush(QColor(Qt::transparent));
QPolygonF poly;
poly<<QPointF(x-w2, y+w2)<<QPointF(x+w2, y+w2)<<QPointF(x, y-w2);
painter.drawConvexPolygon(poly);
} break;
case JKQTPFilledTriangle: {
painter.setBrush(b);
QPolygonF poly;
poly<<QPointF(x-w2, y+w2)<<QPointF(x+w2, y+w2)<<QPointF(x, y-w2);
painter.drawConvexPolygon(poly);
} break;
case JKQTPDownTriangle: {
painter.setBrush(QColor(Qt::transparent));
QPolygonF poly;
poly<<QPointF(x-w2, y-w2)<<QPointF(x+w2, y-w2)<<QPointF(x, y+w2);
painter.drawConvexPolygon(poly);
} break;
case JKQTPFilledDownTriangle: {
painter.setBrush(b);
QPolygonF poly;
poly<<QPointF(x-w2, y-w2)<<QPointF(x+w2, y-w2)<<QPointF(x, y+w2);
painter.drawConvexPolygon(poly);
} break;
case JKQTPLeftTriangle: {
painter.setBrush(QColor(Qt::transparent));
QPolygonF poly;
poly<<QPointF(x+w2, y+w2)<<QPointF(x-w2, y)<<QPointF(x+w2, y-w2);
painter.drawConvexPolygon(poly);
} break;
case JKQTPFilledLeftTriangle: {
painter.setBrush(b);
QPolygonF poly;
poly<<QPointF(x+w2, y+w2)<<QPointF(x-w2, y)<<QPointF(x+w2, y-w2);
painter.drawConvexPolygon(poly);
} break;
case JKQTPRightTriangle: {
painter.setBrush(QColor(Qt::transparent));
QPolygonF poly;
poly<<QPointF(x-w2, y+w2)<<QPointF(x+w2, y)<<QPointF(x-w2, y-w2);
painter.drawConvexPolygon(poly);
} break;
case JKQTPFilledRightTriangle: {
painter.setBrush(b);
QPolygonF poly;
poly<<QPointF(x-w2, y+w2)<<QPointF(x+w2, y)<<QPointF(x-w2, y-w2);
painter.drawConvexPolygon(poly);
} break;
case JKQTPTripod: {
painter.setBrush(QColor(Qt::transparent));
QVector<QLineF> lines;
lines<<QLineF(x, y-w2, x, y)
<<QLineF(x, y, x-w45, y+w45)
<<QLineF(x, y, x+w45, y+w45);
painter.drawLines(lines);
} break;
case JKQTPDownTripod: {
painter.setBrush(QColor(Qt::transparent));
QVector<QLineF> lines;
lines<<QLineF(x, y+w2, x, y)
<<QLineF(x, y, x-w45, y-w45)
<<QLineF(x, y, x+w45, y-w45);
painter.drawLines(lines);
} break;
case JKQTPLeftTripod: {
painter.setBrush(QColor(Qt::transparent));
QVector<QLineF> lines;
lines<<QLineF(x-w2, y, x, y)
<<QLineF(x, y, x+w45, y-w45)
<<QLineF(x, y, x+w45, y+w45);
painter.drawLines(lines);
} break;
case JKQTPRightTripod: {
painter.setBrush(QColor(Qt::transparent));
QVector<QLineF> lines;
lines<<QLineF(x+w2, y, x, y)
<<QLineF(x, y, x-w45, y-w45)
<<QLineF(x, y, x-w45, y+w45);
painter.drawLines(lines);
} break;
case JKQTPUpDownTriangle: {
painter.setBrush(QColor(Qt::transparent));
QPolygonF poly;
poly<<QPointF(x-w2, y+w2)<<QPointF(x, y+w2)<<QPointF(x+w2, y-w2)<<QPointF(x-w2, y-w2)<<QPointF(x, y+w2)<<QPointF(x+w2, y+w2)<<QPointF(x, y-w2)<<QPointF(x-w2, y+w2);
painter.drawConvexPolygon(poly);
} break;
case JKQTPFilledUpDownTriangle: {
painter.setBrush(b);
QPolygonF poly;
poly<<QPointF(x-w2, y+w2)<<QPointF(x, y+w2)<<QPointF(x+w2, y-w2)<<QPointF(x-w2, y-w2)<<QPointF(x, y+w2)<<QPointF(x+w2, y+w2)<<QPointF(x, y-w2)<<QPointF(x-w2, y+w2);
painter.drawConvexPolygon(poly);
} break;
case JKQTPSantaClauseHouse: {
painter.setBrush(QColor(Qt::transparent));
QPolygonF poly;
poly<<QPointF(x-w2, y+w2)<<QPointF(x+w2, y+w2)<<QPointF(x+w2, y-w/6.0)<<QPointF(x-w2, y-w/6.0)<<QPointF(x, y-w2)<<QPointF(x+w2, y-w/6.0)<<QPointF(x-w2, y+w2)<<QPointF(x-w2, y-w/6.0)<<QPointF(x+w2, y+w2);
painter.drawConvexPolygon(poly);
} break;
case JKQTPFilledSantaClauseHouse: {
painter.setBrush(b);
QPolygonF poly;
poly<<QPointF(x-w2, y+w2)<<QPointF(x+w2, y+w2)<<QPointF(x+w2, y-w/6.0)<<QPointF(x-w2, y-w/6.0)<<QPointF(x, y-w2)<<QPointF(x+w2, y-w/6.0)<<QPointF(x-w2, y+w2)<<QPointF(x-w2, y-w/6.0)<<QPointF(x+w2, y+w2);
painter.drawConvexPolygon(poly);
} break;
case JKQTPHourglass: {
painter.setBrush(QColor(Qt::transparent));
QPolygonF poly;
poly<<QPointF(x-w2, y+w2)<<QPointF(x+w2, y+w2)<<QPointF(x-w2, y-w2)<<QPointF(x+w2, y-w2);
painter.drawConvexPolygon(poly);
} break;
case JKQTPHorizontalHourglass: {
painter.setBrush(QColor(Qt::transparent));
QPolygonF poly;
poly<<QPointF(x-w2, y+w2)<<QPointF(x-w2, y-w2)<<QPointF(x+w2, y+w2)<<QPointF(x+w2, y-w2);
painter.drawConvexPolygon(poly);
} break;
case JKQTPFilledHourglass: {
painter.setBrush(b);
QPolygonF poly;
poly<<QPointF(x-w2, y+w2)<<QPointF(x+w2, y+w2)<<QPointF(x-w2, y-w2)<<QPointF(x+w2, y-w2);
painter.drawConvexPolygon(poly);
} break;
case JKQTPFilledHorizontalHourglass: {
painter.setBrush(b);
QPolygonF poly;
poly<<QPointF(x-w2, y+w2)<<QPointF(x-w2, y-w2)<<QPointF(x+w2, y+w2)<<QPointF(x+w2, y-w2);
painter.drawConvexPolygon(poly);
} break;
case JKQTPDiamond: {
QPolygonF poly;
painter.setBrush(QColor(Qt::transparent));
poly<<QPointF(x, y-w2)<<QPointF(x+w2, y)<<QPointF(x, y+w2)<<QPointF(x-w2, y);
painter.drawConvexPolygon(poly);
} break;
case JKQTPDiamondPlus: {
QPolygonF poly;
painter.setBrush(QColor(Qt::transparent));
poly<<QPointF(x, y-w2)<<QPointF(x+w2, y)<<QPointF(x, y+w2)<<QPointF(x-w2, y);
painter.drawConvexPolygon(poly);
painter.drawLine(poly[0], poly[2]);
painter.drawLine(poly[1], poly[3]);
} break;
case JKQTPDiamondCross: {
QPolygonF poly;
painter.setBrush(QColor(Qt::transparent));
poly<<QPointF(x, y-w2)<<QPointF(x+w2, y)<<QPointF(x, y+w2)<<QPointF(x-w2, y);
painter.drawConvexPolygon(poly);
painter.drawLine((poly[0]+poly[1])/2.0, (poly[2]+poly[3])/2.0);
painter.drawLine((poly[1]+poly[2])/2.0, (poly[3]+poly[0])/2.0);
} break;
case JKQTPFilledDiamond: {
painter.setBrush(b);
QPolygonF poly;
poly<<QPointF(x, y-w2)<<QPointF(x+w2, y)<<QPointF(x, y+w2)<<QPointF(x-w2, y);
painter.drawConvexPolygon(poly);
} break;
case JKQTPstar: {
painter.setBrush(QColor(Qt::transparent));
QPolygonF poly;
for (int i=0; i<star5_items*2; i++) {
poly<<QPointF(x+star5cordsx[i]*w2, y+star5cordsy[i]*w2);
}
painter.drawConvexPolygon(poly);
} break;
case JKQTPFilledStar: {
painter.setBrush(b);
QPolygonF poly;
for (int i=0; i<star5_items*2; i++) {
poly<<QPointF(x+star5cordsx[i]*w2, y+star5cordsy[i]*w2);
}
painter.drawConvexPolygon(poly);
} break;
case JKQTPPentagon: {
painter.setBrush(QColor(Qt::transparent));
QPolygonF poly;
for (int i=0; i<star5_items*2; i+=2) {
poly<<QPointF(x+star5cordsx[i]*w2, y+star5cordsy[i]*w2);
}
painter.drawConvexPolygon(poly);
} break;
case JKQTPHexagon: {
painter.setBrush(QColor(Qt::transparent));
QPolygonF poly;
for (int i=0; i<star6_items*2; i+=2) {
poly<<QPointF(x+star6cordsx[i]*w2, y+star6cordsy[i]*w2);
}
painter.drawConvexPolygon(poly);
} break;
case JKQTPOctagon: {
painter.setBrush(QColor(Qt::transparent));
QPolygonF poly;
for (int i=0; i<star8_items*2; i+=2) {
poly<<QPointF(x+star8cordsx[i]*w2, y+star8cordsy[i]*w2);
}
painter.drawConvexPolygon(poly);
} break;
case JKQTPAsterisc: {
QPainterPath path;
for (int i=0; i<star5_items*2; i+=2) {
path.moveTo(x+star5cordsx[i]*w2, y+star5cordsy[i]*w2);
path.lineTo(x,y);
}
painter.drawPath(path);
} break;
case JKQTPAsterisc6: {
QPainterPath path;
for (int i=0; i<star6_items*2; i+=2) {
path.moveTo(x+star6cordsx[i]*w2, y+star6cordsy[i]*w2);
path.lineTo(x,y);
}
painter.drawPath(path);
} break;
case JKQTPAsterisc8: {
QPainterPath path;
for (int i=0; i<star8_items*2; i+=2) {
path.moveTo(x+star8cordsx[i]*w2, y+star8cordsy[i]*w2);
path.lineTo(x,y);
}
painter.drawPath(path);
} break;
case JKQTPFilledPentagon: {
painter.setBrush(b);
QPolygonF poly;
for (int i=0; i<star5_items*2; i+=2) {
poly<<QPointF(x+star5cordsx[i]*w2, y+star5cordsy[i]*w2);
}
painter.drawConvexPolygon(poly);
} break;
case JKQTPFilledHexagon: {
painter.setBrush(b);
QPolygonF poly;
for (int i=0; i<star6_items*2; i+=2) {
poly<<QPointF(x+star6cordsx[i]*w2, y+star6cordsy[i]*w2);
}
painter.drawConvexPolygon(poly);
} break;
case JKQTPFilledOctagon: {
painter.setBrush(b);
QPolygonF poly;
for (int i=0; i<star8_items*2; i+=2) {
poly<<QPointF(x+star8cordsx[i]*w2, y+star8cordsy[i]*w2);
}
painter.drawConvexPolygon(poly);
} break;
default: break;
}
}
template <class TPainter>
inline void JKQTPDrawTooltip(TPainter& painter, double x, double y, const QRectF& rect)
{
QPolygonF poly;
if (y<rect.top()) {
poly<<rect.topLeft()<<QPointF(rect.left()+rect.width()/3, rect.top())<<QPointF(x,y)<<QPointF(rect.right()-rect.width()/3, rect.top())<< rect.topRight()<<rect.bottomRight()<<rect.bottomLeft()<<rect.topLeft();
painter.drawPolygon(poly);
} else if (y>rect.bottom()) {
poly<<rect.topLeft()<<rect.topRight()<<rect.bottomRight()<<QPointF(rect.right()-rect.width()/3, rect.bottom())<<QPointF(x,y)<<QPointF(rect.left()+rect.width()/3, rect.bottom())<< rect.bottomLeft()<<rect.topLeft();
painter.drawPolygon(poly);
} else if (x<rect.left()) {
poly<<QPointF(x,y)<<rect.topLeft()<<rect.topRight()<<rect.bottomRight()<<rect.bottomLeft()<<QPointF(rect.left(), rect.top()+rect.height()/2)<<QPointF(x,y);
painter.drawPolygon(poly);
} else if (x>rect.left()) {
poly<<rect.topLeft()<<rect.topRight()<<QPointF(x,y)<<QPointF(rect.right(), rect.top()+rect.height()/2)<<rect.bottomRight()<<rect.bottomLeft()<<rect.topLeft();
painter.drawPolygon(poly);
} else {
painter.drawRect(rect);
}
}
#endif // JKQTPDRAWINGTOOLS_H_INCLUDED

View File

@ -22,7 +22,7 @@ Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>)
#include "jkqtplottertools/jkqtpenhancedpainter.h"
#include "jkqtcommon/jkqtpenhancedpainter.h"

View File

@ -0,0 +1,23 @@
/*
Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>)
last modification: $LastChangedDate$ (revision $Rev$)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License (LGPL) as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License (LGPL) for more details.
You should have received a copy of the GNU Lesser General Public License (LGPL)
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "jkqtplinalgtools.h"

View File

@ -0,0 +1,866 @@
/*
Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>)
last modification: $LastChangedDate$ (revision $Rev$)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License (LGPL) as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License (LGPL) for more details.
You should have received a copy of the GNU Lesser General Public License (LGPL)
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef JKQTPLINALGTOOLS_H_INCLUDED
#define JKQTPLINALGTOOLS_H_INCLUDED
#include <stdint.h>
#include <cmath>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <limits>
#include <vector>
#include <utility>
#include <cfloat>
#include <ostream>
#include <iomanip>
#include <sstream>
#include "jkqtcommon/jkqtp_imexport.h"
#include "jkqtcommon/jkqtparraytools.h"
#include "jkqtcommon/jkqtpmathtools.h"
#include "jkqtcommon/jkqtpstringtools.h"
#ifdef _OPENMP
# include <omp.h>
#endif
#ifndef JKQTP_ALIGNMENT_BYTES
#define JKQTP_ALIGNMENT_BYTES 32
#endif
#ifdef JKQTP_STATISTICS_TOOLS_MAY_USE_EIGEN3
# include <Eigen/Core>
# include <Eigen/SVD>
# include <Eigen/Jacobi>
# include <Eigen/LU>
# include <Eigen/QR>
#endif
/** \brief calculate the index of the entry in line \a l and column \a c
* in a row-major matrix with \a C columns
* \ingroup jkqtptools_math_linalg
*
* You can use this to access a matrix with L rows and C columns:
* \code
* for (long l=0; l<L; l++) {
* for (long c=0; c<C; c++) {
* matrix[jkqtplinalgMatIndex(l,c,C)=0;
* if (l==c) matrix[jkqtplinalgMatIndex(l,c,C)=1;
* }
* }
* \endcode
*/
#define jkqtplinalgMatIndex(l,c,C) ((l)*(C)+(c))
/** \brief print the given LxC matrix to std::cout
* \ingroup jkqtptools_math_linalg
*
* \tparam type of the matrix cells (typically double or float)
* \param L number of lines/rows in the matrix
* \param C number of columns in the matrix
* \param width width (in characters) of each cell in the output (used for formatting)
* \param precision precision (in digits) for string-conversions in the output (used for formatting)
* \param mode if \c =='f' the mode \c std::fixed is used for output, otherwise \c std::scientific is used
*/
template <class T>
inline void jkqtplinalgPrintMatrix(T* matrix, long L, long C, int width=9, int precision=3, char mode='f') {
for (long l=0; l<L; l++) {
for (long c=0; c<C; c++) {
if (c>0) std::cout<<", ";
std::cout.precision(precision);
std::cout.width(width);
if (mode=='f') std::cout<<std::fixed<<std::right<<matrix[jkqtplinalgMatIndex(l,c,C)];
else std::cout<<std::scientific<<std::right<<matrix[jkqtplinalgMatIndex(l,c,C)];
}
std::cout<<std::endl;
}
}
/** \brief convert the given LxC matrix to std::string
* \ingroup jkqtptools_math_linalg
*
* \tparam type of the matrix cells (typically double or float)
* \param L number of lines/rows in the matrix
* \param C number of columns in the matrix
* \param width width (in characters) of each cell in the output (used for formatting)
* \param precision precision (in digits) for string-conversions in the output (used for formatting)
* \param mode the (printf()) string conversion mode for output of the cell values
*/
template <class T>
inline std::string jkqtplinalgMatrixToString(T* matrix, long L, long C, int width=9, int precision=3, const std::string& mode=std::string("g")) {
std::string format="%"+jkqtp_inttostr(width)+std::string(".")+jkqtp_inttostr(precision)+std::string("l")+mode;
std::ostringstream ost;
for (long l=0; l<L; l++) {
for (long c=0; c<C; c++) {
if (c>0) ost<<", ";
char buf[500];
sprintf(buf, format.c_str(), jkqtp_todouble(matrix[jkqtplinalgMatIndex(l,c,C)]));
ost<<buf;
/*ost.precision(precision);
ost.width(width);
if (mode=='f') ost<<std::fixed<<std::right<<matrix[jkqtplinalgMatIndex(l,c,C)];
else ost<<std::scientific<<std::right<<matrix[jkqtplinalgMatIndex(l,c,C)];*/
}
ost<<std::endl;
}
return ost.str();
}
/** \brief maps the number range -1 ... +1 to a color-scale lightblue - white - lightred (used for coloring matrices!)
* \ingroup jkqtptools_math_linalg
*
* \param val the value to convert
* \param[out] r returns the red value (0..255)
* \param[out] g returns the green value (0..255)
* \param[out] b returns the blue value (0..255)
*/
inline void jkqtplinalgPM1ToRWBColors(double val, uint8_t& r, uint8_t& g, uint8_t& b){
r=255;
g=255;
b=255;
const double fval=fabs(val);
if (val<0 && val>=-1) {
r=jkqtp_boundedRoundTo<uint8_t>(0,255.0-fval*127.0,255);
g=jkqtp_boundedRoundTo<uint8_t>(0,255.0-fval*127.0,255);
} else if (val>0 && val<=1) {
b=jkqtp_boundedRoundTo<uint8_t>(0,255.0-fval*127.0,255);
g=jkqtp_boundedRoundTo<uint8_t>(0,255.0-fval*127.0,255);
} else if (val<-1) {
r=127;
g=127;
b=255;
} else if (val>1) {
r=255;
g=127;
b=127;
}
}
/** \brief maps the number range -1 ... +1 to a non-linear color-scale lightblue - white - lightred (used for coloring matrices!)
* \ingroup jkqtptools_math_linalg
*
* \param val the value to convert
* \param[out] r returns the red value (0..255)
* \param[out] g returns the green value (0..255)
* \param[out] b returns the blue value (0..255)
*/
inline void jkqtplinalgPM1ToNonlinRWBColors(double val, uint8_t& r, uint8_t& g, uint8_t& b, double gamma=0.5){
if (val<0) {
jkqtplinalgPM1ToRWBColors(-1.0*pow(-val,gamma),r,g,b);
} else {
jkqtplinalgPM1ToRWBColors(pow(val,gamma),r,g,b);
}
}
/** \brief convert the given LxC matrix to std::string, encoded as HTML table
* \ingroup jkqtptools_math_linalg
*
*
* \tparam type of the matrix cells (typically double or float)
* \param L number of lines/rows in the matrix
* \param C number of columns in the matrix
* \param width width (in characters) of each cell in the output (used for formatting)
* \param precision precision (in digits) for string-conversions in the output (used for formatting)
* \param mode the (printf()) string conversion mode for output of the cell values
* \param tableformat this is inserted into the \c <table...> tag (may contain HTML property definitions)
* \param prenumber this is inserted before each number (may contain HTML markup)
* \param postnumber this is inserted after each number (may contain HTML markup)
* \param colorcoding if \c true, teh cell backgrounds are color-coded
* \param zeroIsWhite if \c the color-coding is forced to white for 0 and then encodes in positive/negative direction with colors (red and blue)
* \param[out] colorlabel outputs a label explaining the auto-generated color-coding
* \param nonlinColors if \c true, a non-linear color-coding is used
* \param nonlinColorsGamma gamma-value for a non-linear color-coding
* \param colortableformat lie \a tableformat, but for the legend table output in \a colorLabel
*
* \see jkqtplinalgPM1ToNonlinRWBColors() and jkqtplinalgPM1ToRWBColors()
*/
template <class T>
inline std::string jkqtplinalgMatrixToHTMLString(T* matrix, long L, long C, int width=9, int precision=3, const std::string& mode=std::string("g"), const std::string& tableformat=std::string(), const std::string& prenumber=std::string(), const std::string& postnumber=std::string(), bool colorcoding=false, bool zeroIsWhite=true, std::string* colorlabel=nullptr, bool nonlinColors=false, double nonlinColorsGamma=0.25, const std::string& colortableformat=std::string()) {
std::ostringstream ost;
ost<<"<table "<<tableformat<<">\n";
std::string format="%"+jkqtp_inttostr(width)+std::string(".")+jkqtp_inttostr(precision)+std::string("l")+mode;
double minv=0, maxv=0;
if (colorcoding) {
jkqtpstatMinMax(matrix, L*C, minv, maxv);
}
for (long l=0; l<L; l++) {
ost<<" <tr>";
for (long c=0; c<C; c++) {
const double val=matrix[jkqtplinalgMatIndex(l,c,C)];
std::string cols="";
if (colorcoding) {
double valrel=0;
uint8_t r=255,g=255,b=255;
if (zeroIsWhite){
if (val<0) valrel=-1.0*fabs(val/minv);
if (val>0) valrel=fabs(val/maxv);
} else {
valrel=((val-minv)/(maxv-minv)-0.5)*2.0;
}
if (nonlinColors) {
jkqtplinalgPM1ToNonlinRWBColors(valrel, r,g,b, nonlinColorsGamma);
} else {
jkqtplinalgPM1ToRWBColors(valrel, r,g,b);
}
char buf[500];
sprintf(buf, " bgcolor=\"#%02X%02X%02X\"", int(r), int(g), int(b));
cols=buf;
}
ost<<"<td align=\"center\" valign=\"middle\" width=\""<<(100.0/double(C))<<"%\" "<<cols<<"><nobr>";
ost.precision(precision);
ost.width(width);
char buf[500];
sprintf(buf, format.c_str(), val);
ost<<prenumber<<buf<<postnumber;
ost<<"</nobr></td>";
}
ost<<"</tr>\n";
}
ost<<"</table>";
if (colorcoding && colorlabel) {
char buf[8192];
uint8_t rm=255,gm=255,bm=255;
uint8_t rmc=255,gmc=255,bmc=255;
uint8_t rc=255,gc=255,bc=255;
uint8_t rcp=255,gcp=255,bcp=255;
uint8_t rp=255,gp=255,bp=255;
double vm=minv;
double vc=0;
double vp=maxv;
if (!zeroIsWhite) {
vc=(maxv+minv)/2.0;
}
if (nonlinColors) {
jkqtplinalgPM1ToNonlinRWBColors(-1, rm, gm, bm, nonlinColorsGamma);
jkqtplinalgPM1ToNonlinRWBColors(-0.5, rmc, gmc, bmc, nonlinColorsGamma);
jkqtplinalgPM1ToNonlinRWBColors(0, rc, gc, bc, nonlinColorsGamma);
jkqtplinalgPM1ToNonlinRWBColors(0.5, rcp, gcp, bcp, nonlinColorsGamma);
jkqtplinalgPM1ToNonlinRWBColors(1, rp, gp, bp, nonlinColorsGamma);
} else {
jkqtplinalgPM1ToRWBColors(-1, rm, gm, bm);
jkqtplinalgPM1ToRWBColors(-0.5, rmc, gmc, bmc);
jkqtplinalgPM1ToRWBColors(0, rc, gc, bc);
jkqtplinalgPM1ToRWBColors(0.5, rcp, gcp, bcp);
jkqtplinalgPM1ToRWBColors(1, rp, gp, bp);
}
sprintf(buf, "<table %s cellpadding=\"2\" cellspacing=\"0\" border=\"1\"><tr><td><table width=\"100%%\" cellpadding=\"3\" cellspacing=\"0\" border=\"0\"><tr>"
"<td bgcolor=\"#%02X%02X%02X\" width=\"20%%\"><nobr>&nbsp;%9.3lg&nbsp;</nobr></td>"
"<td bgcolor=\"#%02X%02X%02X\" width=\"20%%\"><nobr>&nbsp;&nbsp;&nbsp;&mdash;&nbsp;&nbsp;&nbsp;</nobr></td>"
"<td bgcolor=\"#%02X%02X%02X\" width=\"20%%\"><nobr>&nbsp;%9.3lg&nbsp;</nobr></td>"
"<td bgcolor=\"#%02X%02X%02X\" width=\"20%%\"><nobr>&nbsp;&nbsp;&nbsp;&mdash;&nbsp;&nbsp;&nbsp;</nobr></td>"
"<td bgcolor=\"#%02X%02X%02X\" width=\"20%%\"><nobr>&nbsp;%9.3lg&nbsp;</nobr></td>"
"</tr></table></td></tr></table>", colortableformat.c_str(), int(rm), int(gm), int(bm), vm, int(rmc), int(gmc), int(bmc), int(rc), int(gc), int(bc), vc, int(rcp), int(gcp), int(bcp), int(rp), int(gp), int(bp), vp);
(*colorlabel)=std::string(buf);
}
return ost.str();
}
/** \brief dot-product between two vectors \a vec1 and \a vec2, each with a length of \a N entries
* \ingroup jkqtptools_math_linalg
*
* \tparam T of the vector cells (typically double or float)
* \param vec1 first vector
* \param vec2 second vector
* \param N number of entries in \a vec1 and \a vec2
*/
template <class T>
inline T jkqtplinalgDotProduct(const T* vec1, const T* vec2, long N) {
T res=0;
for (long l=0; l<N; l++) {
res=res+vec1[l]*vec2[l];
}
return res;
}
/** \brief transpose the given NxN matrix
* \ingroup jkqtptools_math_linalg
*
* \tparam T of the matrix cells (typically double or float)
* \param matrix the matrix to transpose
* \param N number of rows and columns in the matrix
*
*/
template <class T>
inline void jkqtplinalgTransposeMatrix(T* matrix, long N) {
for (long l=0; l<N; l++) {
for (long c=l+1; c<N; c++) {
jkqtpArraySwap(matrix, jkqtplinalgMatIndex(l,c,N), jkqtplinalgMatIndex(c,l,N));
}
}
}
/** \brief transpose the given LxC matrix
* \ingroup jkqtptools_math_linalg
*
* \tparam T of the matrix cells (typically double or float)
* \param matrix the matrix to transpose
* \param L number of rows in the matrix
* \param C number of columns in the matrix
*
* \note The output is interpreted as CxL matrix!!!
*/
template <class T>
inline void jkqtplinalgTransposeMatrix(T* matrix, long L, long C) {
JKQTPArrayScopedPointer<T> t(jkqtpArrayDuplicate<T>(matrix, L*C));
for (long l=0; l<L; l++) {
for (long c=0; c<C; c++) {
matrix[jkqtplinalgMatIndex(c,l,L)]=t[jkqtplinalgMatIndex(l,c,C)];
}
}
}
/** \brief swap two lines in a matrix
* \ingroup jkqtptools_math_linalg
*
* \tparam T of the matrix cells (typically double or float)
* \param m the matrix to work on
* \param l1 the row to swap with row \a l2
* \param l2 the row to swap with row \a l1
* \param C number of columns in the matrix
*/
template <class T>
inline void jkqtplinalgMatrixSwapLines(T* m, long l1, long l2, long C) {
for (long c=0; c<C; c++) {
jkqtpArraySwap(m, jkqtplinalgMatIndex(l1, c, C), jkqtplinalgMatIndex(l2, c, C));
}
}
/*! \brief matrix-matrix product
\ingroup jkqtptools_math_linalg
\tparam T of the matrix cells (typically double or float)
\param M1 matrix 1, size: L1xC1
\param L1 number of rows in the matrix \a M1
\param C1 number of columns in the matrix \a M1
\param M2 matrix 1, size: L2xC2
\param L2 number of rows in the matrix \a M2
\param C2 number of columns in the matrix \a M2
\param[out] M output matrix M=M1*M2, size: L1xC2
*/
template <class T>
inline void jkqtplinalgMatrixProduct(const T* M1, long L1, long C1, const T* M2, long L2, long C2, T* M) {
if (M1!=M &&M2!=M) {
for (long l=0; l<L1; l++) {
for (long c=0; c<C2; c++) {
double s=T(0);
for (long i=0; i<C1; i++) {
s = s + M1[jkqtplinalgMatIndex(l, i, C1)]*M2[jkqtplinalgMatIndex(i,c, C2)];
}
M[jkqtplinalgMatIndex(l, c, C2)]=s;
}
}
} else if (M1==M && M2!=M) {
JKQTPArrayScopedPointer<T> MM(jkqtpArrayDuplicate(M1, L1*C1));
jkqtplinalgMatrixProduct(MM,L1,C1,M2,L2,C2,M);
} else if (M1!=M && M2==M) {
JKQTPArrayScopedPointer<T> MM(jkqtpArrayDuplicate(M1, L1*C1));
jkqtplinalgMatrixProduct(M1,L1,C1,MM,L2,C2,M);
} else if (M1==M && M2==M) {
JKQTPArrayScopedPointer<T> MM(jkqtpArrayDuplicate(M1, L1*C1));
jkqtplinalgMatrixProduct(MM,L1,C1,MM,L2,C2,M);
}
}
/*! \brief matrix-matrix product of two NxN matrices
\ingroup jkqtptools_math_linalg
\param M1 matrix 1, size: NxN
\param M2 matrix 1, size: NxN
\param N number os rows/columns in the matrices \a M1, \a M2 and \a M
\param[out] M output matrix M=M1*M2, size: NxN
*/
template <class T>
inline void jkqtplinalgMatrixProduct(const T* M1, const T* M2, long N, T* M) {
jkqtplinalgMatrixProduct(M1,N,N,M2,N,N,M);
}
/*! \brief performs a Gauss-Jordan eliminaion on a LxC matrix m
\ingroup jkqtptools_math_linalg
For a matrix equation \f[ A\cdot\vec{x}=\vec{b} \f] the input matrix is \f[ \left[A | \vec{b}\right] \f] for matrix inversion it is
\f[ \left[A | I_L\right] \f] where \f$ I_L \f$ is the unit matrix with LxL entries.
\tparam T of the matrix cells (typically double or float)
\param m the matrix
\param L number of rows in the matrix
\param C number of columns in the matrix
\see http://www.virtual-maxim.de/matrix-invertieren-in-c-plus-plus/
*/
template <class T>
inline bool jkqtplinalgGaussJordan(T* m, long L, long C) {
const long N=L;
//std::cout<<"\nstep 0:\n";
//linalgPrintMatrix(m, N, C);
// first we perform a Gauss-elimination, which transforms the matrix in the left half of m into upper triangular form
for (long k=0; k<N-1; k++) {
//std::cout<<"\nstep G"<<k<<": pivot="<<m[jkqtpstatisticsMatIndex(k,k,C)]<<"\n";
if (m[jkqtplinalgMatIndex(k,k,C)]==0.0) {
// if pivot(m[k,k])==0, then swap this line with a line, which does not have a 0 in the k-th column
for (long ks=k+1; ks<N; ks++) {
if (m[jkqtplinalgMatIndex(ks,k,C)]!=0.0) {
jkqtplinalgMatrixSwapLines(m, ks, k, C);
break;
} else if (ks==N-1) {
// if no such element is found, the matrix may not be inverted!
return false;
}
}
}
// now we can eliminate all entries i below the pivot line p, by subtracting
// the pivot line, scaled by s, from every line, where
// s=m[i,p]/m[p,p]
for (long i=k+1; i<N; i++) {
const T s=m[jkqtplinalgMatIndex(i,k,C)]/m[jkqtplinalgMatIndex(k,k,C)];
for (long c=k; c<C; c++) {
m[jkqtplinalgMatIndex(i,c,C)] -= m[jkqtplinalgMatIndex(k,c,C)]*s;
}
}
//linalgPrintMatrix(m, N, C);
}
// now we can caluate the determinant of the left half-matrix, which can be used to determine, whether matrix
// is invertible at all: if det(T)==0.0 -> matrix is not invertible
// the determinant of an upper triangular marix equals the product of the diagonal elements
T det=1.0;
for (long k=0; k<N; k++) {
det = det * m[jkqtplinalgMatIndex(k,k,C)];
}
//linalgPrintMatrix(m, N, C);
//std::cout<<"\nstep 2: det(M)="<<det<<"\n";
if (fabs(det)<DBL_MIN*10.0) return false;
// if the matrix may be inverted, we can go on with the JOrdan part of the algorithm:
// we work the Nx(2N) matrix from bottom to top and transform the left side into a unit matrix
// - the last row is left unchanged
// - the last row is subtracted from every row i above, scaled by m[i,N]/m[N,N]
// then we repeat this for the (N-1)*(N-1) left upper matrix, which has again full triangular form
for (long k=N-1; k>0; k--) {
//std::cout<<"\nstep J"<<k<<":\n";
for (long i=k-1; i>=0; i--) {
const T s=m[jkqtplinalgMatIndex(i,k,C)]/m[jkqtplinalgMatIndex(k,k,C)];
for (long c=k; c<C; c++) {
m[jkqtplinalgMatIndex(i,c,C)] -= m[jkqtplinalgMatIndex(k,c,C)]*s;
}
}
//linalgPrintMatrix(m, N, C);
}
// finally each line is normalized to 1 by dividing by the diagonal entry in the left NxN matrix
// and copy the result to matrix_out
for (long k=0; k<N; k++) {
const T s=m[jkqtplinalgMatIndex(k,k,C)];
for (long c=N; c<C; c++) {
m[jkqtplinalgMatIndex(k,c,C)] = m[jkqtplinalgMatIndex(k,c,C)] / s;
}
m[jkqtplinalgMatIndex(k,k,C)]=T(1);
}
return true;
}
/*! \brief invert the given NxN matrix using Gauss-Jordan elimination
\ingroup jkqtptools_math_linalg
\tparam T of the matrix cells (typically double or float)
\param matrix the matrix to invert
\param[out] matrix_out target for the inverted matrix
\param N number of rows and columns in the matrix
\return \c true on success and the inverted matrix in matrix_out.
\note It is save to call \c jkqtpstatMatrixInversion(A,A,N) with the same argument for in and out matrix. Then the input will be overwritten with the new matrix!
\note matrix and matrix_out have to be of size N*N. Matrices are interpreted as row-major!
\see http://www.virtual-maxim.de/matrix-invertieren-in-c-plus-plus/
*/
template <class T>
inline bool jkqtplinalgMatrixInversion(const T* matrix, T* matrix_out, long N) {
#ifdef JKQTP_STATISTICS_TOOLS_MAY_USE_EIGEN3
if (N==2) {
Eigen::Map<const Eigen::Matrix<T,2,2,Eigen::RowMajor> > eA(matrix);
Eigen::Map<Eigen::Matrix<T,2,2,Eigen::RowMajor> > eO(matrix_out);
eO=eA.inverse();
//std::cout<<"\n--------------------------------------\n2x2 input matrix\n"<<eA<<"\n--------------------------------------\n";
return eO.allFinite();
} else if (N==3) {
Eigen::Map<const Eigen::Matrix<T,3,3,Eigen::RowMajor> > eA(matrix);
Eigen::Map<Eigen::Matrix<T,3,3,Eigen::RowMajor> > eO(matrix_out);
//std::cout<<"\n--------------------------------------\n3x3 input matrix\n"<<eA<<"\n--------------------------------------\n";
eO=eA.inverse();
return eO.allFinite();
} else if (N==4) {
Eigen::Map<const Eigen::Matrix<T,4,4,Eigen::RowMajor> > eA(matrix);
Eigen::Map<Eigen::Matrix<T,4,4,Eigen::RowMajor> > eO(matrix_out);
//std::cout<<"\n--------------------------------------\n4x4 input matrix\n"<<eA<<"\n--------------------------------------\n";
eO=eA.inverse();
return eO.allFinite();
} else {
Eigen::Map<const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> > eA(matrix,N,N);
Eigen::Map<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> > eO(matrix_out,N,N);
eO=eA.inverse();
//std::cout<<"\n--------------------------------------\nNxN input matrix\n"<<eA<<"\n--------------------------------------\n";
return eO.allFinite();
}
return true;
#else
// first build a N*(2N) matrix of the form
//
// m11 m12 ... | 1 0 0
// m21 m22 ... | 0 1 0
// ... ... ... | .....
//
const long msize=N*N*2;
std::vector<T> m;
m.resize(msize);
for (long i=0; i<msize; i++) m[i]=T(0); // init with 0
for (long l=0; l<N; l++) {
for (long c=0; c<N; c++) { // init left half with matrix
m[jkqtplinalgMatIndex(l,c,2*N)]=matrix[jkqtplinalgMatIndex(l,c,N)];
}
// init right half with unit matrix
m[jkqtplinalgMatIndex(l,N+l,2*N)]=T(1);
}
bool ok=linalgGaussJordanV(m, N, 2*N);
if (ok) {
// finally we copy the result to matrix_out
for (long k=0; k<N; k++) {
for (long c=N; c<2*N; c++) {
matrix_out[jkqtplinalgMatIndex(k,c-N,N)] = m[jkqtplinalgMatIndex(k,c,2*N)];
}
}
}
return ok;
#endif
}
/*! \brief invert the given NxN matrix using Gauss-Jordan elimination
\ingroup jkqtptools_math_linalg
\tparam T of the matrix cells (typically double or float)
\param[in,out] matrix the matrix to invert (at the same time the target)
\param N number of rows and columns in the matrix
*/
template <class T>
inline bool jkqtplinalgMatrixInversion(T* matrix, long N) {
return jkqtplinalgMatrixInversion(matrix, matrix, N);
}
/*! \brief solve a system of N linear equations \f$ A\cdot\vec{x}=B \f$ simultaneously for C columns in B
\ingroup jkqtptools_math_linalg
\param A an NxN matrix of coefficients
\param B an NxC marix
\param N number of equations
\param C number of columns in B
\param result_out a NxC matrix with the results after the inversion of the system of equations
\return \c true on success
\note This function uses the Gauss-Jordan algorithm
\note It is save to call \c jkqtpstatLinSolve(A,B,N,C,B) with the same argument for B and result_out. Then the input will be overwritten with the new matrix!
*/
template <class T>
inline bool jkqtplinalgLinSolve(const T* A, const T* B, long N, long C, T* result_out) {
#if defined(JKQTP_STATISTICS_TOOLS_MAY_USE_EIGEN3) && (!defined(STATISTICS_TOOLS_linalgLinSolve_EIGENMETHOD_noeigen))
if (N==2 && C==1) {
Eigen::Map<const Eigen::Matrix<T,2,2,Eigen::RowMajor> > eA(A);
Eigen::Matrix<T,2,1> eB;
Eigen::Map<Eigen::Matrix<T,2,1> > x(result_out);
eB=Eigen::Map<const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> >(B,2,1);
# ifdef STATISTICS_TOOLS_linalgLinSolve_EIGENMETHOD_fullPivLu
x=eA.fullPivLu().solve(eB);
# elif defined(STATISTICS_TOOLS_linalgLinSolve_EIGENMETHOD_householderQr)
x=eA.householderQr().solve(eB);
# elif defined(STATISTICS_TOOLS_linalgLinSolve_EIGENMETHOD_fullPivHouseholderQr)
x=eA.fullPivHouseholderQr().solve(eB);
# elif defined(STATISTICS_TOOLS_linalgLinSolve_EIGENMETHOD_jacobiSvd)
x=eA.jacobiSVD().solve(eB);
# elif defined(STATISTICS_TOOLS_linalgLinSolve_EIGENMETHOD_colPivHouseholderQr)
x=eA.colPivHouseholderQr().solve(eB);
# else
x=eA.fullPivLu().solve(eB);
# endif
} else if (N==3 && C==1) {
Eigen::Map<const Eigen::Matrix<T,3,3,Eigen::RowMajor> > eA(A);
Eigen::Matrix<T,3,1> eB;
Eigen::Map<Eigen::Matrix<T,3,1> > x(result_out);
eB=Eigen::Map<const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> >(B,3,1);
# ifdef STATISTICS_TOOLS_linalgLinSolve_EIGENMETHOD_fullPivLu
x=eA.fullPivLu().solve(eB);
# elif defined(STATISTICS_TOOLS_linalgLinSolve_EIGENMETHOD_householderQr)
x=eA.householderQr().solve(eB);
# elif defined(STATISTICS_TOOLS_linalgLinSolve_EIGENMETHOD_fullPivHouseholderQr)
x=eA.fullPivHouseholderQr().solve(eB);
# elif defined(STATISTICS_TOOLS_linalgLinSolve_EIGENMETHOD_jacobiSvd)
x=eA.jacobiSVD().solve(eB);
# elif defined(STATISTICS_TOOLS_linalgLinSolve_EIGENMETHOD_colPivHouseholderQr)
x=eA.colPivHouseholderQr().solve(eB);
# else
x=eA.fullPivLu().solve(eB);
# endif
} else {
Eigen::Map<const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> > eA(A,N,N);
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> eB(N,C);
Eigen::Map<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> > x(result_out,N,C);
eB=Eigen::Map<const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> >(B,N,C);
# ifdef STATISTICS_TOOLS_linalgLinSolve_EIGENMETHOD_fullPivLu
x=eA.fullPivLu().solve(eB);
# elif defined(STATISTICS_TOOLS_linalgLinSolve_EIGENMETHOD_householderQr)
x=eA.householderQr().solve(eB);
# elif defined(STATISTICS_TOOLS_linalgLinSolve_EIGENMETHOD_fullPivHouseholderQr)
x=eA.fullPivHouseholderQr().solve(eB);
# elif defined(STATISTICS_TOOLS_linalgLinSolve_EIGENMETHOD_jacobiSvd)
x=eA.jacobiSVD().solve(eB);
# elif defined(STATISTICS_TOOLS_linalgLinSolve_EIGENMETHOD_colPivHouseholderQr)
x=eA.colPivHouseholderQr().solve(eB);
# else
x=eA.fullPivLu().solve(eB);
# endif
}
return true;
#else
// first build a N*(N+C) matrix of the form
//
// <---- N ----> <---- C ---->
// ^ A11 A12 ... | B11 B12 ...
// | A21 A22 ... | B21 B22 ...
// N ... ... ... | .....
// | ... ... ... | .....
// v ... ... ... | .....
//
const long msize=N*(N+C);
JKQTPArrayScopedPointer<T> m(static_cast<T*>(jkqtpArrayMalloc(msize*sizeof(T)))); // use scoped pointer to ensure, that m is free'd, when the function is ending
for (long l=0; l<N; l++) {
for (long c=0; c<N; c++) { // init left half with matrix A
m[jkqtplinalgMatIndex(l,c,N+C)]=A[jkqtplinalgMatIndex(l,c,N)];
}
// init right half with B
for (long c=0; c<C; c++) { // init left half with matrix B
m[jkqtplinalgMatIndex(l,N+c,N+C)]=B[jkqtplinalgMatIndex(l,c,C)];
}
}
bool ok=linalgGaussJordan(m.data(), N, N+C);
if (ok) {
for (long k=0; k<N; k++) {
for (long c=N; c<(N+C); c++) {
if (!JKQTPIsOKFloat(m[jkqtplinalgMatIndex(k,c,N+C)])) {
ok=false;
break;
}
}
if (!ok) break;
}
if (ok) {
// finally we copy the result to matrix_out
for (long k=0; k<N; k++) {
for (long c=N; c<(N+C); c++) {
result_out[jkqtplinalgMatIndex(k,c-N,C)] = m[jkqtplinalgMatIndex(k,c,N+C)];
}
}
}
}
return ok;
#endif
}
/*! \brief solve a system of N linear equations \f$ A\cdot\vec{x}=B \f$ simultaneously for C columns in B
\ingroup jkqtptools_math_linalg
\param A an NxN matrix of coefficients
\param[in,out] B an NxC marix (also receives the result)
\param N number of equations
\param C number of columns in B
\return \c true on success
\note This function uses the Gauss-Jordan algorithm
\note It is save to call \c jkqtpstatLinSolve(A,B,N,C,B) with the same argument for B and result_out. Then the input will be overwritten with the new matrix!
*/
template <class T>
inline bool jkqtplinalgLinSolve(const T* A, T* B, long N, long C) {
return jkqtplinalgLinSolve(A,B,N,C,B);
}
/*! \brief solve a system of N linear equations \f$ A\cdot\vec{x}=\vec{b} \f$
\ingroup jkqtptools_math_linalg
\param A an NxN matrix of coefficients
\param b an N-entry vector
\param N number of equations
\param C number of columns in B
\param[out] result_out a N-entry vector with the result
\return \c true on success
\note This function uses the Gauss-Jordan algorithm
\note It is save to call \c jkqtpstatLinSolve(A,B,N,C,B) with the same argument for B and result_out. Then the input will be overwritten with the new matrix!
*/
template <class T>
inline bool jkqtplinalgLinSolve(const T* A, const T* b, long N, T* result_out) {
return jkqtplinalgLinSolve(A, b, N, 1, result_out);
}
/*! \brief solve a system of N linear equations \f$ A\cdot\vec{x}=\vec{b} \f$
\ingroup jkqtptools_math_linalg
\param A an NxN matrix of coefficients
\param[in,out] b an N-entry vector (also receives the result)
\param N number of equations
\param C number of columns in B
\return \c true on success
\note This function uses the Gauss-Jordan algorithm
\note It is save to call \c jkqtpstatLinSolve(A,B,N,C,B) with the same argument for B and result_out. Then the input will be overwritten with the new matrix!
*/
template <class T>
inline bool jkqtplinalgLinSolve(const T* A, T* b, long N) {
return jkqtplinalgLinSolve(A,b,N,1,b);
}
/*! \brief determinant the given NxN matrix
\ingroup jkqtptools_math_linalg
\tparam T of the matrix cells (typically double or float)
\param a the matrix for which to calculate the determinant
\param N number of rows and columns in the matrix
\return the determinant of \a a
\note for large matrices this algorithm is very slow, think about defining the macro JKQTP_STATISTICS_TOOLS_MAY_USE_EIGEN3 to use faster methods from the EIGEN library!
*/
template <class T>
inline T jkqtplinalgMatrixDeterminant(const T* a, long N) {
#ifdef JKQTP_STATISTICS_TOOLS_MAY_USE_EIGEN3
if (N < 1) { /* Error */
return NAN;
} else if (N == 1) { /* Shouldn't get used */
return a[jkqtplinalgMatIndex(0,0,N)];
} else if (N == 2) {
return a[jkqtplinalgMatIndex(0,0,N)] * a[jkqtplinalgMatIndex(1,1,N)] - a[jkqtplinalgMatIndex(1,0,N)] * a[jkqtplinalgMatIndex(0,1,N)];
} else if (N==3){
Eigen::Map<const Eigen::Matrix<T,3,3,Eigen::RowMajor> > eA(a);
return eA.determinant();
} else if (N==4){
Eigen::Map<const Eigen::Matrix<T,4,4,Eigen::RowMajor> > eA(a);
return eA.determinant();
} else {
Eigen::Map<const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> > eA(a,N,N);
return eA.determinant();
}
#else
long i,j,j1,j2;
T det = 0;
if (N < 1) { /* Error */
det=NAN;
} else if (N == 1) { /* Shouldn't get used */
det = a[jkqtplinalgMatIndex(0,0,N)];
} else if (N == 2) {
det = a[jkqtplinalgMatIndex(0,0,N)] * a[jkqtplinalgMatIndex(1,1,N)] - a[jkqtplinalgMatIndex(1,0,N)] * a[jkqtplinalgMatIndex(0,1,N)];
} else {
det = 0;
for (j1=0;j1<N;j1++) {
JKQTPArrayScopedPointer<T> m(static_cast<T*>(jkqtpArrayCalloc((N-1)*(N-1),sizeof(T *))));
for (i=1;i<N;i++) {
j2 = 0;
for (j=0;j<N;j++) {
if (j != j1){
m[jkqtplinalgMatIndex(i-1,j2,N-1)] = a[jkqtplinalgMatIndex(i,j,N)];
j2++;
}
}
}
//printf("%d: %lf (%lf %lf)\n",j1,pow(-1.0,1.0+double(j1)+1.0),a[jkqtplinalgMatIndex(0,j1,N)], jkqtplinalgMatrixDeterminant(m,N-1));
det = det + double(((1+j1+1)%2==0)?1.0:-1.0)/* pow(-1.0,1.0+double(j1)+1.0)*/ * a[jkqtplinalgMatIndex(0,j1,N)] * jkqtplinalgMatrixDeterminant(m,N-1);
}
}
//printf("\n\n jkqtplinalgMatrixDeterminant(%d):\n",N);
//linalgPrintMatrix(a,N,N);
//printf(" jkqtplinalgMatrixDeterminant(%d) = %lf\n", N, det);
return(det);
#endif
}
#endif // JKQTPLINALGTOOLS_H_INCLUDED

View File

@ -20,15 +20,10 @@
#define COMPILING_THIS_JKMATHPARSER
#include "jkqtplottertools/jkqtpmathparser.h" // class's header file
#include "jkqtcommon/jkqtpmathparser.h" // class's header file
#include <iostream>
#include <float.h>
#ifndef __WINDOWS__
# ifndef __LINUX__
# warning("these methods are ment to be used under windows or linux ... no other system were tested")
# endif
#endif
#include "jkqtcommon/jkqtpstringtools.h"
/* This just distinguishes between the different path formats on Windows and Unix:
* - on Windows you use a backslash '\' do separate directories
@ -603,6 +598,22 @@ namespace { // anonymous namespace to limit availability to this module (CPP-fil
}
void JKQTPMathParser::jkmpError(const std::string &st) {
if (jkmathparser_exception_function!=nullptr) {
jkmathparser_exception_function(st);
} else {
throw jkmpException(st);
}
}
void JKQTPMathParser::setException_function(JKQTPMathParser::jkmpexceptionf exception_function) {
jkmathparser_exception_function=exception_function;
}
void JKQTPMathParser::resetException_function() {
jkmathparser_exception_function=nullptr;
}
std::string JKQTPMathParser::tokentostring(JKQTPMathParser::jkmpTokenType token) {
switch(token) {
case END: return "END";
@ -678,7 +689,7 @@ std::string JKQTPMathParser::currenttokentostring() {
/******************************************************************************************
* jkMathParser
* JKQTPMathParser
******************************************************************************************/
// class constructor
@ -783,6 +794,16 @@ JKQTPMathParser::~JKQTPMathParser()
clearVariables();
}
void JKQTPMathParser::setData(void *__value)
{
this->data = __value;
}
void *JKQTPMathParser::getData() const
{
return this->data;
}
void JKQTPMathParser::addVariableDouble(const std::string& ni, double* v)
{
std::string name=strip(ni);
@ -903,6 +924,8 @@ void JKQTPMathParser::deleteVariable(const std::string& name) {
}
}
void JKQTPMathParser::clearFunctions() {functions.clear();}
void JKQTPMathParser::clearVariables(){
if (variables.size()>0) {
@ -987,6 +1010,18 @@ JKQTPMathParser::jkmpEvaluateFunc JKQTPMathParser::getFunctionDef(const std::str
return nullptr;
}
bool JKQTPMathParser::tempvariableExists(const std::string &name){
if (tempvariables.size()<=0) return false;
for (int i=tempvariables.size()-1; i>=0; i--) {
if (tempvariables[i].name==name) return true;
}
return false;
}
bool JKQTPMathParser::variableExists(const std::string &name){ return tempvariableExists(name)||(variables.find(name)!=variables.end()); }
bool JKQTPMathParser::functionExists(const std::string &name){ return !(functions.find(name)==functions.end()); }
void JKQTPMathParser::addTempVariable(const std::string& name, JKQTPMathParser::jkmpResult value) {
jkmpTempVariable v;
v.name=name;
@ -1312,7 +1347,7 @@ JKQTPMathParser::jkmpNode* JKQTPMathParser::primary(bool get){
}
case NAME: {
//jkMathParser::jkmpNode* def=nullptr;
//JKQTPMathParser::jkmpNode* def=nullptr;
std::string varname=StringValue;
getToken();
if (CurrentToken == ASSIGN) { // assign a variable name
@ -1412,7 +1447,7 @@ std::string JKQTPMathParser::readDelim(char delimiter){
while(program->get(ch)) {
if (ch==delimiter ) {
char ch1=program->peek();
const char ch1=static_cast<char>(program->peek());
if (ch1==delimiter) {
program->get(ch);
res=res+delimiter;
@ -1714,27 +1749,22 @@ JKQTPMathParser::jkmpResult JKQTPMathParser::jkmpBinaryBoolNode::evaluate(){
res.type=JKQTPMathParser::jkmpBool;
res.boolean=l.boolean&&r.boolean;
return res;
break;
case jkmpLOPor:
res.type=JKQTPMathParser::jkmpBool;
res.boolean=l.boolean||r.boolean;
return res;
break;
case jkmpLOPnor:
res.type=JKQTPMathParser::jkmpBool;
res.boolean=!(l.boolean||r.boolean);
return res;
break;
case jkmpLOPxor:
res.type=JKQTPMathParser::jkmpBool;
res.boolean=(l.boolean&& (!r.boolean))||(r.boolean&& (!l.boolean));
return res;
break;
case jkmpLOPnand:
res.type=JKQTPMathParser::jkmpBool;
res.boolean=!(l.boolean&&r.boolean);
return res;
break;
default: parser->jkmpError("unknown error");
}
res.isValid=false;
@ -1776,6 +1806,8 @@ JKQTPMathParser::jkmpResult JKQTPMathParser::jkmpNodeList::evaluate(){
return res;
}
int JKQTPMathParser::jkmpNodeList::getCount() {return list.size();}
JKQTPMathParser::jkmpNodeList::jkmpNodeList(JKQTPMathParser *p) { setParser(p); setParent(nullptr); }
JKQTPMathParser::jkmpNodeList::~jkmpNodeList() = default;
@ -1820,7 +1852,7 @@ JKQTPMathParser::jkmpResult JKQTPMathParser::jkmpFunctionNode::evaluate() {
data[i]=child[i]->evaluate();
}
}
// jkMathParser::jkmpResult r= getParser()->evaluateFunction(fun, data,n);
// JKQTPMathParser::jkmpResult r= getParser()->evaluateFunction(fun, data,n);
return function(data,n, parser);
}
@ -1848,6 +1880,24 @@ JKQTPMathParser::jkmpResult::jkmpResult()
boolean=false; /*!< \brief contains result if \c type==jkmpBool */
}
std::string JKQTPMathParser::jkmpResult::toString() {
switch(type) {
case jkmpDouble: return jkqtp_floattostr(num);
case jkmpString: return str;
case jkmpBool: return jkqtp_booltostr(boolean);
}
return "";
}
std::string JKQTPMathParser::jkmpResult::toTypeString() {
switch(type) {
case jkmpDouble: return jkqtp_floattostr(num)+" [number]";
case jkmpString: return str+" [string]";
case jkmpBool: return jkqtp_booltostr(boolean)+" [bool]";
}
return "";
}
JKQTPMathParser::jkmpVariable::jkmpVariable()
{
type=jkmpDouble; /*!< \brief type of the variable */
@ -1881,6 +1931,26 @@ JKQTPMathParser::jkmpResult JKQTPMathParser::jkmpConstantNode::evaluate() { retu
JKQTPMathParser::jkmpException::~jkmpException() = default;
JKQTPMathParser::jkmpException::jkmpException() {
errormessage="unknown error";
}
JKQTPMathParser::jkmpException::jkmpException(const std::string &msg) {
errormessage=msg;
}
std::string JKQTPMathParser::jkmpException::getMessage() const {
return errormessage;
}
const char *JKQTPMathParser::jkmpException::what() const noexcept {
return getMessage().c_str();
}
JKQTPMathParser *JKQTPMathParser::jkmpNode::getParser(){ return parser; }
void JKQTPMathParser::jkmpNode::setParser(JKQTPMathParser *mp){ parser=mp; }
JKQTPMathParser::jkmpNode *JKQTPMathParser::jkmpNode::getParent(){ return parent; }
void JKQTPMathParser::jkmpNode::setParent(JKQTPMathParser::jkmpNode *par) { parent=par; }

View File

@ -29,7 +29,7 @@
*/
/**
* \defgroup jkmpultil utilities for jkMathParser function parser class
* \defgroup jkmpultil utilities for JKQTPMathParser function parser class
* \ingroup jkmp
*/
@ -54,7 +54,6 @@
#include <ctype.h>
#include <list>
#include <utility>
#include "jkqtcommon/jkqtptools.h"
#ifndef JKQTPMATHPARSER_H
@ -84,7 +83,7 @@
memory is provided by the calling program. The parser supports a variable
assign operation \code a=<expression>\endcode which allows to define new
variables during evaluation. There are some mathematical standard constants
registered by calling jkMathParser::addStandardVariables():
registered by calling JKQTPMathParser::addStandardVariables():
- \c pi = \f$ \pi \f$
- \c e = \f$ \exp(1) \f$
- \c sqrt2 = \f$ \sqrt{2} \f$
@ -110,8 +109,8 @@
- \c kB = \f$ k_B=1.380650424\cdot 10^{-23}\;\mathrm{\frac{J}{K}} \f$ (Boltzman constant)
- \c kB_eV = \f$ k_B=8.61734315\cdot 10^{-5}\;\mathrm{\frac{eV}{K}} \f$ (Boltzman constant)
.
You can add user-defined contants by calling jkMathParser::addVariableDouble()
jkMathParser::addVariableBoolean() or jkMathParser::addVariableString()
You can add user-defined contants by calling JKQTPMathParser::addVariableDouble()
JKQTPMathParser::addVariableBoolean() or JKQTPMathParser::addVariableString()
\section jkmp_functions functions:
@ -135,11 +134,11 @@
- cmdparam, argv
.
these functions are registere by calling jkMathParser::addStandardFunctions().
you can add new functions by calling jkMathParser::addFunction();
these functions are registered by calling JKQTPMathParser::addStandardFunctions().
you can add new functions by calling JKQTPMathParser::addFunction();
\section jkmp_resultsofparsing result of parsing and evaluation:
The result of calling jkMathParser::parse()
The result of calling JKQTPMathParser::parse()
will be a tree-like structure in memory. The parse() function will return
a pointer to the root node of this structure. All nodes inherit from
jkmpNode class. To evaluate such a structure simply call jkmpNode::evaluate()
@ -189,7 +188,7 @@
\section jkmp_example Simple Example of Usage
\code
try {
jkMathParser mp; // instanciate
JKQTPMathParser mp; // instanciate
jkmpNode* n;
jkmpResult r;
// parse some numeric expression
@ -237,7 +236,7 @@
}
int main() {
jkMathParser mp;
JKQTPMathParser mp;
mp.setException_function(error); // make error ahndler known
...
}
@ -248,7 +247,7 @@ class JKQTPMathParser
protected:
void* data;
/** \brief the possible tokens that can be recognized by the tokenizer in jkMathParser::getToken()
/** \brief the possible tokens that can be recognized by the tokenizer in JKQTPMathParser::getToken()
* \ingroup jkmpultil
*/
enum jkmpTokenType {
@ -333,24 +332,10 @@ class JKQTPMathParser
bool boolean; /*!< \brief contains result if \c type==jkmpBool */
/** \brief convert the value this struct representens into a std::string */
inline std::string toString() {
switch(type) {
case jkmpDouble: return jkqtp_floattostr(num);
case jkmpString: return str;
case jkmpBool: return jkqtp_booltostr(boolean);
}
return "";
}
std::string toString();
/** \brief convert the value this struct representens into a std::string and adds the name of the datatype in \c [...] */
inline std::string toTypeString() {
switch(type) {
case jkmpDouble: return jkqtp_floattostr(num)+" [number]";
case jkmpString: return str+" [string]";
case jkmpBool: return jkqtp_booltostr(boolean)+" [bool]";
}
return "";
}
std::string toTypeString();
};
@ -386,7 +371,7 @@ class JKQTPMathParser
*
* If you want to add more math functions (like sin, cos , abs ...) to the
* parser, you will have to implement it with this prototype and then register
* it with jkMathParser::addFunction(). The first parameter points to an array
* it with JKQTPMathParser::addFunction(). The first parameter points to an array
* containing the input parameters while the second one specifies the number
* of supplied parameters. The result has to be of type jkmpResult.
*
@ -433,17 +418,17 @@ class JKQTPMathParser
/** \brief evaluate this node */
virtual jkmpResult evaluate()=0;
/** \brief return a pointer to the jkMathParser */
inline JKQTPMathParser* getParser(){ return parser; }
/** \brief return a pointer to the JKQTPMathParser */
JKQTPMathParser *getParser();
/** \brief set the jkMathParser */
inline void setParser(JKQTPMathParser* mp){ parser=mp; }
/** \brief set the JKQTPMathParser */
void setParser(JKQTPMathParser* mp);
/** \brief returns a pointer to the parent node */
inline jkmpNode* getParent(){ return parent; }
jkmpNode *getParent();
/** \brief sets the parent node */
inline void setParent(jkmpNode* par) { parent=par; }
void setParent(jkmpNode* par);
};
@ -461,7 +446,7 @@ class JKQTPMathParser
* \param op the operation to be performed: add (+), subtract (-), multiply (*), divide (/), a to the power of b (a^b)
* \param l left child node/operand
* \param r right child node/operand
* \param p a pointer to a jkMathParser object
* \param p a pointer to a JKQTPMathParser object
* \param par a pointer to the parent node
*/
jkmpBinaryArithmeticNode(char op, jkmpNode* l, jkmpNode* r, JKQTPMathParser* p, jkmpNode* par);
@ -486,7 +471,7 @@ class JKQTPMathParser
* \param op the operation to be performed: (a)nd, (o)r, (x)or, (n)or, nand (A)
* \param l left child node/operand
* \param r right child node/operand
* \param p a pointer to a jkMathParser object
* \param p a pointer to a JKQTPMathParser object
* \param par a pointer to the parent node
*/
jkmpBinaryBoolNode(char op, jkmpNode* l, jkmpNode* r, JKQTPMathParser* p, jkmpNode* par);
@ -511,7 +496,7 @@ class JKQTPMathParser
* \param op the operation to be performed: != (!), == (=), >= (b), <= (a), (>), (<)
* \param l left child node/operand
* \param r right child node/operand
* \param p a pointer to a jkMathParser object
* \param p a pointer to a JKQTPMathParser object
* \param par a pointer to the parent node
*/
jkmpCompareNode(char op, jkmpNode* l, jkmpNode* r, JKQTPMathParser* p, jkmpNode* par);
@ -535,7 +520,7 @@ class JKQTPMathParser
/** \brief constructor for a jkmpUnaryNode
* \param op the operation to be performed: (!), (-)
* \param c child node/operand
* \param p a pointer to a jkMathParser object
* \param p a pointer to a JKQTPMathParser object
* \param par a pointer to the parent node
*/
jkmpUnaryNode(char op, jkmpNode* c, JKQTPMathParser* p, jkmpNode* par);
@ -563,7 +548,7 @@ class JKQTPMathParser
/** \brief constructor for a jkmpVariableAssignNode
* \param var name of the variable to assign to
* \param c child node/right-hand-side expression
* \param p a pointer to a jkMathParser object
* \param p a pointer to a JKQTPMathParser object
* \param par a pointer to the parent node
*/
jkmpVariableAssignNode(const std::string& var, jkmpNode* c, JKQTPMathParser* p, jkmpNode* par);
@ -582,7 +567,7 @@ class JKQTPMathParser
public:
/** \brief constructor for a jkmpConstantNode
* \param d the value of the constant
* \param p a pointer to a jkMathParser object
* \param p a pointer to a JKQTPMathParser object
* \param par a pointer to the parent node
*/
jkmpConstantNode(jkmpResult d, JKQTPMathParser* p, jkmpNode* par);
@ -601,7 +586,7 @@ class JKQTPMathParser
public:
/** \brief constructor for a jkmpVariableNode
* \param name name of the variable
* \param p a pointer to a jkMathParser object
* \param p a pointer to a JKQTPMathParser object
* \param par a pointer to the parent node
*/
jkmpVariableNode(const std::string& name, JKQTPMathParser* p, jkmpNode* par);
@ -615,7 +600,7 @@ class JKQTPMathParser
* \ingroup jkmpNodes
*
* When initialized this class will get the function description that is
* linked to the supplied function name from jkMathParser object. This
* linked to the supplied function name from JKQTPMathParser object. This
* information is saved locally and won't be changed when evaluating!
*
* Functions may have 8 parameters at the most.
@ -631,7 +616,7 @@ class JKQTPMathParser
* \param name name of the function
* \param c a pointer to an array of jkmpNode objects that represent the parameter expressions
* \param num number of children in c
* \param p a pointer to a jkMathParser object
* \param p a pointer to a JKQTPMathParser object
* \param par a pointer to the parent node
*/
jkmpFunctionNode(const std::string& name, jkmpNode** c, unsigned char num, JKQTPMathParser* p, jkmpNode* par);
@ -654,7 +639,7 @@ class JKQTPMathParser
std::vector<jkmpNode*> list;
public:
/** \brief constructor for a jkmpNodeList
* \param p a pointer to a jkMathParser object
* \param p a pointer to a JKQTPMathParser object
*/
jkmpNodeList(JKQTPMathParser* p);
@ -668,7 +653,7 @@ class JKQTPMathParser
virtual jkmpResult evaluate() override;
/** \brief get the number of nodes in the list */
inline int getCount() {return list.size();};
int getCount();
};
/*@}*/
@ -694,25 +679,19 @@ class JKQTPMathParser
std::string errormessage;
public:
/** \brief class constructors */
inline jkmpException() {
errormessage="unknown error";
}
jkmpException();
/** \brief constructor with supplied error message */
inline jkmpException(const std::string& msg) {
errormessage=msg;
}
jkmpException(const std::string& msg);
/** \brief class destructors */
virtual ~jkmpException() override;
/** \brief returns the assigned errormessage */
inline std::string getMessage() const {
return errormessage;
}
std::string getMessage() const;
/** \brief returns the error description as C string */
virtual const char* what() const throw();
virtual const char* what() const noexcept override;
};
/** \brief type for a custom error handler. This an alternative error handling
@ -722,13 +701,7 @@ class JKQTPMathParser
/** \brief function that throws an exception or calls an error handler
* \ingroup jkmpErrorhandling */
inline void jkmpError(const std::string& st) {
if (jkmathparser_exception_function!=nullptr) {
jkmathparser_exception_function(st);
} else {
throw jkmpException(st);
}
}
void jkmpError(const std::string& st);
private:
/** \brief if this is nullptr then an exception may be thrown otherwise this should point to an error handler that will be called.
@ -738,15 +711,11 @@ class JKQTPMathParser
public:
/** \brief activate error handling by use of an exception function
* \ingroup jkmpErrorhandling */
inline void setException_function(jkmpexceptionf exception_function) {
jkmathparser_exception_function=exception_function;
}
void setException_function(jkmpexceptionf exception_function);
/** \brief deactivate error handling by use of an exception function
* \ingroup jkmpErrorhandling */
inline void resetException_function() {
jkmathparser_exception_function=nullptr;
}
void resetException_function();
protected:
@ -828,15 +797,9 @@ class JKQTPMathParser
virtual ~JKQTPMathParser();
/*! \copydoc data */
inline virtual void setData(void* __value)
{
this->data = __value;
}
virtual void setData(void* __value);
/*! \copydoc data */
inline virtual void* getData() const
{
return this->data;
}
virtual void* getData() const;
/** \brief register a new function
* \param name name of the new function
@ -909,19 +872,13 @@ class JKQTPMathParser
jkmpEvaluateFunc getFunctionDef(const std::string& name);
/** \brief tests whether a temporary variable exists */
inline bool tempvariableExists(const std::string& name){
if (tempvariables.size()<=0) return false;
for (int i=tempvariables.size()-1; i>=0; i--) {
if (tempvariables[i].name==name) return true;
}
return false;
}
bool tempvariableExists(const std::string& name);
/** \brief tests whether a variable exists */
inline bool variableExists(const std::string& name){ return tempvariableExists(name)||(variables.find(name)!=variables.end()); };
bool variableExists(const std::string& name);
/** \brief tests whether a function exists */
inline bool functionExists(const std::string& name){ return !(functions.find(name)==functions.end()); };
bool functionExists(const std::string& name);
/** \brief deletes all defined variables. the memory of internal variables
* will be released. the external memory will not be released.
@ -932,7 +889,7 @@ class JKQTPMathParser
void deleteVariable(const std::string& name);
/** \brief clears the list of internal functions*/
inline void clearFunctions() {functions.clear();}
void clearFunctions();
/** \brief registers standard variables*/
void addStandardVariables();

View File

@ -21,5 +21,7 @@ Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>)
#include "jkqtcommon/jkqtpcommonmathtools.h"
#include "jkqtcommon/jkqtpmathtools.h"
#include <cmath>

View File

@ -0,0 +1,258 @@
/*
Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>, <j.krieger@dkfz.de>)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef jkqtpmathtools_H_INCLUDED
#define jkqtpmathtools_H_INCLUDED
#include "jkqtcommon/jkqtp_imexport.h"
#include <cmath>
#include <QPoint>
#include <QPointF>
#include <vector>
/*! \brief \f$ \sqrt{2\pi}=2.50662827463 \f$
\ingroup jkqtptools_math_basic
*/
#define JKQTPSTATISTICS_SQRT_2PI 2.50662827463
/** \brief double-value NotANumber
* \ingroup jkqtptools_math_basic
*/
#define JKQTP_DOUBLE_NAN (std::numeric_limits<double>::signaling_NaN())
/** \brief float-value NotANumber
* \ingroup jkqtptools_math_basic
*/
#define JKQTP_FLOAT_NAN (std::numeric_limits<float>::signaling_NaN())
/** \brief double-value NotANumber
* \ingroup jkqtptools_math_basic
*/
#define JKQTP_NAN JKQTP_DOUBLE_NAN
/** \brief double-value epsilon
* \ingroup jkqtptools_math_basic
*/
#define JKQTP_DOUBLE_EPSILON (std::numeric_limits<double>::epsilon())
/** \brief float-value epsilon
* \ingroup jkqtptools_math_basic
*/
#define JKQTP_FLOAT_EPSILON (std::numeric_limits<float>::epsilon())
/** \brief double-value NotANumber
* \ingroup jkqtptools_math_basic
*/
#define JKQTP_EPSILON JKQTP_DOUBLE_EPSILON
/** \brief converts a boolean to a double, is used to convert boolean to double by JKQTPDatastore
* \ingroup jkqtptools_math_basic
*
* This function uses static_cast<double>() by default, but certain specializations (e.g. for bool) are
* readily available.
*
* \callergraph
*/
template<typename T>
inline constexpr double jkqtp_todouble(const T& d) {
return static_cast<double>(d);
}
/** \brief converts a boolean to a double, is used to convert boolean to double by JKQTPDatastore
* \ingroup jkqtptools_math_basic
*
* Specialisation of the generic template jkqtp_todouble() with (true -> 1.0, false -> 0.0)
*
* \callergraph
*/
template<>
inline constexpr double jkqtp_todouble(const bool& d) {
return static_cast<double>((d)?1.0:0.0);
}
/** \brief round a double \a v using round() and convert it to a specified type T (static_cast!)
* \ingroup jkqtptools_math_basic
*
* \tparam T a numeric datatype (int, double, ...)
* \param v the value to round and cast
*
* this is equivalent to
* \code
* static_cast<T>(round(v));
* \endcode
*
* \callergraph
*/
template<typename T>
inline T jkqtp_roundTo(const double& v) {
return static_cast<T>(round(v));
}
/** \brief round a double \a v using round() and convert it to a specified type T (static_cast!).
* Finally the value is bounded to the range \a min ... \a max
* \ingroup jkqtptools_math_basic
*
* \tparam T a numeric datatype (int, double, ...)
* \param min minimum output value
* \param v the value to round and cast
* \param max maximum output value
*
* this is equivalent to
* \code
* qBound(min, static_cast<T>(round(v)), max);
* \endcode
*/
template<typename T>
inline T jkqtp_boundedRoundTo(T min, const double& v, T max) {
return qBound(min, static_cast<T>(round(v)), max);
}
/** \brief round a double \a v using round() and convert it to a specified type T (static_cast!).
* Finally the value is bounded to the range \c std::numeric_limits<T>::min() ... \c std::numeric_limits<T>::max()
* \ingroup jkqtptools_math_basic
*
* \tparam T a numeric datatype (int, double, ...)
* \param v the value to round and cast
*
* this is equivalent to
* \code
* jkqtp_boundedRoundTo<T>(std::numeric_limits<T>::min(), v, std::numeric_limits<T>::max())
* \endcode
*/
template<typename T>
inline T jkqtp_boundedRoundTo(const double& v) {
return jkqtp_boundedRoundTo<T>(std::numeric_limits<T>::min(), v, std::numeric_limits<T>::max());
}
/** \brief bounds a value \a v to the given range \a min ... \a max
* \ingroup jkqtptools_math_basic
*
* \tparam T a numeric datatype (int, double, ...)
* \param min minimum output value
* \param v the value to round and cast
* \param max maximum output value
*/
template<typename T>
inline T jkqtp_bounded(T min, T v, T max) {
if (v<min) return min;
if (v>max) return max;
return v;
}
/** \brief compare two floats \a a and \a b for euqality, where any difference smaller than \a epsilon is seen as equality
* \ingroup jkqtptools_math_basic */
inline bool jkqtp_approximatelyEqual(float a, float b, float epsilon=2.0f*JKQTP_FLOAT_EPSILON)
{
return fabsf(a - b) <= epsilon;
}
/** \brief compare two doubles \a a and \a b for euqality, where any difference smaller than \a epsilon is seen as equality
* \ingroup jkqtptools_math_basic */
inline bool jkqtp_approximatelyEqual(double a, double b, double epsilon=2.0*JKQTP_DOUBLE_EPSILON)
{
return fabs(a - b) <= epsilon;
}
/** \brief returns the given value \a v (i.e. identity function)
* \ingroup jkqtptools_math_basic */
template<typename T>
inline T jkqtp_identity(const T& v) {
return v;
}
/** \brief returns the quare of the value \a v, i.e. \c v*v
* \ingroup jkqtptools_math_basic */
template<typename T>
inline T jkqtp_sqr(const T& v) {
return v*v;
}
/*! \brief 4-th power of a number
\ingroup jkqtptools_math_basic
*/
template <class T>
inline T jkqtp_pow4(T x) {
const T xx=x*x;
return xx*xx;
}
/*! \brief cube of a number
\ingroup jkqtptools_math_basic
*/
template <class T>
inline T jkqtp_cube(T x) {
return x*x*x;
}
/*! \brief calculates the sign of number \a x
\ingroup jkqtptools_math_basic
*/
template <class T>
inline T jkqtp_sign(T x) {
if (x<0) return -1;
//else if (x==0) return 0;
else return 1;
}
/** \brief calculate the distance between two QPointF points
* \ingroup jkqtptools_math_basic
*
*/
inline double jkqtp_distance(const QPointF& p1, const QPointF& p2){
return sqrt(jkqtp_sqr<double>(p1.x()-p2.x())+jkqtp_sqr<double>(p1.y()-p2.y()));
}
/** \brief calculate the distance between two QPoint points
* \ingroup jkqtptools_math_basic
*
*/
inline double jkqtp_distance(const QPoint& p1, const QPoint& p2){
return sqrt(jkqtp_sqr<double>(p1.x()-p2.x())+jkqtp_sqr<double>(p1.y()-p2.y()));
}
/** \brief check whether the dlotaing point number is OK (i.e. non-inf, non-NAN)
* \ingroup jkqtptools_math_basic
*/
template <typename T>
inline bool JKQTPIsOKFloat(T v) {
return std::isfinite(v)&&(!std::isinf(v))&&(!std::isnan(v));
}
/** \brief evaluates a gaussian propability density function
* \ingroup jkqtptools_math_basic
*
* \f[ f(x,\mu, \sigma)=\frac{1}{\sqrt{2\pi\sigma^2}}\cdot\exp\left(-\frac{(x-\mu)^2}{2\sigma^2}\right)
*/
inline double jkqtp_gaussdist(double x, double mu=0.0, double sigma=1.0) {
return exp(-0.5*jkqtp_sqr(x-mu)/jkqtp_sqr(sigma))/sqrt(2.0*M_PI*sigma*sigma);
}
#endif // jkqtpmathtools_H_INCLUDED

View File

@ -0,0 +1,106 @@
/*
Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>)
last modification: $LastChangedDate$ (revision $Rev$)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License (LGPL) as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License (LGPL) for more details.
You should have received a copy of the GNU Lesser General Public License (LGPL)
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "jkqtpstatisticstools.h"
double jkqtpstatKernel1DGaussian(double t) {
return exp(-0.5*t*t)/JKQTPSTATISTICS_SQRT_2PI;
}
double jkqtpstatKernel1DCauchy(double t) {
return 1.0/(M_PI*(1.0+t*t));
}
double jkqtpstatKernel1DPicard(double t) {
return exp(-0.5*fabs(t))/2.0;
}
double jkqtpstatKernel1DEpanechnikov(double t) {
return (fabs(t)<1.0)?(0.75*(1.0-t*t)):0.0;
}
double jkqtpstatKernel1DUniform(double t) {
return (fabs(t)<=1.0)?0.5:0.0;
}
double jkqtpstatKernel1DTriangle(double t) {
return (fabs(t)<=1.0)?(1.0-fabs(t)):0.0;
}
double jkqtpstatKernel1DQuartic(double t) {
return (fabs(t)<=1.0)?(15.0/16.0*jkqtp_sqr(1.0-t*t)):0.0;
}
double jkqtpstatKernel1DTriweight(double t) {
return (fabs(t)<1.0)?(35.0/32.0*jkqtp_cube(1.0-t*t)):0.0;
}
double jkqtpstatKernel1DTricube(double t) {
return (fabs(t)<1.0)?(70.0/81.0*jkqtp_cube(1.0-jkqtp_cube(fabs(t)))):0.0;
}
double jkqtpstatKernel1DCosine(double t) {
return (fabs(t)<1.0)?(M_PI/4.0*cos(t*M_PI/2.0)):0.0;
}
double jkqtpstatKernel2DGaussian(double tx, double ty)
{
return exp(-0.5*(tx*tx+ty*ty))/(2.0*M_PI);
}
double jkqtpstatKernel2DUniform(double tx, double ty) {
return (fabs(tx)<1.0 && fabs(ty)<=1.0)?0.25:0.0;
}
JKQTPStat5NumberStatistics::JKQTPStat5NumberStatistics():
minimum(JKQTP_DOUBLE_NAN),
minimumQuantile(0),
quantile1(JKQTP_DOUBLE_NAN),
quantile1Spec(0.25),
median(JKQTP_DOUBLE_NAN),
quantile2(JKQTP_DOUBLE_NAN),
quantile2Spec(0.75),
maximum(JKQTP_DOUBLE_NAN),
maximumQuantile(1),
N(0)
{}
double JKQTPStat5NumberStatistics::IQR() const {
return quantile2-quantile1;
}
double JKQTPStat5NumberStatistics::IQRSignificanceEstimate() const {
return 2.0*(1.58*(IQR()))/sqrt(static_cast<double>(N));
}

File diff suppressed because it is too large Load Diff

View File

@ -562,3 +562,18 @@ std::string jkqtp_chartostr(char data){
ost<<data;
return ost.str();
}
QString jkqtp_floattounitqstr(double data, int past_comma, bool remove_trail0)
{
return QString::fromStdString(jkqtp_floattounitstr(data, past_comma, remove_trail0));
}
QString jkqtp_floattolatexqstr(double data, int past_comma, bool remove_trail0, double belowIsZero, double minNoExponent, double maxNoExponent)
{
return QString::fromStdString(jkqtp_floattolatexstr(data, past_comma, remove_trail0, belowIsZero, minNoExponent, maxNoExponent));
}
QString jkqtp_floattohtmlqstr(double data, int past_comma, bool remove_trail0, double belowIsZero, double minNoExponent, double maxNoExponent)
{
return QString::fromStdString(jkqtp_floattohtmlstr(data, past_comma, remove_trail0, belowIsZero, minNoExponent, maxNoExponent));
}

View File

@ -168,6 +168,20 @@ JKQTP_LIB_EXPORT std::string jkqtp_floattolatexstr(double data, int past_comma=5
* \ingroup jkqtptools_string
*/
JKQTP_LIB_EXPORT std::string jkqtp_floattohtmlstr(double data, int past_comma=5, bool remove_trail0=false, double belowIsZero=1e-16, double minNoExponent=1e-3, double maxNoExponent=1e4);
/** \brief convert a double to a string, encoding powers of ten as characters, e.g. \c jkqtp_floattounitstr(1000) will result in "1k"
* \ingroup jkqtptools_string
*/
JKQTP_LIB_EXPORT QString jkqtp_floattounitqstr(double data, int past_comma=5, bool remove_trail0=false);
/** \brief convert a double to a string, encoding powers of ten as exponent in LaTeX notation (e.g. <code>-1.23\\cdot 10^{-5}</code>)
* \ingroup jkqtptools_string
*/
JKQTP_LIB_EXPORT QString jkqtp_floattolatexqstr(double data, int past_comma=5, bool remove_trail0=false, double belowIsZero=1e-16, double minNoExponent=1e-3, double maxNoExponent=1e4);
/** \brief convert a double to a string, encoding powers of ten as exponent with HTML tags
* \ingroup jkqtptools_string
*/
JKQTP_LIB_EXPORT QString jkqtp_floattohtmlqstr(double data, int past_comma=5, bool remove_trail0=false, double belowIsZero=1e-16, double minNoExponent=1e-3, double maxNoExponent=1e4);
/** \brief convert a character to a string
* \ingroup jkqtptools_string
*/

View File

@ -66,6 +66,100 @@ class JKQTP_LIB_EXPORT JKQTPAutoOutputTimer : public QElapsedTimer
};
/** \brief dynamic assertion, throws a \c std::runtime_error exception if \a condition is \c false
* \ingroup jkqtptools_debugging
*
* \param condition the condition to check
* \param message a user-provided error message
* \param expression the expression (as a string) that was used to calculate \a condition
* \param file filename where the exception occured
* \param line line in file \a file where the exception occured
*
* \see JKQTPASSERT_M(), JKQTPASSERT() for macros that use this function and automatically stringify the expression and add file and line
*/
inline void jkqtp_assert(bool condition, const std::string& message, const std::string expression, const std::string& file, int line)
{
if (!condition) {
throw std::runtime_error(message+" (expression: "+expression+", file: "+file+":"+std::to_string(line)+")");
}
}
/** \brief dynamic assertion, throws a \c std::runtime_error exception if \a condition is \c false
* \ingroup jkqtptools_debugging
*
* \param condition the condition to check
* \param message a user-provided error message
* \param expression the expression (as a string) that was used to calculate \a condition
* \param file filename where the exception occured
* \param line line in file \a file where the exception occured
* \param function calling function
*
* \see JKQTPASSERT_M(), JKQTPASSERT() for macros that use this function and automatically stringify the expression and add file and line
*/
inline void jkqtp_assert(bool condition, const std::string& message, const std::string expression, const std::string& file, int line, const std::string& function)
{
if (!condition) {
throw std::runtime_error(message+" (expression: "+expression+", function: "+function+", file: "+file+":"+std::to_string(line)+")");
}
}
/** \brief dynamic assertion, throws a \c std::runtime_error exception if \a condition is \c false
* \ingroup jkqtptools_debugging
*
* \param condition the condition to check
* \param expression the expression (as a string) that was used to calculate \a condition
* \param file filename where the exception occured
* \param line line in file \a file where the exception occured
* \param function calling function
*
* \see JKQTPASSERT_M(), JKQTPASSERT() for macros that use this function and automatically stringify the expression and add file and line
*/
inline void jkqtp_assert(bool condition, const std::string expression, const std::string& file, int line, const std::string& function)
{
if (!condition) {
throw std::runtime_error("assertion failed (expression: "+expression+", function: "+function+", file: "+file+":"+std::to_string(line)+")");
}
}
/** \brief dynamic assertion, throws a \c std::runtime_error exception if \a condition is \c false
* \ingroup jkqtptools_debugging
*
* \param condition the condition to check
* \param expression the expression (as a string) that was used to calculate \a condition
* \param file filename where the exception occured
* \param line line in file \a file where the exception occured
*
* \see JKQTPASSERT_M(), JKQTPASSERT() for macros that use this function and automatically stringify the expression and add file and line
*/
inline void jkqtp_assert(bool condition, const std::string expression, const std::string& file, int line)
{
if (!condition) {
throw std::runtime_error("assertion failed (expression: "+expression+", file: "+file+":"+std::to_string(line)+")");
}
}
/** \brief dynamic assertion, throws a \c std::runtime_error exception if \a condition is \c false
* \ingroup jkqtptools_debugging
*
* \param condition the condition to check
* \param message a user-provided error message
*
* \see JKQTPASSERT_M(), JKQTPASSERT()
*/
inline void jkqtp_assert(bool condition, const std::string& message)
{
if (!condition) {
throw std::runtime_error(message);
}
}
/** \brief dynamic assertion, throws an exception with the given \a message, when the given condition \a condition evaluates to \c false
* \ingroup jkqtptools_debugging
*/
#define JKQTPASSERT_M(condition, message) jkqtp_assert(condition, message, #condition, __FILE__, __LINE__, __FUNCTION__)
/** \brief dynamic assertion, throws an exception with the given \a message, when the given condition \a condition evaluates to \c false
* \ingroup jkqtptools_debugging
*/
#define JKQTPASSERT(condition) jkqtp_assert(condition, #condition, __FILE__, __LINE__, __FUNCTION__)
#endif // JKQTPDEBUGGINGTOOLS_H_INCLUDED

View File

@ -1,17 +1,18 @@
# uncomment this line to prevent linking in of the XITS fonts
#DEFINES += NO_XITS_FONTS
include($$PWD/common.pri)
isEmpty(JKQTP_FASTPLOTTER_PRI_INCLUDED) {
JKQTP_FASTPLOTTER_PRI_INCLUDED = 1
INCLUDEPATH += $PWD
HEADERS += $$PWD/jkqtfastplotter/jkqtfastplotter.h \
$$PWD/jkqtplottertools/jkqtphighrestimer.h
HEADERS += $$PWD/jkqtfastplotter/jkqtfastplotter.h
SOURCES += $$PWD/jkqtfastplotter/jkqtfastplotter.cpp \
$$PWD/jkqtplottertools/jkqtphighrestimer.cpp
SOURCES += $$PWD/jkqtfastplotter/jkqtfastplotter.cpp
RESOURCES += $$PWD/jkqtplotterressources/jkqtpbaseplotter.qrc
RESOURCES += $$PWD/jkqtplotterressources/jkqtpbaseplotter.qrc
QT += opengl
QT += opengl
}

View File

@ -20,7 +20,7 @@
#include "jkqtfastplotter.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include <QLocale>
#include <QPainter>
#include <QPaintEvent>
@ -47,7 +47,7 @@
var=(settings).value((group)+(varname), var).varconvert;
const double JKQTFastPlotter::ABS_MIN_LINEWIDTH=0.05;
const int JKQTFastPlotter::LUTSIZE=256;
const size_t JKQTFastPlotter::LUTSIZE=256;
JKQTFPPlot::JKQTFPPlot(JKQTFastPlotter* parent):
QObject(parent)
@ -1119,7 +1119,7 @@ void JKQTFPXRangePlot::drawGraph(QPainter& painter) {
painter.setPen(p);
painter.fillRect(r, b);
if (showCenterline) {
painter.drawLine(parent->x2p(centerline), parent->getInternalPlotBorderTop(), parent->x2p(centerline), parent->getInternalPlotBorderTop()+parent->getPlotHeight());
painter.drawLine(QLineF(parent->x2p(centerline), parent->getInternalPlotBorderTop(), parent->x2p(centerline), parent->getInternalPlotBorderTop()+parent->getPlotHeight()));
}
painter.drawRect(r);
}
@ -1276,7 +1276,7 @@ void JKQTFPimagePlot::drawGraph(QPainter& painter) {
painter.drawImage(QRectF(pxmin, pymax, dx, dy), img.transformed(trans));
if (drawColorBar && parent->getPlotHeight()>3) {
uint8_t d[200];
for (int i=0; i<200; i++) d[i]=i;
for (uint8_t i=0; i<200; i++) d[i]=i;
QImage b(1, 200, QImage::Format_ARGB32);
JKQTFPimagePlot_array2image<uint8_t>(d, 1, 200, b, palette, 0, 199);
//std::cout<<"bar.width="<<b.width()<<" bar.height="<<b.height()<<"\n";
@ -1428,7 +1428,7 @@ void JKQTFPQScaleBarXPlot::drawGraph(QPainter& painter) {
QRectF r(QPointF(parent->getInternalPlotBorderLeft(), parent->getInternalPlotBorderTop()), QPointF(parent->getInternalPlotBorderLeft()+parent->getPlotWidth(), parent->getInternalPlotBorderTop()+parent->getPlotHeight()));
double borderfraction=0.1;
int yDistance=static_cast<double>(parent->getPlotHeight())*borderfraction;
int yDistance=static_cast<int>(static_cast<double>(parent->getPlotHeight())*borderfraction);
QPen p(color);
p.setWidthF(qMax(JKQTFastPlotter::ABS_MIN_LINEWIDTH, lineWidth));
@ -1447,7 +1447,7 @@ void JKQTFPQScaleBarXPlot::drawGraph(QPainter& painter) {
painter.drawLine(QLineF(xx1, yy1, xx2, yy2));
painter.setFont(font);
QFontMetrics fm=painter.fontMetrics();
painter.drawText(xx1+(xx2-xx1)/2-fm.width(s)/2, yy1+3*lineWidth+fm.ascent(), s);
painter.drawText(static_cast<int>(xx1+(xx2-xx1)/2-fm.width(s)/2), static_cast<int>(yy1+3*lineWidth+fm.ascent()), s);
} else if (position==JKQTFPQScaleBarXPlot::TopLeft) {
yy1=parent->getInternalPlotBorderTop()+yDistance;
yy2=yy1;
@ -1458,7 +1458,7 @@ void JKQTFPQScaleBarXPlot::drawGraph(QPainter& painter) {
painter.drawLine(QLineF(xx1, yy1, xx2, yy2));
painter.setFont(font);
QFontMetrics fm=painter.fontMetrics();
painter.drawText(xx1+(xx2-xx1)/2-fm.width(s)/2, yy1+3*lineWidth+fm.ascent(), s);
painter.drawText(static_cast<int>(xx1+(xx2-xx1)/2-fm.width(s)/2), static_cast<int>(yy1+3*lineWidth+fm.ascent()), s);
} else if (position==JKQTFPQScaleBarXPlot::BottomLeft) {
yy1=parent->getInternalPlotBorderTop()+parent->getPlotHeight()-yDistance;
yy2=yy1;
@ -1469,7 +1469,7 @@ void JKQTFPQScaleBarXPlot::drawGraph(QPainter& painter) {
painter.drawLine(QLineF(xx1, yy1, xx2, yy2));
painter.setFont(font);
QFontMetrics fm=painter.fontMetrics();
painter.drawText(xx1+(xx2-xx1)/2-fm.width(s)/2, yy1-3*lineWidth-fm.descent(), s);
painter.drawText(static_cast<int>(xx1+(xx2-xx1)/2-fm.width(s)/2), static_cast<int>(yy1-3*lineWidth-fm.descent()), s);
} else if (position==JKQTFPQScaleBarXPlot::BottomRight) {
yy1=parent->getInternalPlotBorderTop()+parent->getPlotHeight()-yDistance;
yy2=yy1;
@ -1480,7 +1480,7 @@ void JKQTFPQScaleBarXPlot::drawGraph(QPainter& painter) {
painter.drawLine(QLineF(xx1, yy1, xx2, yy2));
painter.setFont(font);
QFontMetrics fm=painter.fontMetrics();
painter.drawText(xx1+(xx2-xx1)/2-fm.width(s)/2, yy1-3*lineWidth-fm.descent(), s);
painter.drawText(static_cast<int>(xx1+(xx2-xx1)/2-fm.width(s)/2), static_cast<int>(yy1-3*lineWidth-fm.descent()), s);
}

View File

@ -42,9 +42,8 @@
#include <QMutex>
#include <QGLWidget>
#include "jkqtcommon/jkqtptools.h"
#ifdef DEBUG_TIMING
# include "jkqtplottertools/jkqtphighrestimer.h"
# include "jkqtcommon/jkqtphighrestimer.h"
#endif
@ -100,7 +99,7 @@ class JKQTP_LIB_EXPORT JKQTFastPlotter : public QGLWidget {
/*! \brief size of the lookup tables used by JKQTFPimagePlot_array2image()
*/
static const int LUTSIZE;
static const size_t LUTSIZE;
protected:
/** \brief indicates whether to do full repaint (system and data) at the next repaint (any of the repaint meothods) */
@ -1907,7 +1906,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
(*plut)[l]=qRgb(static_cast<int>(255.0*v), 0, 0);
}
@ -1922,7 +1921,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
(*plut)[l]=qRgb(0, static_cast<int>(255.0*v), 0);
}
@ -1937,7 +1936,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
(*plut)[l]=qRgb(0, 0, static_cast<int>(255.0*v));
}
@ -1954,7 +1953,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
(*plut)[l]=qRgb(static_cast<int>(255.0*v),
static_cast<int>(255.0*v),
@ -1971,7 +1970,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
(*plut)[l]=qRgb(static_cast<int>(255.0*(1.0-v)), 0, 0);
}
@ -1986,7 +1985,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
(*plut)[l]=qRgb(0, static_cast<int>(255.0*(1.0-v)), 0);
}
@ -2000,7 +1999,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
(*plut)[l]=qRgb(0, 0, static_cast<int>(255.0*(1.0-v)));
}
@ -2014,7 +2013,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=1.0-(l/static_cast<double>(JKQTFastPlotter::LUTSIZE));
(*plut)[l]=qRgb(static_cast<int>(255.0*v),
static_cast<int>(255.0*v),
@ -2031,7 +2030,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
double r = 382.5 - 1020.0 * std::abs(v - 0.75);
if (r > 255.0)
@ -2064,7 +2063,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
double r = 796.875*v - 199.21875;
if (r > 255.0)
@ -2090,7 +2089,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
int h = static_cast<int>(floor(6*v));
double f = 6*v-double(h);
@ -2116,7 +2115,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
int h = static_cast<int>(floor(6.0-6.0*v));
double f = 6.0-6.0*v-double(h);
@ -2143,7 +2142,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
lut_rainbow=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
//std::cout<<"!!! creating rainbow lut\n";
if (lut_rainbow!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
double r = 255.0*std::abs(2.0*v-0.5);
if (r > 255.0)
@ -2165,7 +2164,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
double r = 765.0*v;
if (r > 255.0)
@ -2192,7 +2191,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
double r = 765.0*v-510.0;
if (r < 0.0)
@ -2213,7 +2212,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
double r = (v/0.32-0.78125);
if (r < 0.0) r = 0.0;
@ -2242,7 +2241,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
double r = sqrt(sqrt(v));
if (r < 0.0) r = 0.0;
@ -2269,7 +2268,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
double r = v*0.5;
if (r < 0.0) r = 0.0;
@ -2295,7 +2294,7 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
if ((*plut)==nullptr) {
(*plut)=static_cast<QRgb*>(malloc((JKQTFastPlotter::LUTSIZE+2)*sizeof(QRgb)));
if ((*plut)!=nullptr) {
for (int l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
for (size_t l=0; l<=JKQTFastPlotter::LUTSIZE; l++) {
double v=l/static_cast<double>(JKQTFastPlotter::LUTSIZE);
double r = (v < 0.5) ? 128.0*sin(M_PI*(2.0*v-0.5))+128.0 : 255.0;
if (r > 255.0)
@ -2323,8 +2322,8 @@ inline void JKQTFPimagePlot_array2image(T* dbl, int width, int height, QImage &i
for (int j=0; j<height; ++j) {
QRgb* line=reinterpret_cast<QRgb *>(img.scanLine(height-1-j));
for (int i=0; i<width; ++i) {
int v = (dbl[j*width+i]-min)/delta*JKQTFastPlotter::LUTSIZE;
v = (v < 0) ? 0 : ( (v > JKQTFastPlotter::LUTSIZE) ? JKQTFastPlotter::LUTSIZE : v);
int v = static_cast<int>((dbl[j*width+i]-min)/delta*static_cast<double>(JKQTFastPlotter::LUTSIZE));
v = (v < 0) ? 0 : ( (v > static_cast<int>(JKQTFastPlotter::LUTSIZE)) ? static_cast<int>(JKQTFastPlotter::LUTSIZE) : v);
line[i]=lut_used[v];
}
}
@ -2574,22 +2573,22 @@ class JKQTP_LIB_EXPORT JKQTFPimagePlot: public JKQTFPPlot {
public slots:
void setRotation(int rotation) {
if (this->rotation!=rotation) {
this->rotation=(JKQTFPColorPalette)rotation;
this->rotation=rotation;
replot();
}
}
void setPalette(int palette) {
if (this->palette!=palette) {
this->palette=(JKQTFPColorPalette)palette;
this->palette=static_cast<JKQTFPColorPalette>(palette);
replot();
}
};
}
void setPalette(JKQTFPColorPalette palette) {
if (this->palette!=palette) {
this->palette=palette;
replot();
}
};
}
void setColorMin(uint32_t colorMin) {
if (this->colorMin!=colorMin) {
this-> colorMin= colorMin;
@ -2633,17 +2632,19 @@ class JKQTP_LIB_EXPORT JKQTFPimagePlot: public JKQTFPPlot {
/*! \brief convert a 2D image (as 1D array) into a QImage and puts the image values into one color channel (set by \a channel).
\ingroup jkqtfastplotter
*/
template <class T>
inline void JKQTFPRGBImageOverlayPlot_array2image(T* dbl, int width, int height, QImage &img, int channel, T minColor, T maxColor)
inline void JKQTFPRGBImageOverlayPlot_array2image(T* dbl, int width, int height, QImage &img, int channel, double minColor_, double maxColor_)
{
if (!dbl)
return;
T minColor=static_cast<T>(minColor_);
T maxColor=static_cast<T>(maxColor_);
#ifdef DEBUG_TIMING
JKQTPHighResTimer timer;
double time_sum=0;
@ -2973,7 +2974,7 @@ class JKQTP_LIB_EXPORT JKQTFPRGBImageOverlayPlot: public JKQTFPPlot {
public slots:
inline void setRotation(int rotation) {
if (this->rotation!=rotation) {
this->rotation=(JKQTFPColorPalette)rotation;
this->rotation=rotation;
replot();
}
}
@ -3234,7 +3235,7 @@ class JKQTP_LIB_EXPORT JKQTFPimageOverlayPlot: public JKQTFPPlot {
public slots:
inline void setRotation(int rotation) {
if (this->rotation!=rotation) {
this->rotation=(JKQTFPColorPalette)rotation;
this->rotation=rotation;
replot();
}
}
@ -3243,7 +3244,7 @@ class JKQTP_LIB_EXPORT JKQTFPimageOverlayPlot: public JKQTFPPlot {
this->color=color;
replot();
}
};
}
};
@ -3365,7 +3366,7 @@ class JKQTP_LIB_EXPORT JKQTFPQScaleBarXPlot: public JKQTFPPlot {
}
public slots:
void setPosition(int pos) {
setPosition((Position)pos);
setPosition(static_cast<Position>(pos));
}
};

View File

@ -1,15 +1,17 @@
# uncomment this line to prevent linking in of the XITS fonts
#DEFINES += NO_XITS_FONTS
include($$PWD/common.pri)
isEmpty(JKQTP_MATHTEXT_PRI_INCLUDED) {
JKQTP_MATHTEXT_PRI_INCLUDED = 1
HEADERS += $$PWD/jkqtmathtext/jkqtmathtext.h
INCLUDEPATH += $PWD
SOURCES += $$PWD/jkqtmathtext/jkqtmathtext.cpp
HEADERS += $$PWD/jkqtmathtext/jkqtmathtext.h
SOURCES += $$PWD/jkqtmathtext/jkqtmathtext.cpp
include($$PWD/jkqtplotterressources/math_fonts/xits.pri)
DEFINES += AUTOLOAD_XITS_FONTS
include($$PWD/jkqtplotterressources/math_fonts/xits.pri)
DEFINES += AUTOLOAD_XITS_FONTS
DEFINES += USE_XITS_FONTS
#win32:LIBS += -lgdi32
#win32:LIBS += -lgdi32
}

View File

@ -20,7 +20,9 @@
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
#include <QFontDatabase>

View File

@ -36,7 +36,6 @@
#include <QString>
#include <QSet>
#include <QFile>
#include "jkqtcommon/jkqtptools.h"
#include "jkqtcommon/jkqtp_imexport.h"
#include <QWidget>
#include <QLabel>

56
lib/jkqtpcommon.pri Normal file
View File

@ -0,0 +1,56 @@
# include guard against multiple inclusion
isEmpty(JKQTP_COMMON_PRI_INCLUDED) {
JKQTP_COMMON_PRI_INCLUDED = 1
!win32-msvc* {
QMAKE_CXXFLAGS += -fexceptions
} else {
QMAKE_CXXFLAGS += /EHsc
# /std:c++14
# To enable M_PI, M_E,...
DEFINES += _USE_MATH_DEFINES
# To fix error: C2338: va_start argument must not
# have reference type and must not be parenthesized
DEFINES += _CRT_NO_VA_START_VALIDATION
}
HEADERS += $$PWD/jkqtcommon/jkqtp_imexport.h \
$$PWD/jkqtcommon/jkqtptoolsdebugging.h \
$$PWD/jkqtcommon/jkqtpmathtools.h \
$$PWD/jkqtcommon/jkqtpalgorithms.h \
$$PWD/jkqtcommon/jkqtpstringtools.h \
$$PWD/jkqtcommon/jkqtplinalgtools.h \
$$PWD/jkqtcommon/jkqtpcodestructuring.h \
$$PWD/jkqtcommon/jkqtpbasicimagetools.h \
$$PWD/jkqtcommon/jkqtpdrawingtools.h \
$$PWD/jkqtcommon/jkqtpenhancedpainter.h \
$$PWD/jkqtcommon/jkqtphighrestimer.h \
$$PWD/jkqtcommon/jkqtpmathparser.h \
$$PWD/jkqtcommon/jkqttools.h \
$$PWD/jkqtcommon/jkqtparraytools.h \
$$PWD/jkqtcommon/jkqtpstatisticstools.h
SOURCES += $$PWD/jkqtcommon/jkqtptoolsdebugging.cpp \
$$PWD/jkqtcommon/jkqtpmathtools.cpp \
$$PWD/jkqtcommon/jkqtpalgorithms.cpp \
$$PWD/jkqtcommon/jkqtpstringtools.cpp \
$$PWD/jkqtcommon/jkqtplinalgtools.cpp \
$$PWD/jkqtcommon/jkqtpcodestructuring.cpp \
$$PWD/jkqtcommon/jkqtpbasicimagetools.cpp \
$$PWD/jkqtcommon/jkqtpdrawingtools.cpp \
$$PWD/jkqtcommon/jkqtpenhancedpainter.cpp \
$$PWD/jkqtcommon/jkqtphighrestimer.cpp \
$$PWD/jkqtcommon/jkqtpmathparser.cpp \
$$PWD/jkqtcommon/jkqttools.cpp \
$$PWD/jkqtcommon/jkqtparraytools.cpp \
$$PWD/jkqtcommon/jkqtpstatisticstools.cpp
INCLUDEPATH += $$PWD
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
CONFIG += c++11
}

View File

@ -2,12 +2,15 @@
#DEFINES += NO_XITS_FONTS
include($$PWD/common.pri)
isEmpty(JKQTP_PLOTTER_PRI_INCLUDED) {
JKQTP_PLOTTER_PRI_INCLUDED = 1
INCLUDEPATH += $PWD
HEADERS += \
$$PWD/jkqtfastplotter/jkqtfastplotter.h \
$$PWD/jkqtmathtext/jkqtmathtext.h \
HEADERS += \
$$PWD/jkqtplotter/jkqtptools.h \
$$PWD/jkqtplotter/jkqtpbaseelements.h \
$$PWD/jkqtplotter/jkqtpbaseplotter.h \
$$PWD/jkqtplotter/jkqtpdatastorage.h \
@ -32,8 +35,10 @@ HEADERS += \
$$PWD/jkqtplotter/jkqtpgraphsimageoverlays.h \
$$PWD/jkqtplotter/jkqtpgraphscontour.h \
$$PWD/jkqtplotter/jkqtpgraphsimagergb.h \
$$PWD/jkqtplotter/jkqtpgraphsstatisticsadaptors.h \
$$PWD/jkqtplotter/jkqtplotter.h \
$$PWD/jkqtplotter/jkqtplotterstyle.h \
$$PWD/jkqtplotter/jkqtpkeystyle.h \
$$PWD/jkqtplotter/jkqtpbaseplotterstyle.h \
$$PWD/jkqtplotter/jkqtpcoordinateaxes.h \
$$PWD/jkqtplotter/jkqtpcoordinateaxesstyle.h \
@ -42,18 +47,12 @@ HEADERS += \
$$PWD/jkqtplottergui/jkqtpenhancedtableview.h \
$$PWD/jkqtplottergui/jkqtpgraphsmodel.h \
$$PWD/jkqtplottergui/jkvanishqtoolbar.h \
$$PWD/jkqtplottertools/jkqtpdrawingtools.h \
$$PWD/jkqtplottertools/jkqtpenhancedpainter.h \
$$PWD/jkqtplottertools/jkqtphighrestimer.h \
$$PWD/jkqtplottertools/jkqtpimagetools.h \
$$PWD/jkqtplottertools/jkqtpmathparser.h \
$$PWD/jkqtplottertools/jkqttools.h \
$$PWD/jkqtplotter/jkqtpkeystyle.h
$$PWD/jkqtplotter/jkqtpimagetools.h
SOURCES += \
$$PWD/jkqtfastplotter/jkqtfastplotter.cpp \
$$PWD/jkqtmathtext/jkqtmathtext.cpp \
SOURCES += \
$$PWD/jkqtplotter/jkqtptools.cpp \
$$PWD/jkqtplotter/jkqtpbaseelements.cpp \
$$PWD/jkqtplotter/jkqtpbaseplotter.cpp \
$$PWD/jkqtplotter/jkqtpdatastorage.cpp \
@ -78,8 +77,10 @@ SOURCES += \
$$PWD/jkqtplotter/jkqtpgraphsimageoverlays.cpp \
$$PWD/jkqtplotter/jkqtpgraphscontour.cpp \
$$PWD/jkqtplotter/jkqtpgraphsimagergb.cpp \
$$PWD/jkqtplotter/jkqtpgraphsstatisticsadaptors.cpp \
$$PWD/jkqtplotter/jkqtplotter.cpp \
$$PWD/jkqtplotter/jkqtplotterstyle.cpp \
$$PWD/jkqtplotter/jkqtpkeystyle.cpp \
$$PWD/jkqtplotter/jkqtpbaseplotterstyle.cpp \
$$PWD/jkqtplotter/jkqtpcoordinateaxes.cpp \
$$PWD/jkqtplotter/jkqtpcoordinateaxesstyle.cpp \
@ -88,20 +89,12 @@ SOURCES += \
$$PWD/jkqtplottergui/jkqtpenhancedtableview.cpp \
$$PWD/jkqtplottergui/jkqtpgraphsmodel.cpp \
$$PWD/jkqtplottergui/jkvanishqtoolbar.cpp \
$$PWD/jkqtplottertools/jkqtpdrawingtools.cpp \
$$PWD/jkqtplottertools/jkqtpenhancedpainter.cpp \
$$PWD/jkqtplottertools/jkqtphighrestimer.cpp \
$$PWD/jkqtplottertools/jkqtpimagetools.cpp \
$$PWD/jkqtplottertools/jkqtpmathparser.cpp \
$$PWD/jkqtplottertools/jkqttools.cpp \
$$PWD/jkqtplotter/jkqtpkeystyle.cpp
$$PWD/jkqtplotter/jkqtpimagetools.cpp
RESOURCES += $$PWD/jkqtplotterressources/jkqtpbaseplotter.qrc \
RESOURCES += $$PWD/jkqtplotterressources/jkqtpbaseplotter.qrc \
$$PWD/jkqtplotterressources/jkqtpstyles.qrc
QT += xml svg opengl
QT += xml svg opengl
include($$PWD/jkqtplotterressources/math_fonts/xits.pri)
DEFINES += AUTOLOAD_XITS_FONTS
DEFINES += USE_XITS_FONTS
}

View File

@ -532,7 +532,7 @@ void JKQTBasePlotter::propagateStyle() {
xAxis->setCurrentAxisStyle(plotterStyle.xAxisStyle);
yAxis->setCurrentAxisStyle(plotterStyle.yAxisStyle);
for (int i=0; i<graphs.size(); i++) {
JKQTPColorPaletteTools* palTools=dynamic_cast<JKQTPColorPaletteTools*>(graphs[i]);
JKQTPColorPaletteStyleAndToolsMixin* palTools=dynamic_cast<JKQTPColorPaletteStyleAndToolsMixin*>(graphs[i]);
if (palTools) {
palTools->getColorBarRightAxis()->setCurrentAxisStyle(plotterStyle.rightColorbarAxisStyle);
palTools->getColorBarTopAxis()->setCurrentAxisStyle(plotterStyle.topColorbarAxisStyle);

View File

@ -17,13 +17,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/jkqtpdatastorage.h"
#include "jkqtplotter/jkqtpbaseplotterstyle.h"
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplotter/jkqtpelementsoverlay.h"
#include "jkqtplottertools/jkqtpenhancedpainter.h"
#include "jkqtcommon/jkqtpenhancedpainter.h"
#include "jkqtplottergui/jkqtpenhancedspinboxes.h"
#include <QObject>

View File

@ -1,7 +1,7 @@
#include "jkqtpbaseplotterstyle.h"
#include <QPalette>
#include <QApplication>
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
JKQTBasePlotterStyle::JKQTBasePlotterStyle():
debugShowRegionBoxes(false),

View File

@ -20,11 +20,14 @@
#ifndef JKQTBASEPLOTTERSTYLE_H
#define JKQTBASEPLOTTERSTYLE_H
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/jkqtpimagetools.h"
#include "jkqtplotter/jkqtpcoordinateaxesstyle.h"
#include "jkqtplotter/jkqtpkeystyle.h"
#include "jkqtplottertools/jkqtpimagetools.h"
#include "jkqtplotter/jkqtpimagetools.h"
#include "jkqtcommon/jkqtp_imexport.h"
#include "jkqtcommon/jkqtpdrawingtools.h"
#include "jkqtcommon/jkqtpbasicimagetools.h"
#include <QColor>
#include <QPainter>
#include <QString>

View File

@ -19,7 +19,7 @@
#include "jkqtplotter/jkqtpcoordinateaxes.h"
#include "jkqtplotter/jkqtpbaseplotter.h"
#include "jkqtplottertools/jkqtpdrawingtools.h"
#include "jkqtcommon/jkqtpdrawingtools.h"
#include <QDebug>
#include <QDateTime>
#include <cfloat>

View File

@ -28,7 +28,7 @@
#include <QPainter>
#include <QPair>
#include <QSettings>
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtp_imexport.h"
#include "jkqtplotter/jkqtpcoordinateaxesstyle.h"

View File

@ -23,7 +23,7 @@
#include <QSettings>
#include <QString>
#include <QColor>
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtcommon/jkqtp_imexport.h"
class JKQTBasePlotterStyle; // forward

View File

@ -287,7 +287,8 @@ size_t JKQTPDatastore::addColumn(JKQTPColumn col) {
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPDatastore::JKQTPDatastore()
JKQTPDatastore::JKQTPDatastore():
m_invalidColumn(new JKQTPColumn)
{
maxItemID=0;
maxColumnsID=0;
@ -299,6 +300,114 @@ JKQTPDatastore::~JKQTPDatastore() {
clear();
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPDatastore::ColumnIterator JKQTPDatastore::begin()
{
return columns.begin();
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPDatastore::ColumnIterator JKQTPDatastore::end()
{
return columns.end();
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPDatastore::ConstColumnIterator JKQTPDatastore::begin() const
{
return columns.begin();
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPDatastore::ConstColumnIterator JKQTPDatastore::end() const
{
return columns.end();
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPColumnIterator JKQTPDatastore::begin(int i)
{
if (i<0) return m_invalidColumn->end();
auto it=columns.find(static_cast<size_t>(i));
if (it==columns.end()) return m_invalidColumn->end();
else return it->begin();
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPColumnIterator JKQTPDatastore::end(int i)
{
if (i<0) return m_invalidColumn->end();
auto it=columns.find(static_cast<size_t>(i));
if (it==columns.end()) return m_invalidColumn->end();
else return it->end();
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPColumnConstIterator JKQTPDatastore::begin(int i) const
{
if (i<0) return m_invalidColumn->end();
auto it=columns.find(static_cast<size_t>(i));
if (it==columns.end()) return m_invalidColumn->end();
else return it->begin();
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPColumnConstIterator JKQTPDatastore::end(int i) const
{
if (i<0) return m_invalidColumn->end();
auto it=columns.find(static_cast<size_t>(i));
if (it==columns.end()) return m_invalidColumn->end();
else return it->end();
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPColumnIterator JKQTPDatastore::begin(size_t i)
{
auto it=columns.find(i);
if (it==columns.end()) return m_invalidColumn->end();
else return it->begin();
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPColumnIterator JKQTPDatastore::end(size_t i)
{
auto it=columns.find(i);
if (it==columns.end()) return m_invalidColumn->end();
else return it->end();
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPColumnConstIterator JKQTPDatastore::begin(size_t i) const
{
auto it=columns.find(i);
if (it==columns.end()) return m_invalidColumn->end();
else return it->begin();
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPColumnConstIterator JKQTPDatastore::end(size_t i) const
{
auto it=columns.find(i);
if (it==columns.end()) return m_invalidColumn->end();
else return it->end();
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPColumnBackInserter JKQTPDatastore::backInserter(int i)
{
auto it=columns.find(i);
if (i<0 || it==columns.end()) return JKQTPColumnBackInserter(this, std::numeric_limits<size_t>::max());
else return JKQTPColumnBackInserter(this, static_cast<size_t>(i));
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPColumnBackInserter JKQTPDatastore::backInserter(size_t i)
{
auto it=columns.find(i);
if (it==columns.end()) return JKQTPColumnBackInserter(this, std::numeric_limits<size_t>::max());
else return JKQTPColumnBackInserter(this, static_cast<size_t>(i));
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPDatastore::clear(){
maxItemID=0;
@ -386,6 +495,15 @@ int JKQTPDatastore::getColumnNum(const QString& name) {
return -1;
}
////////////////////////////////////////////////////////////////////////////////////////////////
QString JKQTPDatastore::getColumnName(size_t column)
{
auto it=columns.find(column);
if (it==columns.end()) return "";
else return it->getName();
}
////////////////////////////////////////////////////////////////////////////////////////////////
int JKQTPDatastore::ensureColumnNum(const QString& name) {
if (columns.size()<=0) return -1;
@ -488,36 +606,28 @@ size_t JKQTPDatastore::addCopiedItem(const double* data, size_t rows) {
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPDatastore::addColumnForItem(size_t itemID, size_t columnInItem, const QString& name) {
/*JKQTPColumn c(this, name, itemID, columnInItem);
columns.push_back(c);
return columns.size()-1;*/
return addColumn(JKQTPColumn(this, name, itemID, columnInItem));
};
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPDatastore::addColumn(size_t rows, const QString& name) {
//items.push_back(new JKQTPDatastoreItem(1, rows));
//return addColumnForItem(items.size()-1, 0, name);
size_t item= addItem(new JKQTPDatastoreItem(1, rows));
return addColumnForItem(item, 0, name);
};
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPDatastore::addColumn(const QString& name) {
return addColumn(0, name);
};
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPDatastore::addColumn(double* data, size_t rows, const QString& name) {
//items.push_back(new JKQTPDatastoreItem(JKQTPSingleColumn, data, 1, rows));
//std::cout<<"added item\n";
//size_t it=items.size()-1;
//std::cout<<"adding column\n";
size_t it=addItem(new JKQTPDatastoreItem(JKQTPDatastoreItemFormat::SingleColumn, data, 1, rows));
return addColumnForItem(it, 0, name);
};
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPDatastore::addInternalColumn(double* data, size_t rows, const QString& name) {
//items.push_back(new JKQTPDatastoreItem(JKQTPSingleColumn, data, 1, rows));
//std::cout<<"added item\n";
//size_t it=items.size()-1;
//std::cout<<"adding column\n";
size_t it=addItem(new JKQTPDatastoreItem(JKQTPDatastoreItemFormat::SingleColumn, data, 1, rows,true));
return addColumnForItem(it, 0, name);
}

File diff suppressed because it is too large Load Diff

View File

@ -21,8 +21,8 @@
#include "jkqtplotter/jkqtpelementsoverlay.h"
#include "jkqtplotter/jkqtpbaseplotter.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplottertools/jkqtpdrawingtools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtcommon/jkqtpdrawingtools.h"
#include <stdlib.h>
#include <QDebug>

View File

@ -22,7 +22,7 @@
#include <QString>
#include <QPainter>
#include <QPair>
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtcommon/jkqtp_imexport.h"
#include "jkqtplotter/jkqtpgraphsbasestylingmixins.h"

View File

@ -24,7 +24,7 @@
#include <stdlib.h>
#include <QDebug>
#include <iostream>
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/jkqtpgraphsimage.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplotter/jkqtplotter.h"

View File

@ -20,9 +20,9 @@
#include <QString>
#include <QPainter>
#include <QPair>
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtcommon/jkqtp_imexport.h"
#include "jkqtplottertools/jkqtpimagetools.h"
#include "jkqtplotter/jkqtpimagetools.h"
#include "jkqtplotter/jkqtpgraphsbase.h"
#include "jkqtplotter/jkqtpgraphsbaseerrors.h"
#include "jkqtplotter/jkqtpgraphsbasestylingmixins.h"

View File

@ -24,7 +24,7 @@
#include <stdlib.h>
#include <QDebug>
#include <iostream>
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/jkqtpgraphsimage.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplotter/jkqtplotter.h"
@ -167,11 +167,11 @@ QString JKQTPPlotElement::formatHitTestDefaultLabel(double x, double y, int inde
if (errgx->getXErrorColumn()>=0) {
if (errgx->getXErrorColumnLower()>=0) {
xerrstr=QString("\\:+%1\\:-%2")
.arg(QString::fromStdString(jkqtp_floattolatexstr(datastore->get(errgx->getXErrorColumn(),static_cast<size_t>(index)), 3)))
.arg(QString::fromStdString(jkqtp_floattolatexstr(datastore->get(errgx->getXErrorColumnLower(),static_cast<size_t>(index)), 3)));
.arg(jkqtp_floattolatexqstr(datastore->get(errgx->getXErrorColumn(),static_cast<size_t>(index)), 3))
.arg(jkqtp_floattolatexqstr(datastore->get(errgx->getXErrorColumnLower(),static_cast<size_t>(index)), 3));
} else {
xerrstr=QString("{\\:}{\\pm}%1")
.arg(QString::fromStdString(jkqtp_floattolatexstr(datastore->get(errgx->getXErrorColumn(),static_cast<size_t>(index)), 3)));
.arg(jkqtp_floattolatexqstr(datastore->get(errgx->getXErrorColumn(),static_cast<size_t>(index)), 3));
}
}
}
@ -183,15 +183,15 @@ QString JKQTPPlotElement::formatHitTestDefaultLabel(double x, double y, int inde
if (errgy->getYErrorColumn()>=0) {
if (errgy->getYErrorColumnLower()>=0) {
yerrstr=QString("\\:+%1\\:-%2")
.arg(QString::fromStdString(jkqtp_floattolatexstr(datastore->get(errgy->getYErrorColumn(),static_cast<size_t>(index)), 3)))
.arg(QString::fromStdString(jkqtp_floattolatexstr(datastore->get(errgy->getYErrorColumnLower(),static_cast<size_t>(index)), 3)));
.arg(jkqtp_floattolatexqstr(datastore->get(errgy->getYErrorColumn(),static_cast<size_t>(index)), 3))
.arg(jkqtp_floattolatexqstr(datastore->get(errgy->getYErrorColumnLower(),static_cast<size_t>(index)), 3));
} else {
yerrstr=QString("{\\:}{\\pm}%1")
.arg(QString::fromStdString(jkqtp_floattolatexstr(datastore->get(errgy->getYErrorColumn(),static_cast<size_t>(index)), 3)));
.arg(jkqtp_floattolatexqstr(datastore->get(errgy->getYErrorColumn(),static_cast<size_t>(index)), 3));
}
}
}
return QString("\\ensuremath{\\left[{\\:}%1%3{\\;},{\\;}%2%4{\\:}\\right]}").arg(QString::fromStdString(jkqtp_floattolatexstr(x, 3))).arg(QString::fromStdString(jkqtp_floattolatexstr(y, 3))).arg(xerrstr).arg(yerrstr);
return QString("\\ensuremath{\\left[{\\:}%1%3{\\;},{\\;}%2%4{\\:}\\right]}").arg(jkqtp_floattolatexqstr(x, 3)).arg(jkqtp_floattolatexqstr(y, 3)).arg(xerrstr).arg(yerrstr);
}
@ -506,6 +506,7 @@ JKQTPSingleColumnGraph::JKQTPSingleColumnGraph(JKQTPlotter *parent):
void JKQTPSingleColumnGraph::setDataColumn(int __value)
{
this->dataColumn = __value;
if (this->title.size()==0 && parent && __value>=0) this->title=parent->getDatastore()->getColumnName(static_cast<size_t>(__value));
}
int JKQTPSingleColumnGraph::getDataColumn() const
@ -515,6 +516,7 @@ int JKQTPSingleColumnGraph::getDataColumn() const
void JKQTPSingleColumnGraph::setDataColumn(size_t __value) {
this->dataColumn = static_cast<int>(__value);
if (this->title.size()==0 && parent) this->title=parent->getDatastore()->getColumnName(__value);
}
void JKQTPSingleColumnGraph::setDataSortOrder(JKQTPSingleColumnGraph::DataSortOrder __value)

View File

@ -23,9 +23,9 @@
#include <QPair>
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplotter/jkqtpbaseplotter.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtcommon/jkqtp_imexport.h"
#include "jkqtplottertools/jkqtpimagetools.h"
#include "jkqtplotter/jkqtpimagetools.h"
#ifndef JKQTPGRAPHSBASE_H
#define JKQTPGRAPHSBASE_H

View File

@ -24,7 +24,7 @@
#include <stdlib.h>
#include <QDebug>
#include <iostream>
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/jkqtpgraphsimage.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplotter/jkqtplotter.h"

View File

@ -24,9 +24,9 @@
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplotter/jkqtpbaseplotter.h"
#include "jkqtplotter/jkqtpgraphsbase.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtcommon/jkqtp_imexport.h"
#include "jkqtplottertools/jkqtpimagetools.h"
#include "jkqtplotter/jkqtpimagetools.h"
#ifndef JKQTPGRAPHSBASEERROR_H
#define JKQTPGRAPHSBASEERROR_H

View File

@ -22,9 +22,9 @@
#include <QPainter>
#include <QPen>
#include <QBrush>
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtcommon/jkqtp_imexport.h"
#include "jkqtplottertools/jkqtpdrawingtools.h"
#include "jkqtcommon/jkqtpdrawingtools.h"
#ifndef jkqtpgraphsbasestylingmixins_H

View File

@ -24,7 +24,7 @@
#include <stdlib.h>
#include <QDebug>
#include <iostream>
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/jkqtpgraphsimage.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplotter/jkqtplotter.h"
@ -50,6 +50,7 @@ JKQTPBoxplotVerticalGraph::JKQTPBoxplotVerticalGraph(JKQTBasePlotter* parent):
sortData=Unsorted;
initBoxplotStyle(parent, parentPlotStyle);
setMeanSymbolType(JKQTPPlus);
}
@ -123,19 +124,19 @@ void JKQTPBoxplotVerticalGraph::draw(JKQTPEnhancedPainter& painter) {
QStringList labelValues, labelNames;
int labMedian=-1, labMean=-1, labMin=-1, labMax=-1, labQ25=-1, labQ75=-1;
labelNames<<"pos";
labelValues<<QString::fromStdString(jkqtp_floattolatexstr(xv, 3));
if (minColumn>=0 && JKQTPIsOKFloat(minv)) { labelNames<<"\\min"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(minv, 3)); labMin=labelValues.size()-1; }
if (percentile25Column>=0 && JKQTPIsOKFloat(p25v)) { labelNames<<"q_{25}"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(p25v, 3)); labQ25=labelValues.size()-1; }
labelValues<<jkqtp_floattolatexqstr(xv, 3);
if (minColumn>=0 && JKQTPIsOKFloat(minv)) { labelNames<<"\\min"; labelValues<<jkqtp_floattolatexqstr(minv, 3); labMin=labelValues.size()-1; }
if (percentile25Column>=0 && JKQTPIsOKFloat(p25v)) { labelNames<<"q_{25}"; labelValues<<jkqtp_floattolatexqstr(p25v, 3); labQ25=labelValues.size()-1; }
if (medianColumn>=0 && JKQTPIsOKFloat(medianv)) {
if (medianConfidenceColumn>=0 && JKQTPIsOKFloat(medConf)) {
labelNames<<"\\median"; labelValues<<(QString::fromStdString(jkqtp_floattolatexstr(medianv, 3))+"\\:{\\pm}\\:"+QString::fromStdString(jkqtp_floattolatexstr(medConf, 3))); labMedian=labelValues.size()-1;
labelNames<<"\\median"; labelValues<<(jkqtp_floattolatexqstr(medianv, 3)+"\\:{\\pm}\\:"+jkqtp_floattolatexqstr(medConf, 3)); labMedian=labelValues.size()-1;
} else {
labelNames<<"\\median"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(medianv, 3)); labMedian=labelValues.size()-1;
labelNames<<"\\median"; labelValues<<jkqtp_floattolatexqstr(medianv, 3); labMedian=labelValues.size()-1;
}
}
if (meanColumn>=0 && JKQTPIsOKFloat(meanv)) { labelNames<<"\\mu"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(meanv, 3)); labMean=labelValues.size()-1; }
if (percentile75Column>=0 && JKQTPIsOKFloat(p75v)) { labelNames<<"q_{75}"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(p75v, 3)); labQ75=labelValues.size()-1; }
if (maxColumn>=0 && JKQTPIsOKFloat(maxv)) { labelNames<<"\\max"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(maxv, 3)); labMax=labelValues.size()-1; }
if (meanColumn>=0 && JKQTPIsOKFloat(meanv)) { labelNames<<"\\mu"; labelValues<<jkqtp_floattolatexqstr(meanv, 3); labMean=labelValues.size()-1; }
if (percentile75Column>=0 && JKQTPIsOKFloat(p75v)) { labelNames<<"q_{75}"; labelValues<<jkqtp_floattolatexqstr(p75v, 3); labQ75=labelValues.size()-1; }
if (maxColumn>=0 && JKQTPIsOKFloat(maxv)) { labelNames<<"\\max"; labelValues<<jkqtp_floattolatexqstr(maxv, 3); labMax=labelValues.size()-1; }
const double x=transformX(xv);
const double p25=transformY(p25v);
@ -627,19 +628,19 @@ void JKQTPBoxplotHorizontalGraph::draw(JKQTPEnhancedPainter& painter) {
QStringList labelValues, labelNames;
int labMedian=-1, labMean=-1, labMin=-1, labMax=-1, labQ25=-1, labQ75=-1;
labelNames<<"pos";
labelValues<<QString::fromStdString(jkqtp_floattolatexstr(yv, 3));
if (minColumn>=0 && JKQTPIsOKFloat(minv)) { labelNames<<"\\min"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(minv, 3)); labMin=labelValues.size()-1; }
if (percentile25Column>=0 && JKQTPIsOKFloat(p25v)) { labelNames<<"q_{25}"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(p25v, 3)); labQ25=labelValues.size()-1; }
labelValues<<jkqtp_floattolatexqstr(yv, 3);
if (minColumn>=0 && JKQTPIsOKFloat(minv)) { labelNames<<"\\min"; labelValues<<jkqtp_floattolatexqstr(minv, 3); labMin=labelValues.size()-1; }
if (percentile25Column>=0 && JKQTPIsOKFloat(p25v)) { labelNames<<"q_{25}"; labelValues<<jkqtp_floattolatexqstr(p25v, 3); labQ25=labelValues.size()-1; }
if (medianColumn>=0 && JKQTPIsOKFloat(medianv)) {
if (medianConfidenceColumn>=0 && JKQTPIsOKFloat(medConf)) {
labelNames<<"\\median"; labelValues<<(QString::fromStdString(jkqtp_floattolatexstr(medianv, 3))+"\\:{\\pm}\\:"+QString::fromStdString(jkqtp_floattolatexstr(medConf, 3))); labMedian=labelValues.size()-1;
labelNames<<"\\median"; labelValues<<(jkqtp_floattolatexqstr(medianv, 3)+"\\:{\\pm}\\:"+jkqtp_floattolatexqstr(medConf, 3)); labMedian=labelValues.size()-1;
} else {
labelNames<<"\\median"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(medianv, 3)); labMedian=labelValues.size()-1;
labelNames<<"\\median"; labelValues<<jkqtp_floattolatexqstr(medianv, 3); labMedian=labelValues.size()-1;
}
}
if (meanColumn>=0 && JKQTPIsOKFloat(meanv)) { labelNames<<"\\mu"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(meanv, 3)); labMean=labelValues.size()-1; }
if (percentile75Column>=0 && JKQTPIsOKFloat(p75v)) { labelNames<<"q_{75}"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(p75v, 3)); labQ75=labelValues.size()-1; }
if (maxColumn>=0 && JKQTPIsOKFloat(maxv)) { labelNames<<"\\max"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(maxv, 3)); labMax=labelValues.size()-1; }
if (meanColumn>=0 && JKQTPIsOKFloat(meanv)) { labelNames<<"\\mu"; labelValues<<jkqtp_floattolatexqstr(meanv, 3); labMean=labelValues.size()-1; }
if (percentile75Column>=0 && JKQTPIsOKFloat(p75v)) { labelNames<<"q_{75}"; labelValues<<jkqtp_floattolatexqstr(p75v, 3); labQ75=labelValues.size()-1; }
if (maxColumn>=0 && JKQTPIsOKFloat(maxv)) { labelNames<<"\\max"; labelValues<<jkqtp_floattolatexqstr(maxv, 3); labMax=labelValues.size()-1; }
@ -744,6 +745,7 @@ JKQTPBoxplotVerticalElement::JKQTPBoxplotVerticalElement(JKQTBasePlotter* parent
drawNotch=false;
initBoxplotStyle(parent, parentPlotStyle);
setMeanSymbolType(JKQTPPlus);
}
@ -789,19 +791,19 @@ void JKQTPBoxplotVerticalElement::draw(JKQTPEnhancedPainter& painter) {
QStringList labelValues, labelNames;
int labMedian=-1, labMean=-1, labMin=-1, labMax=-1, labQ25=-1, labQ75=-1;
labelNames<<"pos";
labelValues<<QString::fromStdString(jkqtp_floattolatexstr(xv, 3));
if (JKQTPIsOKFloat(minv)) { labelNames<<"\\min"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(minv, 3)); labMin=labelValues.size()-1; }
if (JKQTPIsOKFloat(p25v)) { labelNames<<"q_{25}"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(p25v, 3)); labQ25=labelValues.size()-1; }
labelValues<<jkqtp_floattolatexqstr(xv, 3);
if (JKQTPIsOKFloat(minv)) { labelNames<<"\\min"; labelValues<<jkqtp_floattolatexqstr(minv, 3); labMin=labelValues.size()-1; }
if (JKQTPIsOKFloat(p25v)) { labelNames<<"q_{25}"; labelValues<<jkqtp_floattolatexqstr(p25v, 3); labQ25=labelValues.size()-1; }
if (JKQTPIsOKFloat(medianv)) {
if (JKQTPIsOKFloat(medConf)) {
labelNames<<"\\median"; labelValues<<(QString::fromStdString(jkqtp_floattolatexstr(medianv, 3))+"\\:{\\pm}\\:"+QString::fromStdString(jkqtp_floattolatexstr(medConf, 3))); labMedian=labelValues.size()-1;
labelNames<<"\\median"; labelValues<<(jkqtp_floattolatexqstr(medianv, 3)+"\\:{\\pm}\\:"+jkqtp_floattolatexqstr(medConf, 3)); labMedian=labelValues.size()-1;
} else {
labelNames<<"\\median"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(medianv, 3)); labMedian=labelValues.size()-1;
labelNames<<"\\median"; labelValues<<jkqtp_floattolatexqstr(medianv, 3); labMedian=labelValues.size()-1;
}
}
if (JKQTPIsOKFloat(meanv)) { labelNames<<"\\mu"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(meanv, 3)); labMean=labelValues.size()-1; }
if (JKQTPIsOKFloat(p75v)) { labelNames<<"q_{75}"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(p75v, 3)); labQ75=labelValues.size()-1; }
if (JKQTPIsOKFloat(maxv)) { labelNames<<"\\max"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(maxv, 3)); labMax=labelValues.size()-1; }
if (JKQTPIsOKFloat(meanv)) { labelNames<<"\\mu"; labelValues<<jkqtp_floattolatexqstr(meanv, 3); labMean=labelValues.size()-1; }
if (JKQTPIsOKFloat(p75v)) { labelNames<<"q_{75}"; labelValues<<jkqtp_floattolatexqstr(p75v, 3); labQ75=labelValues.size()-1; }
if (JKQTPIsOKFloat(maxv)) { labelNames<<"\\max"; labelValues<<jkqtp_floattolatexqstr(maxv, 3); labMax=labelValues.size()-1; }
double w=parent->pt2px(painter,getBoxWidthAbsolute());
double xma=x+w/2.0;
@ -1063,6 +1065,11 @@ QColor JKQTPBoxplotVerticalElement::getKeyLabelColor() const {
return getLineColor();
}
void JKQTPBoxplotVerticalElement::setColor(QColor c)
{
setBoxplotColor(c, getParent());
}
@ -1172,19 +1179,19 @@ void JKQTPBoxplotHorizontalElement::draw(JKQTPEnhancedPainter& painter) {
QStringList labelValues, labelNames;
int labMedian=-1, labMean=-1, labMin=-1, labMax=-1, labQ25=-1, labQ75=-1;
labelNames<<"pos";
labelValues<<QString::fromStdString(jkqtp_floattolatexstr(yv, 3));
if (JKQTPIsOKFloat(minv)) { labelNames<<"\\min"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(minv, 3)); labMin=labelValues.size()-1; }
if (JKQTPIsOKFloat(p25v)) { labelNames<<"q_{25}"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(p25v, 3)); labQ25=labelValues.size()-1; }
labelValues<<jkqtp_floattolatexqstr(yv, 3);
if (JKQTPIsOKFloat(minv)) { labelNames<<"\\min"; labelValues<<jkqtp_floattolatexqstr(minv, 3); labMin=labelValues.size()-1; }
if (JKQTPIsOKFloat(p25v)) { labelNames<<"q_{25}"; labelValues<<jkqtp_floattolatexqstr(p25v, 3); labQ25=labelValues.size()-1; }
if (JKQTPIsOKFloat(medianv)) {
if (JKQTPIsOKFloat(medConf)) {
labelNames<<"\\median"; labelValues<<(QString::fromStdString(jkqtp_floattolatexstr(medianv, 3))+"\\:{\\pm}\\:"+QString::fromStdString(jkqtp_floattolatexstr(medConf, 3))); labMedian=labelValues.size()-1;
labelNames<<"\\median"; labelValues<<(jkqtp_floattolatexqstr(medianv, 3)+"\\:{\\pm}\\:"+jkqtp_floattolatexqstr(medConf, 3)); labMedian=labelValues.size()-1;
} else {
labelNames<<"\\median"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(medianv, 3)); labMedian=labelValues.size()-1;
labelNames<<"\\median"; labelValues<<jkqtp_floattolatexqstr(medianv, 3); labMedian=labelValues.size()-1;
}
}
if (JKQTPIsOKFloat(meanv)) { labelNames<<"\\mu"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(meanv, 3)); labMean=labelValues.size()-1; }
if (JKQTPIsOKFloat(p75v)) { labelNames<<"q_{75}"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(p75v, 3)); labQ75=labelValues.size()-1; }
if (JKQTPIsOKFloat(maxv)) { labelNames<<"\\max"; labelValues<<QString::fromStdString(jkqtp_floattolatexstr(maxv, 3)); labMax=labelValues.size()-1; }
if (JKQTPIsOKFloat(meanv)) { labelNames<<"\\mu"; labelValues<<jkqtp_floattolatexqstr(meanv, 3); labMean=labelValues.size()-1; }
if (JKQTPIsOKFloat(p75v)) { labelNames<<"q_{75}"; labelValues<<jkqtp_floattolatexqstr(p75v, 3); labQ75=labelValues.size()-1; }
if (JKQTPIsOKFloat(maxv)) { labelNames<<"\\max"; labelValues<<jkqtp_floattolatexqstr(maxv, 3); labMax=labelValues.size()-1; }
double w=parent->pt2px(painter,getBoxWidthAbsolute());
double yma=y+w/2.0;

View File

@ -21,9 +21,9 @@
#include <QString>
#include <QPainter>
#include <QPair>
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtcommon/jkqtp_imexport.h"
#include "jkqtplottertools/jkqtpimagetools.h"
#include "jkqtplotter/jkqtpimagetools.h"
#include "jkqtplotter/jkqtpgraphsbase.h"
#include "jkqtplotter/jkqtpgraphsboxplotstylingmixins.h"
#include "jkqtplotter/jkqtpgraphsbasestylingmixins.h"
@ -102,7 +102,7 @@ class JKQTP_LIB_EXPORT JKQTPBoxplotVerticalGraph: public JKQTPGraph, public JKQT
Q_OBJECT
public:
/** \brief Sortierordnung für Daten in einem JKQTPBoxplotVerticalGraph (oder seinen Kindern) */
/** \brief Sort order in a JKQTPBoxplotVerticalGraph (or one of its child classes) */
enum DataSortOrder {
Unsorted=0,
Sorted=1
@ -321,6 +321,8 @@ class JKQTP_LIB_EXPORT JKQTPBoxplotVerticalElement: public JKQTPPlotObject, publ
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) override;
/** \brief returns the color to be used for the key label */
virtual QColor getKeyLabelColor() const override;
/*! \brief set the color of the graph (colors all elements, based on the given color \a c )*/
virtual void setColor(QColor c);
/** \brief get the maximum and minimum x-value of the graph

View File

@ -24,7 +24,7 @@
#include <stdlib.h>
#include <QDebug>
#include <iostream>
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/jkqtpgraphsimage.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplotter/jkqtplotter.h"
@ -83,6 +83,7 @@ void JKQTPGraphBoxplotStyleMixin::initBoxplotStyle(JKQTBasePlotter *parent, int
setWhiskerLineColor(getLineColor());
setWhiskerCapLineColor(getLineColor());
setMedianLineColor(getLineColor());
setMeanSymbolType(JKQTPPlus);
if (m_meanSymbolSize>0) {
boxWidthAbsolute=m_meanSymbolSize*3.0;

View File

@ -20,7 +20,7 @@
#include <QString>
#include <QPainter>
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtcommon/jkqtp_imexport.h"
#include "jkqtplotter/jkqtpgraphsbase.h"
#include "jkqtplotter/jkqtpgraphsbasestylingmixins.h"

View File

@ -20,9 +20,9 @@
#include "jkqtplotter/jkqtpgraphscontour.h"
#include "jkqtplotter/jkqtpbaseplotter.h"
#include "jkqtplottertools/jkqtpimagetools.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplottertools/jkqtpenhancedpainter.h"
#include "jkqtplotter/jkqtpimagetools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtcommon/jkqtpenhancedpainter.h"
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtpgraphscontour.h"
#include <QDebug>

View File

@ -28,12 +28,12 @@
#include <QVector3D>
#include <QIcon>
#include "jkqtplotter/jkqtpgraphsscatter.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplotter/jkqtpgraphsimage.h"
#include "jkqtplotter/jkqtpgraphsbasestylingmixins.h"
#include "jkqtcommon/jkqtp_imexport.h"
#include "jkqtplottertools/jkqtpimagetools.h"
#include "jkqtplotter/jkqtpimagetools.h"

View File

@ -24,7 +24,7 @@
#include <stdlib.h>
#include <QDebug>
#include <iostream>
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/jkqtpgraphsimage.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplotter/jkqtplotter.h"
@ -82,6 +82,46 @@ JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTPlotter* parent):
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(const jkqtpSimplePlotFunctionType &f, const QString &title_, JKQTBasePlotter *parent):
JKQTPXFunctionLineGraph(parent)
{
title=title_;
plotFunction=jkqtpPlotFunctionType();
simplePlotFunction=f;
functionType=SpecialFunction::UserFunction;
clearData();
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(const jkqtpSimplePlotFunctionType &f, const QString &title_, JKQTPlotter *parent):
JKQTPXFunctionLineGraph(parent)
{
title=title_;
plotFunction=jkqtpPlotFunctionType();
simplePlotFunction=f;
functionType=SpecialFunction::UserFunction;
clearData();
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(jkqtpSimplePlotFunctionType &&f, const QString &title_, JKQTBasePlotter *parent):
JKQTPXFunctionLineGraph(parent)
{
title=title_;
plotFunction=jkqtpPlotFunctionType();
simplePlotFunction=std::move(f);
functionType=SpecialFunction::UserFunction;
clearData();
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(jkqtpSimplePlotFunctionType &&f, const QString &title_, JKQTPlotter *parent):
JKQTPXFunctionLineGraph(parent)
{
title=title_;
plotFunction=jkqtpPlotFunctionType();
simplePlotFunction=std::move(f);
functionType=SpecialFunction::UserFunction;
clearData();
}
JKQTPXFunctionLineGraph::~JKQTPXFunctionLineGraph() {
clearData();
@ -519,6 +559,16 @@ JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(JKQTBasePlotter *parent):JKQTPX
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(JKQTPlotter *parent):JKQTPYFunctionLineGraph(parent->getPlotter()) {}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(const jkqtpSimplePlotFunctionType &f, const QString &title, JKQTBasePlotter *parent):JKQTPXFunctionLineGraph(f, title, parent) {}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(const jkqtpSimplePlotFunctionType &f, const QString &title, JKQTPlotter *parent):JKQTPXFunctionLineGraph(f, title, parent) {}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(jkqtpSimplePlotFunctionType &&f, const QString &title, JKQTBasePlotter *parent):JKQTPXFunctionLineGraph(std::move(f), title, parent) {}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(jkqtpSimplePlotFunctionType &&f, const QString &title, JKQTPlotter *parent):JKQTPXFunctionLineGraph(std::move(f), title, parent) {}
void JKQTPYFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaaot("JKQTPYFunctionLineGraph::draw");

View File

@ -84,6 +84,14 @@ class JKQTP_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPGraph, public JKQTPG
/** \brief class constructor */
JKQTPXFunctionLineGraph(JKQTPlotter* parent);
/** \brief class constructor */
JKQTPXFunctionLineGraph(const jkqtpSimplePlotFunctionType & f, const QString& title, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXFunctionLineGraph(const jkqtpSimplePlotFunctionType & f, const QString& title, JKQTPlotter* parent);
/** \brief class constructor */
JKQTPXFunctionLineGraph(jkqtpSimplePlotFunctionType && f, const QString& title, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXFunctionLineGraph(jkqtpSimplePlotFunctionType && f, const QString& title, JKQTPlotter* parent);
/** \brief class destructor */
virtual ~JKQTPXFunctionLineGraph() override;
@ -392,6 +400,14 @@ class JKQTP_LIB_EXPORT JKQTPYFunctionLineGraph: public JKQTPXFunctionLineGraph {
JKQTPYFunctionLineGraph(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPYFunctionLineGraph(JKQTPlotter* parent);
/** \brief class constructor */
JKQTPYFunctionLineGraph(const jkqtpSimplePlotFunctionType & f, const QString& title, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPYFunctionLineGraph(const jkqtpSimplePlotFunctionType & f, const QString& title, JKQTPlotter* parent);
/** \brief class constructor */
JKQTPYFunctionLineGraph(jkqtpSimplePlotFunctionType && f, const QString& title, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPYFunctionLineGraph(jkqtpSimplePlotFunctionType && f, const QString& title, JKQTPlotter* parent);
/** \brief plots the graph to the plotter object specified as parent */
virtual void draw(JKQTPEnhancedPainter& painter) override;

View File

@ -24,7 +24,7 @@
#include <stdlib.h>
#include <QDebug>
#include <iostream>
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/jkqtpgraphsimage.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplotter/jkqtplotter.h"

View File

@ -515,7 +515,7 @@ void JKQTPGeoInfiniteLine::draw(JKQTPEnhancedPainter& painter) {
if (l.length()>0) {
painter.drawLine(l);
addHitTestData(x, y, formatHitTestDefaultLabel(x,y)+
QString(", \\ensuremath{\\mathrm{\\mathbf{d}}y/\\mathrm{\\mathbf{d}}x\\;=\\;%1/%2\\;=\\;%3\\;=\\;%4\\degree}").arg(QString::fromStdString(jkqtp_floattolatexstr(dy, 3))).arg(QString::fromStdString(jkqtp_floattolatexstr(dx, 3))).arg(QString::fromStdString(jkqtp_floattolatexstr(dy/dx, 3))).arg(QString::fromStdString(jkqtp_floattolatexstr(atan2(dy,dx), 1))));
QString(", \\ensuremath{\\mathrm{\\mathbf{d}}y/\\mathrm{\\mathbf{d}}x\\;=\\;%1/%2\\;=\\;%3\\;=\\;%4\\degree}").arg(jkqtp_floattolatexqstr(dy, 3)).arg(jkqtp_floattolatexqstr(dx, 3)).arg(jkqtp_floattolatexqstr(dy/dx, 3)).arg(jkqtp_floattolatexqstr(atan2(dy,dx), 1)));
addHitTestData(x1, y1);
addHitTestData(x2, y2);
}

View File

@ -23,7 +23,7 @@
#include <QPair>
#include "jkqtplotter/jkqtpgraphsscatter.h"
#include "jkqtplotter/jkqtpgraphsbasestylingmixins.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtcommon/jkqtp_imexport.h"
#include "jkqtmathtext/jkqtmathtext.h"

View File

@ -20,9 +20,9 @@
#include "jkqtplotter/jkqtpgraphsimage.h"
#include "jkqtplotter/jkqtpbaseplotter.h"
#include "jkqtplottertools/jkqtpimagetools.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplottertools/jkqtpenhancedpainter.h"
#include "jkqtplotter/jkqtpimagetools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtcommon/jkqtpenhancedpainter.h"
#include "jkqtplotter/jkqtplotter.h"
#include <QDebug>
#include <QImageWriter>

View File

@ -27,10 +27,10 @@
#include <QImage>
#include <QIcon>
#include "jkqtplotter/jkqtpgraphsscatter.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtcommon/jkqtp_imexport.h"
#include "jkqtplottertools/jkqtpimagetools.h"
#include "jkqtplotter/jkqtpimagetools.h"

View File

@ -20,9 +20,9 @@
#include "jkqtplotter/jkqtpgraphsimageoverlays.h"
#include "jkqtplotter/jkqtpbaseplotter.h"
#include "jkqtplottertools/jkqtpimagetools.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplottertools/jkqtpenhancedpainter.h"
#include "jkqtplotter/jkqtpimagetools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtcommon/jkqtpenhancedpainter.h"
#include "jkqtplotter/jkqtplotter.h"
#include <QDebug>
#include <QImageWriter>

View File

@ -27,11 +27,11 @@
#include <QImage>
#include <QIcon>
#include "jkqtplotter/jkqtpgraphsscatter.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplotter/jkqtpgraphsimage.h"
#include "jkqtcommon/jkqtp_imexport.h"
#include "jkqtplottertools/jkqtpimagetools.h"
#include "jkqtplotter/jkqtpimagetools.h"

View File

@ -20,9 +20,9 @@
#include "jkqtplotter/jkqtpgraphsimagergb.h"
#include "jkqtplotter/jkqtpbaseplotter.h"
#include "jkqtplottertools/jkqtpimagetools.h"
#include "jkqtcommon/jkqtptools.h"
#include "jkqtplottertools/jkqtpenhancedpainter.h"
#include "jkqtplotter/jkqtpimagetools.h"
#include "jkqtplotter/jkqtptools.h"
#include "jkqtcommon/jkqtpenhancedpainter.h"
#include "jkqtplotter/jkqtplotter.h"
#include <QDebug>
#include <QImageWriter>

Some files were not shown because too many files have changed in this diff Show More