QwtPlot3D  Manual

  1. Installation
  2. Using Conventions
  3. Simple Plot
  4. Mouse and Keyboard Handling 
  5. Coordinate Systems and Axes 
  6. Plotting Styles
  7. Normal Vectors
  8. Colors
  9. Lighting
  10. Fonts etc.
  11. Enrichments
  12. Mesh Types
  13. Text, Legends
  14. Input/Output
  15. Examples


Installation

With qwtplot3d.pro you can create a

Adjust the target path and perhaps the library directories. The same is true for the examples .pro files.  

QwtPlot3D supports Qt3 and Qt4. Older Qt versions than 3.0 are not supported (and will never work - especially the 2.3.0 non-commercial version for Windows). If I'm wrong  please don't hesitate to contact me. I'll try to provide a code fix for Qt versions >= 3.0.?.

The library requires OpenGL >= 1.1 or equivalent and a true color mode with 24 or 32 bits color depth.

The API Documentation has been created using doxygen. If you prefer to generate your own version, you will find the configuration in ./doc/Doxyfile.doxygen in the offline documentation.
Remark:

You can test almost all abilities of QwtPlot3D  from within the mesh2 example,  including:

  1. Colors, fonts, normal vectors, mouse handling etc.
  2. Grid and FEM data reading from files (in data/*)
  3. Output to all pixmap formats supported by Qt
  4. Output to vector formats supported by gl2ps
  5. Plotting styles and resolution change on the fly
  6. Shading
The example demonstrates vector graphics output utilizing  gl2ps. That means EPS, PS and  PDF. See here for an extensive discussion. gl2ps uses optionally zlib for compression. This leads to significant smaller EPS & PDF output and is therefore recommended. The zlib switch in qwtplot3d.pro turns compression on or off. The default setting is OFF for Windows and ON for all other systems.

So, it would be a good idea to get this example project up and running ...


Using conventions

Calculations are performed as accurate as DBL_EPSILON (see your float.h for the precise value). This is mainly due to the autoscaler. See e.g. here for a topic related discussion.


Simple Plot

  //-----------------------------------------------------------------
// simpleplot.cpp
//
// A simple example which shows how to use SurfacePlot
//-----------------------------------------------------------------

  #include <math.h>
#include <qapplication.h>
#include <qwt3d_surfaceplot.h>
#include <
qwt3d_function.h>


using namespace Qwt3D;

class Rosenbrock : public Function
{
public:

Rosenbrock(SurfacePlot* pw)
:Function(pw)
{
}

double operator()(double x, double y)
{
return log((1-x)*(1-x) + 100 * (y - x*x)*(y - x*x)) / 8;
}
};


class Plot : public SurfacePlot
{
public:
Plot();
};


Plot::Plot()
{
setTitle("A Simple SurfacePlot Demonstration");

Rosenbrock rosenbrock(this);

rosenbrock.setMesh(41,31);
rosenbrock.setDomain(-1.73,1.5,-1.5,1.5);
rosenbrock.setMinZ(-10);

rosenbrock.create();

setRotation(30,0,15);
setScale(1,1,1);
setShift(0.15,0,0);
setZoom(0.9);

for (unsigned i=0; i!=coordinates()->axes.size(); ++i)
{
coordinates()->axes[i].setMajors(7);
coordinates()->axes[i].setMinors(4);
}


coordinates()->axes[X1].setLabelString("x-axis");
coordinates()->axes[Y1].setLabelString("y-axis");
coordinates()->axes[Z1].setLabelString(QChar (0x38f)); // Omega - see http://www.unicode.org/charts/


setCoordinateStyle(BOX);

updateData();
updateGL();
}

int main(int argc, char **argv)
{
QApplication a(argc, argv);
Plot plot;
a.setMainWidget(&plot);
plot.resize(800,600);
plot.show();
return a.exec();
}


The code above shows the almost most simple application of a SurfacePlot. Data are provided by a mathematical function object (Rosenbrock).  You can derive from this kind of classes by including qwt3d_function.h. A base for the other player - the widget itself - resides inside qwt3d_surfaceplot.h.
The derived class makes only small adaptations to the standard behaviour, mainly providing scales and label for the axes and a boxed coordinate system . The axes themselves are autoscaled.


Mouse and Keyboard Handling

Try  Ctrl, Shift, Alt in combination with your wheel and left mouse button to get a clue (or use instead your cursor keys).

The base class Plot3D implements the standard mouse and keyboard behaviour. You can perform shifts, turns, scales and zooms with your left mouse button and combinations of  Ctrl, Shift and  Alt. Some actions have equivalents delegated to your wheel. You can also turn on or off  mouse handling entirely by using Plot3D::enableMouse () and Plot3D::disableMouse (). The default behaviour can be changed with Plot3D::assignMouse(). Keyboard handling has been implemented in a similar way. Additionally, you can determine the speed of the performed actions  when using the keyboard.


Coordinate Systems and Axes

Axes



Axes are subdivided by major and minor tics. You have full control over tic length and orientation and also the line width of tics and the axis body. Furthermore, the axes provide captions and numberings. Colors, fonts etc. of all of this parts are customizable. Additionally, all axes with linear scaling are autoscalable, giving them major tics at positions which are multiples of 1,2,5 * 10^n relative to the underlying interval. 12 axes together form the coordinate system. It can be visualized as frame or box and has the ability to autoswitch axis decoration and visibility of axes themselves depending on the  position in the 3D-space. Most axis properties can be changed for the whole coordinate system at once or separately for single axes. An axis is also part of the color legend object.

Axes are highly customizable regarding label content and tic distribution. Linear and logarithmic scales are supported by default. Other variants, like different numbering schemes (date/time, letters etc.) and user-defined scales are possible.

See the 'axes' project for example implementations.



Plotting Styles

// todo


Normal Vectors

// todo


Colors

The Color  class operates comparable to Function in defining a callback operator(x,y,z) - able to assign to every single data point a RGBA value. In many cases it is sufficient to do this in an exclusively z-coordinate dependent manner.To satisfy this demand, the StandardColor class has been provided. The class has a vector<RGBA> member and the operator() distributes the entries equidistant between the extreme z values of the data. The Plot3D constructor enforces as standard behaviour a StandardColor object with 100 RGBA entries.

The mesh2 data color dialog gives a good example of changing a standard color. The widget is a specialized Qt file dialog for reading palette files (*) . The files include at most 256 different colors (because originally designed for 256 color graphics), but the color vector itself (and also the file reading routine) is by no means limited to this number. To give a plot a new color use  Plot3D::setDataColor . Also, simple RGBA Color attributes are available for background, axes, meshes, labels, title etc..

*shameless stolen from the fractint homepage


Lighting

Some  Plot3D class member encapsulate (partially) OpenGL's lighting features. This means material and light source properties and light source positions. You can set up to 8 different lights (OpenGL guaranteed minimum). Beware, that some calculations become very slow in this case. Lighting is considered  experimental  at this moment, and works not yet in a completely precise way. This will be fixed in the future.


Fonts etc.

All Fonts available for Qt are also provided for screen representation (including Unicode) and pixmap output. A special question concerns output in vector formats. At the moment I have no plans in supporting FreeType or similar solutions. But you can still use the gl2ps provided mixed TeX-EPS/PDF variant, producing pretty satisfying results.
 


Enrichments

Generally spoken, an Enrichment provides additional visual objects depending on data properties. Furthermore, the base class has been well embedded in the plots framework to draw these objects in a reasonable efficient manner. Enrichments come in six flavors: vertex-, edge-, face-, voxel-, graph- and widget-driven (the term 'graph' refers to the data object as a whole). Widget Enrichments are somewhat special, because they describe entities outside the  data object. In future versions they will also gather things like title and legends. The variants 2)-6) are future work, but the yet implemented vertex based Enrichments are still remarkable powerful:


Enrichment


The primary impulse came from the wish to add some small objects (esp. marker etc.) at dedicated positions to the plot. The result is surprisingly more far-reaching. The screenshot shows an entire new plotting style utilizing Vertex Enrichments. The small red-white marker objects are part of the generating Enrichment object as well as the bars themselves. Beginning with version 0.2.3 QwtPlot3D supports user defined plotting styles. But not enough, Plot3D provides a container allowing the injection of arbitrary Enrichments also in other contexts. See the class documentation for closer explanation. The example/enrichment directory contains the application from which the screenshot has been obtained.


Text, Legends

// todo


Mesh Types

// todo


Input/Output

 File I/O in QwtPlot3D works in one of the following ways:

a)  Define a global function:

bool MyHandler(Plot3D* plot, QString const& fname)
{
   SurfacePlot*  tmpplot = (SurfacePlot*)plot;
   // ... do your in- or output here
   return true;
}

b)  ... or an enhanced version - a Functor:

class MyHandler : public IO::Functor
{
public:
    bool some_modifier;
    void  adaptMyBehaviour();
   
    // The next both must be implemented:
    Functor* clone() const
    {
        // The framework assumes the destruction,
        // so provide a heap based object here
        return new MyHandler(you_name_it);
    } 
    bool operator()(Plot3D* plot, QString const& fname)
    {
       // Do highly complex I/O-things here
    }
};

In any case the new function/functor has to be registered by one of the following static functions:

bool IO::defineInputHandler( QString const& format, Functor const& func)
bool IO::defineInputHandler( QString const& format, Function func)


The same procedure applies to the output variants. If you wish to modify the behaviour later, you can either replace the actual handler with a second call to define...Handler() conveying a fresh function/functor or - in the case of a functor - manipulate the yet installed object:

MyHandler* own_format_handler = (MyHandler*)IO::outputHandler("OWN");
if (own_format_handler)
    own_format_handler->
adaptMyBehaviour();
// ...

Pre-defined
output handler for all of the QImageIO pixmap formats are available, in addition a functor for  PDF, PS and EPS output (see also here).

Data Input

QwtPlot3D supports one general and some special forms of native data input:

Generic:

A general approach has been provided in form of the 3 SurfacePlot member:

bool  loadFromData(double **data, unsigned int columns, unsigned int rows, double minx, double maxx, double miny, double maxy)
bool  loadFromData(Qwt3D::Triple **data, unsigned int columns, unsigned int rows, bool uperiodic=false, bool vperiodic=false)
bool  loadFromData(Qwt3D::TripleField const &data, Qwt3D::CellField const &poly)

The 3 functions in this order have ascending generality:

  1. The first one deals with data on top of  plane grids:  z=f(x,y) ;
  2. The 2nd form maps also deformed rectangular grids  x=f(u,v), y=g(u,v), z=h(u,v)   u and v can be periodic  - both or one of them.
  3. The last variant eventually provides support for more free formed meshs, divided in a node- (the TripleField argument) and a  polygon- (the CellField)  part. This kind of data is common for FEM and CAD applications but not limited to them. It is the 'swiss knife' because it is of course able to represent all the other variants. The question here is performance (still not too bad).

Mathematical Functions & Parametric Surfaces:

Setup a function object. To do so, inherit from the Function class and write your own version of Function::operator()(double x, double y). Set the domain and perhaps limitations for the range and call Function::create(). Thats all.See also Function and the implementation of concrete functions in 'examples'.  Parametric surfaces are generalizations of functions. In a similar way, ParameterSurface::operator()(double u, double v) must be replaced. (u,v) domains might have rotational symmetry.  The drawing routines of SurfacePlot are aware of this, if you provide the necessary information with ParametricSurface::setPeriodic().

Grid data files:

   jk:11051895-17021986                       //  magic string
MESH // MESH file (other keywords in future versions)
327 466 // x,y grid
557726 567506 // domain boundaries (x values)
5.10821e+006 5.12216e+006 // domain boundaries (y values)
682 682 682 682 912 924 928 928 932 ...
... element[327*466-1] // the single z values



Coding example:

Reading of the aforementioned file type, utilizing the first of the above mentioned functions.
See NativeReader for additional information. Write your own reader classes in this spirit. It should always be enough to provide appropriate data for SurfacePlot::loadFromData.

  
bool NativeReader::operator()(Plot3D* plot, QString const& fname, QString const& format)
{
FILE* file;
unsigned int xmesh, ymesh;
double minx, maxx, miny, maxy;

if ( !collectInfo(file, fname, xmesh, ymesh, minx, maxx, miny, maxy) )
return false;

/* allocate some space for the mesh */
double** data = allocateData(xmesh, ymesh);

for (unsigned int j = 0; j < ymesh; j++)
{
for (unsigned int i = 0; i < xmesh; i++)
{
if (fscanf(file, "%lf", &data[i][j]) != 1)
{
fprintf(stderr, "NativeReader::read: error in data file \"%s\"\n", (const char*)fname.local8Bit());
return false;
}

if (data[i][j] > maxz_)
data[i][j] = maxz_;
else if (data[i][j] < minz_)
data[i][j] = minz_;
}
}

/* close the file */
fclose(file);

((SurfacePlot*)plot)->loadFromData(data, xmesh, ymesh, minx, maxx, miny, maxy);
deleteData(data,xmesh);

return true;
}


Data Output

// todo


Examples

All the examples can be found in the examples subdirectory, executables are gathered in the examples/bin directory.

simpleplot
The almost most simple plot possible
autoswitch
Demonstrates the autoswitching of axes, and the parallel use of 2 plot widgets in a splitter windows.
axes
Manipulation of  axes parts, like tics, labeling (including the application of user-defined numbering); Positioning for labels; Nonlinear scales
enrichments
The running version from the Enrichment discussion.
mesh2
Main example. It includes (most of) the other features not found in specialized examples. There are still things, hidden in the API. There is a thesis.tex file under the sources of mesh2. It can be used to produce complete output (esp. vectorized numbering etc.) in connection with the libraries PDF and PS output facilities.