OpenIndy Dev Documentation bio photo

OpenIndy Dev Documentation

Open source software solution for industrial measurement (metrology, laser tracker, quality control)

Facebook Github

Model View Control

Model View Control Overview

Overview  Concept and Architecture  Plugins  Server Interface  Model View Control

Model view control (GUI)

OpenIndy uses the model-view-control principle to handle multi different views on the same data. The data (geometries, stations, functions etc. ) are stored in the model classes and the different views show extracts of the data and its attributes. The controller class handles the interactions between the view and the model. If some changes are made to the view (e.g. some data is edited) the controller calls all needed functions and manages the changes in the model. This allows us to have our own internal data logic that manages our data all needed dependencies and does not depend on any view. The multiple views give us different views on the data for a better support during the measurement task. Each view can have some benefits depending on the task, like the graphical representation of the data.

Views in OpenIndy:

- Tableview

The tableview is a tabular representation of the features and their attributes. Each row represents one feature (e.g. one point) and the columns represent the metadata, attributes and values, number of observations for this geometry, measurement configuration and the functions of this feature.

The table view

- Graphic view

The 3D graphic view, using OpenGL, gives the opportunity for a graphical representation of the features and their dependencies. The graphic view also contains a small tree view that contains all features and their attributes.

The graphic view

- Console

The console actually is used as a output device for information, warnings and errors of currently executed functions and actions as well as interactions.

The console


Our model class tablemodel is derived from QAbstractTableModel and therefore has to implement three functions.

int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;

In addition the optional function headerdata is also implemented to specify the column description. If you do not implement this function the column descriptions will be their index. So all in all our model looks like this:

class TableModel : public QAbstractTableModel
    explicit TableModel(QList<FeatureWrapper*> &features, Station *myStation,FeatureWrapper *myFeature,QObject *parent = 0);
    int rowCount(const QModelIndex &parent = QModelIndex()) const;
    int columnCount(const QModelIndex &parent = QModelIndex()) const;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;

    QList<FeatureWrapper*> &features;

    FeatureWrapper *activeFeature;
    Station *activeStation;

public slots:
    void updateModel(FeatureWrapper *fW, Station *sT);

Now the different views on the model are implemented as QSortFilterProxyModel. As an example here is the view for the main tableview featureoverviewproxymodel.h including the geometries and their metadata, attributes, etc.

class FeatureOvserviewProxyModel : public QSortFilterProxyModel

    QList<FeatureWrapper*> &features;

    explicit FeatureOvserviewProxyModel(QList<FeatureWrapper*> &features,QObject *parent = 0);
    bool filterAcceptsColumn ( int source_column, const QModelIndex & source_parent ) const;
    bool filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const;

Here you only have to implement this two functions with your own logic, to filter the columns and rows displayed in the view. As a last step you need to set the filter on the source model and then show the filtered data in the view.

this->featureOverviewModel = new FeatureOvserviewProxyModel(this->features);

The graphic view is an GLWidget rendered with OpenGL. The draw function of the widget handles the different draw methods of each feature type.

void GLWidget::draw(){

    //TODO sicht auf schwerpunkt zentrieren
    glTranslatef(translateX, translateY, translateZ);
    glRotatef(rotationX, 1.0, 0.0 ,0.0);
    glRotatef(rotationY, 0.0, 1.0 ,0.0);
    glRotatef(rotationZ, 0.0, 0.0 ,1.0);

    if(features->size() > 0){

        for(int i =0; i< features->size(); i++){

To do this it calls the draw function of OiGraphix that determines the correct feature type (e.g. plane) and the specific draw function.

void OiGraphix::drawFeature(FeatureWrapper* feature){

    case Configuration::eCoordinateSystemFeature:{
    case Configuration::eTrafoParamFeature:{
    case Configuration::ePlaneFeature:

The specific drawing classes of the features need to derive from the OiGraphixGeomtry class and implement the draw function. The X, Y and the Z attributes are parameters of the draw function. If more attributes are needed (e.g. ijk vector) they have to be given in the constructor. In case of a plane it looks as follows:

class OiGraphixPlane: public OiGraphixGeometry
    OiGraphixPlane(GLfloat nx,GLfloat ny, GLfloat nz);

    GLfloat rx;
    GLfloat ry;
    GLfloat rz;

    void draw(GLfloat x, GLfloat y, GLfloat z);
OiGraphixPlane::OiGraphixPlane(GLfloat nx,GLfloat ny, GLfloat nz)

    rx = nx;
    ry = ny;
    rz = nz;


void OiGraphixPlane::draw(GLfloat x, GLfloat y, GLfloat z){


    glRotatef(acos(rx) * 180.0/PI,1,0,0);
    glRotatef(acos(rz) * 180.0/PI,0,1,0);
    glRotatef(acos(ry) * 180.0/PI,0,0,1);

    for (GLfloat i = -2.5; i <= 2.5; i += 0.25) {
      glVertex3f(i, 0, 2.5); glVertex3f(i, 0, -2.5);
      glVertex3f(2.5, 0, i); glVertex3f(-2.5, 0, i);



3D view (oiGraphixFactory)

OpenGL 3D View