Skip to content
Permalink
Browse files

GUI for 3D point symbols

  • Loading branch information
wonder-sk committed Jul 27, 2017
1 parent 418dc07 commit 82f608ee09e9b0ebdc4913b4f9bf319c66ce1a4f
@@ -48,7 +48,6 @@ void Polygon3DSymbol::readXml( const QDomElement &elem )
// ---------------

Point3DSymbol::Point3DSymbol()
: height( 0 )
{
}

@@ -61,10 +60,6 @@ void Point3DSymbol::writeXml( QDomElement &elem ) const
{
QDomDocument doc = elem.ownerDocument();

QDomElement elemDataProperties = doc.createElement( "data" );
elemDataProperties.setAttribute( "height", height );
elem.appendChild( elemDataProperties );

QDomElement elemMaterial = doc.createElement( "material" );
material.writeXml( elemMaterial );
elem.appendChild( elemMaterial );
@@ -80,9 +75,6 @@ void Point3DSymbol::writeXml( QDomElement &elem ) const

void Point3DSymbol::readXml( const QDomElement &elem )
{
QDomElement elemDataProperties = elem.firstChildElement( "data" );
height = elemDataProperties.attribute( "height" ).toFloat();

QDomElement elemMaterial = elem.firstChildElement( "material" );
material.readXml( elemMaterial );

@@ -54,7 +54,6 @@ class _3D_EXPORT Point3DSymbol : public Abstract3DSymbol
void writeXml( QDomElement &elem ) const override;
void readXml( const QDomElement &elem ) override;

float height;
PhongMaterialSettings material; //!< Defines appearance of objects
QVariantMap shapeProperties; //!< What kind of shape to use and what
QMatrix4x4 transform; //!< Transform of individual instanced models
@@ -54,7 +54,7 @@ PointEntity::PointEntity( const Map3D &map, QgsVectorLayer *layer, const Point3D
QgsPoint *pt = static_cast<QgsPoint *>( g );
// TODO: use Z coordinates if the point is 3D
float h = map.terrainGenerator()->heightAt( pt->x(), pt->y(), map ) * map.zExaggeration;
positions.append( QVector3D( pt->x() - map.originX, h + symbol.height, -( pt->y() - map.originY ) ) );
positions.append( QVector3D( pt->x() - map.originX, h, -( pt->y() - map.originY ) ) );
//qDebug() << positions.last();
}
else
@@ -141,13 +141,12 @@ int main( int argc, char *argv[] )
pointSymbol->material.setDiffuse( QColor( 222, 184, 135 ) );
pointSymbol->material.setAmbient( pointSymbol->material.diffuse().darker() );
pointSymbol->material.setShininess( 0 );
pointSymbol->height = 2.5;
pointSymbol->shapeProperties["shape"] = "cylinder";
pointSymbol->shapeProperties["radius"] = 1;
pointSymbol->shapeProperties["length"] = 5;
//Qt3DCore::QTransform tr;
//tr.setScale3D(QVector3D(4,1,4));
//pointSymbol->transform = tr.matrix();
Qt3DCore::QTransform tr;
tr.setTranslation( QVector3D( 0, 2.5, 0 ) );
pointSymbol->transform = tr.matrix();
VectorLayer3DRenderer *ptr = new VectorLayer3DRenderer( pointSymbol );
ptr->setLayer( vlPoints );
map.renderers << ptr;
@@ -156,9 +155,11 @@ int main( int argc, char *argv[] )
pointSymbol2->material.setDiffuse( QColor( 60, 179, 113 ) );
pointSymbol2->material.setAmbient( pointSymbol2->material.diffuse().darker() );
pointSymbol2->material.setShininess( 0 );
pointSymbol2->height = 7.5;
pointSymbol2->shapeProperties["shape"] = "sphere";
pointSymbol2->shapeProperties["radius"] = 3.5;
Qt3DCore::QTransform tr2;
tr2.setTranslation( QVector3D( 0, 7.5, 0 ) );
pointSymbol2->transform = tr2.matrix();
VectorLayer3DRenderer *ptr2 = new VectorLayer3DRenderer( pointSymbol2 );
ptr2->setLayer( vlPoints );
map.renderers << ptr2;
@@ -0,0 +1,177 @@
#include "qgspoint3dsymbolwidget.h"

#include "abstract3dsymbol.h"

QgsPoint3DSymbolWidget::QgsPoint3DSymbolWidget( QWidget *parent )
: QWidget( parent )
{
setupUi( this );

cboShape->addItem( tr( "Sphere" ), "sphere" );
cboShape->addItem( tr( "Cylinder" ), "cylinder" );
cboShape->addItem( tr( "Cube" ), "cube" );
cboShape->addItem( tr( "Cone" ), "cone" );
cboShape->addItem( tr( "Plane" ), "plane" );
cboShape->addItem( tr( "Torus" ), "torus" );

setSymbol( Point3DSymbol() );
onShapeChanged();

connect( cboShape, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPoint3DSymbolWidget::onShapeChanged );
QList<QDoubleSpinBox *> spinWidgets;
spinWidgets << spinRadius << spinTopRadius << spinBottomRadius << spinMinorRadius << spinSize << spinLength;
spinWidgets << spinTX << spinTY << spinTZ << spinSX << spinSY << spinSZ << spinRX << spinRY << spinRZ;
Q_FOREACH ( QDoubleSpinBox *spinBox, spinWidgets )
connect( spinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsPoint3DSymbolWidget::changed );
connect( widgetMaterial, &QgsPhongMaterialWidget::changed, this, &QgsPoint3DSymbolWidget::changed );
}

void QgsPoint3DSymbolWidget::setSymbol( const Point3DSymbol &symbol )
{
QVariantMap vm = symbol.shapeProperties;
int index = cboShape->findData( vm["shape"] );
cboShape->setCurrentIndex( index != -1 ? index : 1 ); // use cylinder by default if shape is not set

switch ( cboShape->currentIndex() )
{
case 0: // sphere
spinRadius->setValue( vm["radius"].toDouble() );
break;
case 1: // cylinder
spinRadius->setValue( vm["radius"].toDouble() );
spinLength->setValue( vm["length"].toDouble() );
break;
case 2: // cube
spinSize->setValue( vm["size"].toDouble() );
break;
case 3: // cone
spinTopRadius->setValue( vm["topRadius"].toDouble() );
spinBottomRadius->setValue( vm["bottomRadius"].toDouble() );
spinLength->setValue( vm["length"].toDouble() );
break;
case 4: // plane
spinSize->setValue( vm["size"].toDouble() );
break;
case 5: // torus
spinRadius->setValue( vm["radius"].toDouble() );
spinMinorRadius->setValue( vm["minorRadius"].toDouble() );
break;
}

widgetMaterial->setMaterial( symbol.material );

// decompose the transform matrix
// assuming the last row has values [0 0 0 1]
// see https://math.stackexchange.com/questions/237369/given-this-transformation-matrix-how-do-i-decompose-it-into-translation-rotati
QMatrix4x4 m = symbol.transform;
float *md = m.data(); // returns data in column-major order
float sx = QVector3D( md[0], md[1], md[2] ).length();
float sy = QVector3D( md[4], md[5], md[6] ).length();
float sz = QVector3D( md[8], md[9], md[10] ).length();
float rd[9] =
{
md[0] / sx, md[4] / sy, md[8] / sz,
md[1] / sx, md[5] / sy, md[9] / sz,
md[2] / sx, md[6] / sy, md[10] / sz,
};
QMatrix3x3 rot3x3( rd ); // takes data in row-major order
QVector3D rot = QQuaternion::fromRotationMatrix( rot3x3 ).toEulerAngles();

spinTX->setValue( md[12] );
spinTY->setValue( md[13] );
spinTZ->setValue( md[14] );
spinSX->setValue( sx );
spinSY->setValue( sy );
spinSZ->setValue( sz );
spinRX->setValue( rot.x() );
spinRY->setValue( rot.y() );
spinRZ->setValue( rot.z() );
}

Point3DSymbol QgsPoint3DSymbolWidget::symbol() const
{
QVariantMap vm;
vm["shape"] = cboShape->itemData( cboShape->currentIndex() );

switch ( cboShape->currentIndex() )
{
case 0: // sphere
vm["radius"] = spinRadius->value();
break;
case 1: // cylinder
vm["radius"] = spinRadius->value();
vm["length"] = spinLength->value();
break;
case 2: // cube
vm["size"] = spinSize->value();
break;
case 3: // cone
vm["topRadius"] = spinTopRadius->value();
vm["bottomRadius"] = spinBottomRadius->value();
vm["length"] = spinLength->value();
break;
case 4: // plane
vm["size"] = spinSize->value();
break;
case 5: // torus
vm["radius"] = spinRadius->value();
vm["minorRadius"] = spinMinorRadius->value();
break;
}

QQuaternion rot( QQuaternion::fromEulerAngles( spinRX->value(), spinRY->value(), spinRZ->value() ) );
QVector3D sca( spinSX->value(), spinSY->value(), spinSZ->value() );
QVector3D tra( spinTX->value(), spinTY->value(), spinTZ->value() );

QMatrix4x4 tr;
tr.translate( tra );
tr.scale( sca );
tr.rotate( rot );

Point3DSymbol sym;
sym.shapeProperties = vm;
sym.material = widgetMaterial->material();
sym.transform = tr;
return sym;
}

void QgsPoint3DSymbolWidget::onShapeChanged()
{
QList<QWidget *> allWidgets;
allWidgets << labelSize << spinSize
<< labelRadius << spinRadius
<< labelMinorRadius << spinMinorRadius
<< labelTopRadius << spinTopRadius
<< labelBottomRadius << spinBottomRadius
<< labelLength << spinLength;

QList<QWidget *> activeWidgets;
switch ( cboShape->currentIndex() )
{
case 0: // sphere
activeWidgets << labelRadius << spinRadius;
break;
case 1: // cylinder
activeWidgets << labelRadius << spinRadius << labelLength << spinLength;
break;
case 2: // cube
activeWidgets << labelSize << spinSize;
break;
case 3: // cone
activeWidgets << labelTopRadius << spinTopRadius << labelBottomRadius << spinBottomRadius << labelLength << spinLength;
break;
case 4: // plane
activeWidgets << labelSize << spinSize;
break;
case 5: // torus
activeWidgets << labelRadius << spinRadius << labelMinorRadius << spinMinorRadius;
break;
}

Q_FOREACH ( QWidget *w, allWidgets )
{
w->setVisible( activeWidgets.contains( w ) );
}

emit changed();
}
@@ -0,0 +1,27 @@
#ifndef QGSPOINT3DSYMBOLWIDGET_H
#define QGSPOINT3DSYMBOLWIDGET_H

#include <QWidget>

#include "ui_point3dsymbolwidget.h"

class Point3DSymbol;

//! A widget for configuration of 3D symbol for points
class QgsPoint3DSymbolWidget : public QWidget, private Ui::Point3DSymbolWidget
{
Q_OBJECT
public:
explicit QgsPoint3DSymbolWidget( QWidget *parent = nullptr );

void setSymbol( const Point3DSymbol &symbol );
Point3DSymbol symbol() const;

signals:
void changed();

private slots:
void onShapeChanged();
};

#endif // QGSPOINT3DSYMBOLWIDGET_H
@@ -2,6 +2,7 @@

#include "abstract3dsymbol.h"
#include "qgsline3dsymbolwidget.h"
#include "qgspoint3dsymbolwidget.h"
#include "qgspolygon3dsymbolwidget.h"
#include "vectorlayer3drenderer.h"

@@ -24,14 +25,17 @@ QgsVectorLayer3DRendererWidget::QgsVectorLayer3DRendererWidget( QgsVectorLayer *

widgetUnsupported = new QLabel( tr( "Sorry, this layer is not supported." ), this );
widgetLine = new QgsLine3DSymbolWidget( this );
widgetPoint = new QgsPoint3DSymbolWidget( this );
widgetPolygon = new QgsPolygon3DSymbolWidget( this );

widgetStack->addWidget( widgetUnsupported );
widgetStack->addWidget( widgetLine );
widgetStack->addWidget( widgetPoint );
widgetStack->addWidget( widgetPolygon );

connect( chkEnabled, &QCheckBox::clicked, this, &QgsVectorLayer3DRendererWidget::onEnabledClicked );
connect( widgetLine, &QgsLine3DSymbolWidget::changed, this, &QgsVectorLayer3DRendererWidget::widgetChanged );
connect( widgetPoint, &QgsPoint3DSymbolWidget::changed, this, &QgsVectorLayer3DRendererWidget::widgetChanged );
connect( widgetPolygon, &QgsPolygon3DSymbolWidget::changed, this, &QgsVectorLayer3DRendererWidget::widgetChanged );
}

@@ -61,12 +65,25 @@ void QgsVectorLayer3DRendererWidget::setRenderer( const VectorLayer3DRenderer *r

whileBlocking( chkEnabled )->setChecked( ( bool )mRenderer );
widgetLine->setEnabled( chkEnabled->isChecked() );
widgetPoint->setEnabled( chkEnabled->isChecked() );
widgetPolygon->setEnabled( chkEnabled->isChecked() );

int pageIndex;
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayer );
switch ( vlayer->geometryType() )
{
case QgsWkbTypes::PointGeometry:
pageIndex = 2;
if ( mRenderer && mRenderer->symbol() && mRenderer->symbol()->type() == "point" )
{
whileBlocking( widgetPoint )->setSymbol( *static_cast<const Point3DSymbol *>( mRenderer->symbol() ) );
}
else
{
whileBlocking( widgetPoint )->setSymbol( Point3DSymbol() );
}
break;

case QgsWkbTypes::LineGeometry:
pageIndex = 1;
if ( mRenderer && mRenderer->symbol() && mRenderer->symbol()->type() == "line" )
@@ -80,7 +97,7 @@ void QgsVectorLayer3DRendererWidget::setRenderer( const VectorLayer3DRenderer *r
break;

case QgsWkbTypes::PolygonGeometry:
pageIndex = 2;
pageIndex = 3;
if ( mRenderer && mRenderer->symbol() && mRenderer->symbol()->type() == "polygon" )
{
whileBlocking( widgetPolygon )->setSymbol( *static_cast<const Polygon3DSymbol *>( mRenderer->symbol() ) );
@@ -103,11 +120,13 @@ VectorLayer3DRenderer *QgsVectorLayer3DRendererWidget::renderer()
if ( chkEnabled->isChecked() )
{
int pageIndex = widgetStack->currentIndex();
if ( pageIndex == 1 || pageIndex == 2 )
if ( pageIndex == 1 || pageIndex == 2 || pageIndex == 3 )
{
Abstract3DSymbol *sym;
if ( pageIndex == 1 )
sym = new Line3DSymbol( widgetLine->symbol() );
else if ( pageIndex == 2 )
sym = new Point3DSymbol( widgetPoint->symbol() );
else
sym = new Polygon3DSymbol( widgetPolygon->symbol() );
VectorLayer3DRenderer *r = new VectorLayer3DRenderer( sym );
@@ -136,6 +155,7 @@ void QgsVectorLayer3DRendererWidget::apply()
void QgsVectorLayer3DRendererWidget::onEnabledClicked()
{
widgetLine->setEnabled( chkEnabled->isChecked() );
widgetPoint->setEnabled( chkEnabled->isChecked() );
widgetPolygon->setEnabled( chkEnabled->isChecked() );
emit widgetChanged();
}
@@ -10,6 +10,7 @@ class QLabel;
class QStackedWidget;

class QgsLine3DSymbolWidget;
class QgsPoint3DSymbolWidget;
class QgsPolygon3DSymbolWidget;
class QgsVectorLayer;
class QgsMapCanvas;
@@ -41,6 +42,7 @@ class QgsVectorLayer3DRendererWidget : public QgsMapLayerConfigWidget
QCheckBox *chkEnabled;
QStackedWidget *widgetStack;
QgsLine3DSymbolWidget *widgetLine;
QgsPoint3DSymbolWidget *widgetPoint;
QgsPolygon3DSymbolWidget *widgetPolygon;
QLabel *widgetUnsupported;

@@ -371,6 +371,7 @@ IF (WITH_3D)
3d/qgs3dmapcanvasdockwidget.cpp
3d/qgs3dmapconfigwidget.cpp
3d/qgsline3dsymbolwidget.cpp
3d/qgspoint3dsymbolwidget.cpp
3d/qgspolygon3dsymbolwidget.cpp
3d/qgsphongmaterialwidget.cpp
3d/qgsvectorlayer3drendererwidget.cpp
@@ -382,6 +383,7 @@ IF (WITH_3D)
3d/qgs3dmapcanvasdockwidget.h
3d/qgs3dmapconfigwidget.h
3d/qgsline3dsymbolwidget.h
3d/qgspoint3dsymbolwidget.h
3d/qgspolygon3dsymbolwidget.h
3d/qgsphongmaterialwidget.h
3d/qgsvectorlayer3drendererwidget.h

0 comments on commit 82f608e

Please sign in to comment.
You can’t perform that action at this time.