diff --git a/JKQtPlotterBuildAllExamples.pro b/JKQtPlotterBuildAllExamples.pro
index deaa934880..b293c056e2 100644
--- a/JKQtPlotterBuildAllExamples.pro
+++ b/JKQtPlotterBuildAllExamples.pro
@@ -52,41 +52,42 @@ defineTest(addSimpleTest) {
export (SUBDIRS)
}
+addSimpleTest(advplotstyling)
addSimpleTest(barchart)
+addSimpleTest(boxplot)
+addSimpleTest(contourplot)
+addSimpleTest(datastore)
+addSimpleTest(datastore_groupedstat)
+addSimpleTest(datastore_iterators)
+addSimpleTest(datastore_regression)
+addSimpleTest(datastore_statistics)
+addSimpleTest(datastore_statistics_2d)
addSimpleTest(dateaxes)
addSimpleTest(errorbarstyles)
+addSimpleTest(evalcurve)
+addSimpleTest(filledgraphs)
+addSimpleTest(functionplot)
+addSimpleTest(geo_arrows)
+addSimpleTest(geo_simple)
+addSimpleTest(geometric)
addSimpleTest(imageplot)
addSimpleTest(imageplot_modifier)
+addSimpleTest(imageplot_nodatastore)
+addSimpleTest(impulsesplot)
addSimpleTest(logaxes)
+addSimpleTest(mandelbrot)
+addSimpleTest(parametriccurve)
+addSimpleTest(paramscatterplot)
+addSimpleTest(paramscatterplot_image)
+addSimpleTest(parsedfunctionplot)
+addSimpleTest(rgbimageplot)
+addSimpleTest(rgbimageplot_qt)
+addSimpleTest(speed)
addSimpleTest(stackedbars)
addSimpleTest(symbols_and_errors)
addSimpleTest(symbols_and_styles)
-addSimpleTest(filledgraphs)
-addSimpleTest(speed)
-addSimpleTest(rgbimageplot)
-addSimpleTest(rgbimageplot_qt)
-addSimpleTest(impulsesplot)
-addSimpleTest(paramscatterplot)
-addSimpleTest(paramscatterplot_image)
-addSimpleTest(parametriccurve)
-addSimpleTest(parsedfunctionplot)
-addSimpleTest(functionplot)
-addSimpleTest(geometric)
-addSimpleTest(geo_simple)
-addSimpleTest(geo_arrows)
addSimpleTest(ui)
-addSimpleTest(boxplot)
-addSimpleTest(advplotstyling)
-addSimpleTest(imageplot_nodatastore)
-addSimpleTest(datastore)
-addSimpleTest(datastore_iterators)
-addSimpleTest(datastore_statistics)
-addSimpleTest(datastore_statistics_2d)
-addSimpleTest(datastore_regression)
-addSimpleTest(datastore_groupedstat)
-addSimpleTest(contourplot)
addSimpleTest(violinplot)
-addSimpleTest(evalcurve)
#addSimpleTest(rgbimageplot_opencv)
#addSimpleTest(imageplot_opencv)
diff --git a/doc/dox/examples_and_tutorials.dox b/doc/dox/examples_and_tutorials.dox
index 27693b23ea..86646e11d3 100644
--- a/doc/dox/examples_and_tutorials.dox
+++ b/doc/dox/examples_and_tutorials.dox
@@ -212,6 +212,9 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
\image html mandelbrot_small.png
+ | \subpage JKQTPlotterMandelbrot
+ |
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index e2e4670dbb..e2948a0910 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -12,7 +12,6 @@ add_subdirectory(jkqtmathtext_test)
add_subdirectory(jkqtplot_test)
-add_subdirectory(geo_arrows)
add_subdirectory(advplotstyling)
add_subdirectory(barchart)
add_subdirectory(boxplot)
@@ -26,26 +25,29 @@ add_subdirectory(datastore_statistics_2d)
add_subdirectory(dateaxes)
add_subdirectory(distributionplot)
add_subdirectory(errorbarstyles)
+add_subdirectory(evalcurve)
add_subdirectory(filledgraphs)
add_subdirectory(functionplot)
-add_subdirectory(geometric)
+add_subdirectory(geo_arrows)
add_subdirectory(geo_simple)
+add_subdirectory(geometric)
add_subdirectory(imageplot)
-add_subdirectory(imageplot_userpal)
+add_subdirectory(imageplot_cimg)
add_subdirectory(imageplot_modifier)
add_subdirectory(imageplot_nodatastore)
add_subdirectory(imageplot_opencv)
-add_subdirectory(imageplot_cimg)
+add_subdirectory(imageplot_userpal)
add_subdirectory(impulsesplot)
add_subdirectory(logaxes)
+add_subdirectory(mandelbrot)
add_subdirectory(multiplot)
add_subdirectory(parametriccurve)
add_subdirectory(paramscatterplot)
add_subdirectory(paramscatterplot_image)
add_subdirectory(parsedfunctionplot)
add_subdirectory(rgbimageplot)
-add_subdirectory(rgbimageplot_opencv)
add_subdirectory(rgbimageplot_cimg)
+add_subdirectory(rgbimageplot_opencv)
add_subdirectory(rgbimageplot_qt)
add_subdirectory(simpletest)
add_subdirectory(speed)
@@ -58,6 +60,5 @@ add_subdirectory(symbols_and_styles)
add_subdirectory(ui)
add_subdirectory(user_interaction)
add_subdirectory(violinplot)
-add_subdirectory(evalcurve)
diff --git a/examples/README.md b/examples/README.md
index 94a38933a3..595053278b 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -70,6 +70,7 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_test_user_interaction_small.gif)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/user_interaction) | [User Interaction](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/user_interaction) | different possibilities of user-interaction in JKQtPlotter |
+
## Data Management & Statistics (Tutorials)
| Screenshot | Description | Notes |
@@ -88,6 +89,7 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
|:-------------:| ------------- | ------------- |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/test_multiplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/multiplot) | [Layouting Several Plots](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/multiplot) | Combining plots in Qt Layouts linking plot axes copy data from a `std::map` int the datastore print plots/print preview |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/test_distributionplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/distributionplot) | [Plotting a Statistical Distribution of Data](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/distributionplot) | Combines several different graphs to draw random values, their distribution and some statistical properties |
+| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/mandelbrot_small.gif)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/mandelbrot) | [Mandelbrot Set Explorer](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/mandelbrot) | |
diff --git a/examples/mandelbrot/CMakeLists.txt b/examples/mandelbrot/CMakeLists.txt
new file mode 100644
index 0000000000..dc0eb4151a
--- /dev/null
+++ b/examples/mandelbrot/CMakeLists.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.0)
+
+set(EXAMPLE_NAME mandelbrot)
+set(EXENAME jkqtptest_${EXAMPLE_NAME})
+
+message( STATUS ".. Building Example ${EXAMPLE_NAME}" )
+
+
+# Set up source files
+set(SOURCES ${EXAMPLE_NAME}.cpp mandelbrotmainwindow.cpp)
+set(HEADERS mandelbrotmainwindow.h)
+set(RESOURCES )
+set(UIS mandelbrotmainwindow.ui)
+
+add_executable(${EXENAME} WIN32 ${SOURCES} ${HEADERS} ${RESOURCES} ${UIS})
+target_include_directories(${EXENAME} PRIVATE ../../lib)
+if(JKQtPlotter_BUILD_STATIC_LIBS)
+ target_link_libraries(${EXENAME} JKQTPlotterLib)
+elseif(JKQtPlotter_BUILD_SHARED_LIBS)
+ target_link_libraries(${EXENAME} JKQTPlotterSharedLib)
+endif()
+
+
+
+# Installation
+install(TARGETS ${EXENAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+#Installation of Qt DLLs on Windows
+jkqtplotter_deployqt(${EXENAME})
diff --git a/examples/mandelbrot/README.md b/examples/mandelbrot/README.md
new file mode 100644
index 0000000000..6b267d4648
--- /dev/null
+++ b/examples/mandelbrot/README.md
@@ -0,0 +1,200 @@
+# Example (JKQTPlotter): Mandelbrot Set Explorer {#JKQTPlotterMandelbrot}
+
+## Introduction and Usage
+
+This project (see `./examples/mandelbrot/`) shows how to calculate and visualize the [Mandelbrot set](https://en.wikipedia.org/wiki/Mandelbrot_set) using `JKQTPlotter` and its `JKQTPMathImage`.
+
+The source code of the main application is (see [`mandelbrot.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/mandelbrot/mandelbrotmainwindow.cpp):
+
+![mandelbrot](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/mandelbrot.png)
+
+You can use any of the several zooming methods (by mouse-wheel, panning, by drawing a rectangle ...) and the application will automaticaly calculate the zoomed area. Here is an example:
+
+1. Select the Zoom by Mouse Rectangle tool: ![mandelbrot_zoom_pre](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/mandelbrot_zoom_pre.png)
+2. Drag open a rectangle that you want to zoom into: ![mandelbrot_zoom](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/mandelbrot_zoom.png)
+3. When you release the mouse, the new image will be calculated.
+
+
+## How it works
+
+In the constructor, the ui, containing a JKQTPlotter `ui->plot`, is initialized. Then the JKQTPlotter is set up:
+
+```.cpp
+ // 1. set the graph scales manually
+ ui->plot->setXY(-2,1,-1,1);
+ ui->plot->setAbsoluteXY(-5,5,-5,5);
+ // 2. set the asxpect ratio to width/height
+ ui->plot->getPlotter()->setMaintainAspectRatio(true);
+ ui->plot->getPlotter()->setAspectRatio(static_cast(ui->plot->width())/static_cast(ui->plot->height()));
+ // 3. disable grids
+ ui->plot->getXAxis()->setDrawGrid(false);
+ ui->plot->getYAxis()->setDrawGrid(false);
+```
+
+Then a `JKQTPMathImage` is added which displays an image column `mandelbrot_col_display`:
+
+```.cpp
+ graph=new JKQTPColumnMathImage(ui->plot);
+ graph->setTitle("");
+ // image column with the data
+ graph->setImageColumn(mandelbrot_col_display);
+ // image color range is calculated manually!
+ graph->setAutoImageRange(false);
+ graph->setImageMin(0);
+ graph->setImageMax(ui->spinMaxIterations->value());
+ // set image size
+ graph->setX(ui->plot->getXMin());
+ graph->setY(ui->plot->getYMin());
+ graph->setWidth(ui->plot->getXMax()-ui->plot->getXMin());
+ graph->setHeight(ui->plot->getYMax()-ui->plot->getYMin());
+ // add graph to plot
+ ui->plot->addGraph(graph);
+```
+
+In between thise two code blocks, two image columns are added to the internal `JKQTPDatastore`:
+
+```.cpp
+ mandelbrot_col=ds->addImageColumn(300,200, "mandelbrot_image_calculate");
+ mandelbrot_col_display=ds->copyColumn(mandelbrot_col, "mandelbrot_image_display");
+```
+
+As mentioned before, `mandelbrot_col_display` is used for plotting and the baclground column (of the same size) `mandelbrot_col` is used to calculate a new image:
+
+```.cpp
+ calculateMandelSet(ui->plot->getXMin(), ui->plot->getXMax(), ui->plot->getYMin(), ui->plot->getYMax(), 300, 200, ui->spinMaxIterations->value());
+```
+
+When calculation finished, the contents of `mandelbrot_col` is copied to `mandelbrot_col_display`:
+
+```.cpp
+ ui->plot->getDatastore()->copyColumnData(mandelbrot_col_display, mandelbrot_col);
+```
+
+In order to implement the zoom functionality, the signal `JKQTPlotter::zoomChangedLocally` is connected to a function, which recalculates the new image for the new zoom-range:
+
+
+```.cpp
+void MandelbrotMainWindow::plotZoomChangedLocally(double newxmin, double newxmax, double newymin, double newymax, JKQTPlotter */*sender*/)
+{
+ calculateMandelSet(newxmin, newxmax, newymin, newymax, ui->plot->getXAxis()->getParentPlotWidth(), ui->plot->getYAxis()->getParentPlotWidth(), ui->spinMaxIterations->value());
+ ui->plot->getDatastore()->copyColumnData(mandelbrot_col_display, mandelbrot_col);
+ if (ui->chkLogScaling->isChecked()) {
+ std::transform(ui->plot->getDatastore()->begin(mandelbrot_col), ui->plot->getDatastore()->end(mandelbrot_col), ui->plot->getDatastore()->begin(mandelbrot_col), &log10);
+ }
+ graph->setX(newxmin);
+ graph->setY(newymin);
+ graph->setWidth(newxmax-newxmin);
+ graph->setHeight(newymax-newymin);
+ // this call ensures correctly set NX and NY
+ graph->setImageColumn(mandelbrot_col_display);
+ ui->plot->redrawPlot();
+}
+```
+
+The actual calculation is performed in `calculateMandelSet()`:
+
+```.cpp
+void MandelbrotMainWindow::calculateMandelSet(double rmin, double rmax, double imin, double imax, size_t width, size_t height, unsigned int max_iterations) {
+ QElapsedTimer timer;
+ timer.start();
+
+ auto ds=ui->plot->getDatastore();
+
+ // ensure the image column has the correct size
+ ds->resizeImageColumn(mandelbrot_col, width, height);
+ qDebug()<<"calculating for "<begin(mandelbrot_col); pix!= ds->end(mandelbrot_col); ++pix) {
+ // calculate the pixels coordinate in the imaginary plane
+ const double r0=static_cast(pix.getImagePositionX())/static_cast(width)*(rmax-rmin)+rmin;
+ const double i0=static_cast(pix.getImagePositionY())/static_cast(height)*(imax-imin)+imin;
+ //qDebug()<=2 gives the color of
+ // the point.
+ while(ri*ri+ii*ii<=2.0*2.0 && iteration(timer.nsecsElapsed())/1000000.0<<"ms";
+}
+```
+
+Here the actual algorithm to calculate the mandelbrot set is implemented. It iterates over all pixels `pix` in `mandelbrot_col` and updates their value according to the result of the calculation with `*pix=iteration;`.
+
+In order to speed up the program, it actually uses a parallelized version of the algorithm:
+
+```.cpp
+void MandelbrotMainWindow::calculateMandelSet(double rmin, double rmax, double imin, double imax, size_t width, size_t height, unsigned int max_iterations) {
+ QElapsedTimer timer;
+ timer.start();
+
+ auto ds=ui->plot->getDatastore();
+
+ // ensure the image column has the correct size
+ ds->resizeImageColumn(mandelbrot_col, width, height);
+ qDebug()<<"calculating for "<(100,width*height/std::max(2, std::thread::hardware_concurrency()-1));
+
+ std::vector threads;
+ for (size_t offset=0; offsetbegin(mandelbrot_col)+static_cast(offset);
+ // stop iterating at begin+offset+blocksize, or at the end
+ const auto pix_end=pix+static_cast(blocksize);
+ for (; pix!=pix_end; ++pix) {
+ // calculate the pixels coordinate in the imaginary plane
+ const double r0=static_cast(pix.getImagePositionX())/static_cast(width)*(rmax-rmin)+rmin;
+ const double i0=static_cast(pix.getImagePositionY())/static_cast(height)*(imax-imin)+imin;
+ //qDebug()<=2 gives the color of
+ // the point.
+ while(ri*ri+ii*ii<=2.0*2.0 && iteration(timer.nsecsElapsed())/1000000.0<<"ms";
+}
+```
+
+
diff --git a/examples/mandelbrot/mandelbrot.cpp b/examples/mandelbrot/mandelbrot.cpp
new file mode 100644
index 0000000000..191027258a
--- /dev/null
+++ b/examples/mandelbrot/mandelbrot.cpp
@@ -0,0 +1,21 @@
+/** \example mandelbrot.cpp
+ * Shows how to plot the Mandelbrot set with JKQTPlotter, also providing a zooming feature.
+ *
+ * \ref JKQTPlotterMandelbrot
+ */
+
+#include
+#include
+#include "mandelbrotmainwindow.h"
+
+
+
+int main(int argc, char* argv[])
+{
+ QApplication app(argc, argv);
+ MandelbrotMainWindow widMain;
+
+ widMain.show();
+
+ return app.exec();
+}
diff --git a/examples/mandelbrot/mandelbrot.pro b/examples/mandelbrot/mandelbrot.pro
new file mode 100644
index 0000000000..3a0a5c6054
--- /dev/null
+++ b/examples/mandelbrot/mandelbrot.pro
@@ -0,0 +1,27 @@
+# source code for this simple demo
+SOURCES = mandelbrot.cpp
+
+# configure Qt
+CONFIG += link_prl qt
+QT += core gui xml svg
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
+
+# output executable name
+TARGET = mandelbrot
+
+# include JKQTPlotter source code
+DEPENDPATH += ../../lib ../../qmake/staticlib/jkqtplotterlib
+INCLUDEPATH += ../../lib
+CONFIG (debug, debug|release) {
+ LIBS += -L../../qmake/staticlib/jkqtplotterlib/debug -ljkqtplotterlib_debug
+} else {
+ LIBS += -L../../qmake/staticlib/jkqtplotterlib/release -ljkqtplotterlib
+}
+message("LIBS = $$LIBS")
+
+win32-msvc*: DEFINES += _USE_MATH_DEFINES
+win32-msvc*: DEFINES += NOMINMAX
+
+
+
+
diff --git a/examples/mandelbrot/mandelbrot_and_lib.pro b/examples/mandelbrot/mandelbrot_and_lib.pro
new file mode 100644
index 0000000000..73c1a0cf07
--- /dev/null
+++ b/examples/mandelbrot/mandelbrot_and_lib.pro
@@ -0,0 +1,8 @@
+TEMPLATE = subdirs
+
+SUBDIRS += jkqtplotterlib mandelbrot
+
+jkqtplotterlib.file = ../../qmake/staticlib/jkqtplotterlib/jkqtplotterlib.pro
+
+mandelbrot.file=$$PWD/mandelbrot.pro
+mandelbrot.depends = jkqtplotterlib
diff --git a/examples/mandelbrot/mandelbrotmainwindow.cpp b/examples/mandelbrot/mandelbrotmainwindow.cpp
new file mode 100644
index 0000000000..f6dd87a351
--- /dev/null
+++ b/examples/mandelbrot/mandelbrotmainwindow.cpp
@@ -0,0 +1,209 @@
+#include "mandelbrotmainwindow.h"
+#include "ui_mandelbrotmainwindow.h"
+#include
+#include
+
+MandelbrotMainWindow::MandelbrotMainWindow(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::MandelbrotMainWindow)
+{
+ ui->setupUi(this);
+
+ // format graph:
+ // 1. set the graph scales manually
+ ui->plot->setXY(-2,1,-1,1);
+ ui->plot->setAbsoluteXY(-5,5,-5,5);
+ // 2. set the asxpect ratio to width/height
+ ui->plot->getPlotter()->setMaintainAspectRatio(true);
+ ui->plot->getPlotter()->setAspectRatio(static_cast(ui->plot->width())/static_cast(ui->plot->height()));
+ // 3. disable grids
+ ui->plot->getXAxis()->setDrawGrid(false);
+ ui->plot->getYAxis()->setDrawGrid(false);
+
+ JKQTPDatastore* ds=ui->plot->getDatastore();
+
+ mandelbrot_col=ds->addImageColumn(300,200, "mandelbrot_image_calculate");
+ mandelbrot_col_display=ds->copyColumn(mandelbrot_col, "mandelbrot_image_display");
+ calculateMandelSet(ui->plot->getXMin(), ui->plot->getXMax(), ui->plot->getYMin(), ui->plot->getYMax(), 300, 200, ui->spinMaxIterations->value());
+ ui->plot->getDatastore()->copyColumnData(mandelbrot_col_display, mandelbrot_col);
+
+ // 4. create a graph (JKQTPColumnMathImage) with the column created above as data
+ // The data is color-coded with the color-palette JKQTPMathImageMATLAB
+ // the converted range of data is determined automatically because setAutoImageRange(true)
+ graph=new JKQTPColumnMathImage(ui->plot);
+ graph->setTitle("");
+ // image column with the data
+ graph->setImageColumn(mandelbrot_col_display);
+ // image color range is calculated manually!
+ graph->setAutoImageRange(false);
+ graph->setImageMin(0);
+ graph->setImageMax(ui->spinMaxIterations->value());
+ // set image size
+ graph->setX(ui->plot->getXMin());
+ graph->setY(ui->plot->getYMin());
+ graph->setWidth(ui->plot->getXMax()-ui->plot->getXMin());
+ graph->setHeight(ui->plot->getYMax()-ui->plot->getYMin());
+ // add graph to plot
+ ui->plot->addGraph(graph);
+
+
+ ui->cmbColorPalette->setCurrentColorPalette(graph->getColorPalette());
+
+ connect(ui->action_Reset_View, &QAction::triggered, this, &MandelbrotMainWindow::resetView);
+ connect(ui->cmbColorPalette, &JKQTPMathImageColorPaletteComboBox::currentPaletteChanged, this, &MandelbrotMainWindow::paletteChanged);
+ connect(ui->spinMaxIterations, static_cast(&QSpinBox::valueChanged), this, &MandelbrotMainWindow::maxIterationsChanged);
+ connect(ui->chkLogScaling, &QCheckBox::toggled, this, &MandelbrotMainWindow::logScalingChanged);
+ connect(ui->plot, &JKQTPlotter::zoomChangedLocally, this, &MandelbrotMainWindow::plotZoomChangedLocally);
+ connect(ui->plot, &JKQTPlotter::widgetResized, this, &MandelbrotMainWindow::plotResized);
+}
+
+MandelbrotMainWindow::~MandelbrotMainWindow()
+{
+ delete ui;
+}
+
+void MandelbrotMainWindow::paletteChanged(JKQTPMathImageColorPalette pal)
+{
+ graph->setColorPalette(pal);
+ ui->plot->redrawPlot();
+}
+
+void MandelbrotMainWindow::maxIterationsChanged(int/* maxIter*/)
+{
+ graph->setAutoImageRange(false);
+ graph->setImageMin(0);
+ if (ui->chkLogScaling->isChecked()) {
+ graph->setImageMax(log10(ui->spinMaxIterations->value()));
+ } else {
+ graph->setImageMax(ui->spinMaxIterations->value());
+ }
+ plotZoomChangedLocally(ui->plot->getXMin(), ui->plot->getXMax(), ui->plot->getYMin(), ui->plot->getYMax(), ui->plot);
+}
+
+void MandelbrotMainWindow::logScalingChanged(bool en)
+{
+ if (en) {
+ std::transform(ui->plot->getDatastore()->begin(mandelbrot_col), ui->plot->getDatastore()->end(mandelbrot_col), ui->plot->getDatastore()->begin(mandelbrot_col_display), &log10);
+ } else {
+ std::copy(ui->plot->getDatastore()->begin(mandelbrot_col), ui->plot->getDatastore()->end(mandelbrot_col), ui->plot->getDatastore()->begin(mandelbrot_col_display));
+ }
+ graph->setAutoImageRange(false);
+ graph->setImageMin(0);
+ if (ui->chkLogScaling->isChecked()) {
+ graph->setImageMax(log10(ui->spinMaxIterations->value()));
+ } else {
+ graph->setImageMax(ui->spinMaxIterations->value());
+ }
+ ui->plot->redrawPlot();
+}
+
+void MandelbrotMainWindow::plotResized(int /*new_width*/, int /*new_height*/, JKQTPlotter */*sender*/)
+{
+ ui->plot->getPlotter()->setAspectRatio(static_cast(ui->plot->width())/static_cast(ui->plot->height()));
+ ui->plot->getPlotter()->setMaintainAspectRatio(true);
+ qDebug()<<"plotResized: aspect="<(ui->plot->width())/static_cast(ui->plot->height());
+ plotZoomChangedLocally(ui->plot->getXMin(), ui->plot->getXMax(), ui->plot->getYMin(), ui->plot->getYMax(), ui->plot);
+}
+
+void MandelbrotMainWindow::resetView()
+{
+ ui->plot->setXY(-2,1,-1,1);
+ ui->plot->redrawPlot();
+}
+
+void MandelbrotMainWindow::plotZoomChangedLocally(double newxmin, double newxmax, double newymin, double newymax, JKQTPlotter */*sender*/)
+{
+ calculateMandelSet(newxmin, newxmax, newymin, newymax, ui->plot->getXAxis()->getParentPlotWidth(), ui->plot->getYAxis()->getParentPlotWidth(), ui->spinMaxIterations->value());
+ ui->plot->getDatastore()->copyColumnData(mandelbrot_col_display, mandelbrot_col);
+ if (ui->chkLogScaling->isChecked()) {
+ std::transform(ui->plot->getDatastore()->begin(mandelbrot_col), ui->plot->getDatastore()->end(mandelbrot_col), ui->plot->getDatastore()->begin(mandelbrot_col), &log10);
+ }
+ graph->setX(newxmin);
+ graph->setY(newymin);
+ graph->setWidth(newxmax-newxmin);
+ graph->setHeight(newymax-newymin);
+ // this call ensures correctly set NX and NY
+ graph->setImageColumn(mandelbrot_col_display);
+ ui->plot->redrawPlot();
+}
+
+
+void MandelbrotMainWindow::calculateMandelSet(double rmin, double rmax, double imin, double imax, size_t width, size_t height, unsigned int max_iterations) {
+ QElapsedTimer timer;
+ timer.start();
+
+ auto ds=ui->plot->getDatastore();
+
+ // ensure the image column has the correct size
+ ds->resizeImageColumn(mandelbrot_col, width, height);
+ qDebug()<<"calculating for "<(100,width*height/std::max(2, std::thread::hardware_concurrency()-1));
+
+ std::vector threads;
+ for (size_t offset=0; offsetbegin(mandelbrot_col)+static_cast(offset);
+ // stop iterating at begin+offset+blocksize, or at the end
+ const auto pix_end=pix+static_cast(blocksize);
+ for (; pix!=pix_end; ++pix) {
+ // calculate the pixels coordinate in the imaginary plane
+ const double r0=static_cast(pix.getImagePositionX())/static_cast(width)*(rmax-rmin)+rmin;
+ const double i0=static_cast(pix.getImagePositionY())/static_cast(height)*(imax-imin)+imin;
+ //qDebug()<=2 gives the color of
+ // the point.
+ while(ri*ri+ii*ii<=2.0*2.0 && iteration=2 gives the color of
+ // the point.
+ while(ri*ri+ii*ii<=2.0*2.0 && iteration(timer.nsecsElapsed())/1000000.0<<"ms";
+}
diff --git a/examples/mandelbrot/mandelbrotmainwindow.h b/examples/mandelbrot/mandelbrotmainwindow.h
new file mode 100644
index 0000000000..800a8a618d
--- /dev/null
+++ b/examples/mandelbrot/mandelbrotmainwindow.h
@@ -0,0 +1,37 @@
+#ifndef MANDELBROTMAINWINDOW_H
+#define MANDELBROTMAINWINDOW_H
+
+#include
+#include "jkqtplotter/graphs/jkqtpimage.h"
+
+namespace Ui {
+class MandelbrotMainWindow;
+}
+
+class MandelbrotMainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit MandelbrotMainWindow(QWidget *parent = nullptr);
+ ~MandelbrotMainWindow();
+protected slots:
+ void paletteChanged(JKQTPMathImageColorPalette pal);
+ void plotZoomChangedLocally(double newxmin, double newxmax, double newymin, double newymax, JKQTPlotter* sender);
+ void maxIterationsChanged(int maxIter);
+ void logScalingChanged(bool en);
+ void plotResized(int new_width, int new_height, JKQTPlotter* sender);
+ void resetView();
+protected:
+ void calculateMandelSet(double rmin, double rmax, double imin, double imax, size_t width, size_t height, unsigned int max_iterations = 1000);
+private:
+ Ui::MandelbrotMainWindow *ui;
+ // graph representing Mandelbrot Set
+ JKQTPColumnMathImage* graph;
+ // column for Mandelbrot Set image data, used for calculations (double-buffering with mandelbrot_col_display)
+ size_t mandelbrot_col;
+ // column for Mandelbrot Set image data, used for display (double-buffering with mandelbrot_col)
+ size_t mandelbrot_col_display;
+};
+
+#endif // MANDELBROTMAINWINDOW_H
diff --git a/examples/mandelbrot/mandelbrotmainwindow.ui b/examples/mandelbrot/mandelbrotmainwindow.ui
new file mode 100644
index 0000000000..3cd98b0491
--- /dev/null
+++ b/examples/mandelbrot/mandelbrotmainwindow.ui
@@ -0,0 +1,145 @@
+
+
+ MandelbrotMainWindow
+
+
+
+ 0
+ 0
+ 800
+ 600
+
+
+
+ MainWindow
+
+
+
+ -
+
+
-
+
+
+ Color Palette:
+
+
+
+ -
+
+
+ -
+
+
+ logarithmic color scaling
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ max. iterations:
+
+
+
+ -
+
+
+ 1
+
+
+ 1000000
+
+
+ 100
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+ &Exit
+
+
+
+
+ &Reset View
+
+
+
+
+ &Exit
+
+
+
+
+
+ JKQTPlotter
+ QWidget
+ jkqtplotter/jkqtplotter.h
+ 1
+
+
+ JKQTPMathImageColorPaletteComboBox
+ QComboBox
+ jkqtplotter/gui/jkqtpcomboboxes.h
+
+
+
+
+
+ actionExit
+ triggered()
+ MandelbrotMainWindow
+ close()
+
+
+ -1
+ -1
+
+
+ 399
+ 299
+
+
+
+
+
diff --git a/screenshots/mandelbrot.png b/screenshots/mandelbrot.png
new file mode 100644
index 0000000000..eae1c5b90d
Binary files /dev/null and b/screenshots/mandelbrot.png differ
diff --git a/screenshots/mandelbrot_small.png b/screenshots/mandelbrot_small.png
new file mode 100644
index 0000000000..6d85462626
Binary files /dev/null and b/screenshots/mandelbrot_small.png differ
diff --git a/screenshots/mandelbrot_zoom.png b/screenshots/mandelbrot_zoom.png
new file mode 100644
index 0000000000..fc4a8f8e71
Binary files /dev/null and b/screenshots/mandelbrot_zoom.png differ
diff --git a/screenshots/mandelbrot_zoom_pre.png b/screenshots/mandelbrot_zoom_pre.png
new file mode 100644
index 0000000000..ff360d4329
Binary files /dev/null and b/screenshots/mandelbrot_zoom_pre.png differ
|