Skip to content

Commit 7d3cf22

Browse files
PeterPetrikwonder-sk
authored andcommitted
[FEATURE] support 3d models
1 parent e83ce54 commit 7d3cf22

8 files changed

+344
-147
lines changed

src/3d/abstract3dsymbol.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "abstract3dsymbol.h"
2+
#include "qgsreadwritecontext.h"
23

34
#include "qgsxmlutils.h"
45

@@ -70,8 +71,11 @@ void Point3DSymbol::writeXml( QDomElement &elem, const QgsReadWriteContext &cont
7071
material.writeXml( elemMaterial );
7172
elem.appendChild( elemMaterial );
7273

74+
QVariantMap shapePropertiesCopy(shapeProperties);
75+
shapePropertiesCopy["model"] = QVariant(context.pathResolver().writePath(shapePropertiesCopy["model"].toString()));
76+
7377
QDomElement elemShapeProperties = doc.createElement( "shape-properties" );
74-
elemShapeProperties.appendChild( QgsXmlUtils::writeVariant( shapeProperties, doc ) );
78+
elemShapeProperties.appendChild( QgsXmlUtils::writeVariant( shapePropertiesCopy, doc ) );
7579
elem.appendChild( elemShapeProperties );
7680

7781
QDomElement elemTransform = doc.createElement( "transform" );
@@ -88,6 +92,7 @@ void Point3DSymbol::readXml( const QDomElement &elem, const QgsReadWriteContext
8892

8993
QDomElement elemShapeProperties = elem.firstChildElement( "shape-properties" );
9094
shapeProperties = QgsXmlUtils::readVariant( elemShapeProperties.firstChildElement() ).toMap();
95+
shapeProperties["model"] = QVariant(context.pathResolver().readPath(shapeProperties["model"].toString()));
9196

9297
QDomElement elemTransform = elem.firstChildElement( "transform" );
9398
transform = Utils::stringToMatrix4x4( elemTransform.attribute( "matrix" ) );

src/3d/pointentity.cpp

+109-34
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313
#include <Qt3DExtras/QPlaneGeometry>
1414
#include <Qt3DExtras/QSphereGeometry>
1515
#include <Qt3DExtras/QTorusGeometry>
16+
#include <Qt3DExtras/QPhongMaterial>
17+
#include <Qt3DRender/QSceneLoader>
18+
19+
#include <Qt3DRender/QMesh>
20+
1621
#if QT_VERSION >= 0x050900
1722
#include <Qt3DExtras/QExtrudedTextGeometry>
1823
#endif
@@ -26,17 +31,24 @@
2631

2732
#include "qgsvectorlayer.h"
2833
#include "qgspoint.h"
29-
34+
#include "utils.h"
3035

3136

3237
PointEntity::PointEntity( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, Qt3DCore::QNode *parent )
3338
: Qt3DCore::QEntity( parent )
3439
{
35-
addEntityForSelectedPoints( map, layer, symbol );
36-
addEntityForNotSelectedPoints( map, layer, symbol );
40+
if ( symbol.shapeProperties["shape"].toString() == "model" ) {
41+
Model3DPointEntityFactory::addEntitiesForSelectedPoints(map, layer, symbol, this);
42+
Model3DPointEntityFactory::addEntitiesForNotSelectedPoints(map, layer, symbol, this);
43+
} else {
44+
InstancedPointEntityFactory::addEntityForNotSelectedPoints(map, layer, symbol, this);
45+
InstancedPointEntityFactory::addEntityForSelectedPoints(map, layer, symbol, this);
46+
}
3747
}
3848

39-
Qt3DRender::QMaterial *PointEntity::material( const Point3DSymbol &symbol ) const
49+
//* INSTANCED RENDERING *//
50+
51+
Qt3DRender::QMaterial *InstancedPointEntityFactory::material( const Point3DSymbol &symbol )
4052
{
4153
Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey;
4254
filterKey->setName( "renderingStyle" );
@@ -105,7 +117,7 @@ Qt3DRender::QMaterial *PointEntity::material( const Point3DSymbol &symbol ) cons
105117
return material;
106118
}
107119

108-
void PointEntity::addEntityForSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol )
120+
void InstancedPointEntityFactory::addEntityForSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, PointEntity* parent )
109121
{
110122
// build the default material
111123
Qt3DRender::QMaterial *mat = material( symbol );
@@ -125,12 +137,12 @@ void PointEntity::addEntityForSelectedPoints( const Map3D &map, QgsVectorLayer *
125137
req.setFilterFids( layer->selectedFeatureIds() );
126138

127139
// build the entity
128-
PointEntityNode *entity = new PointEntityNode( map, layer, symbol, req );
140+
InstancedPointEntityNode *entity = new InstancedPointEntityNode( map, layer, symbol, req );
129141
entity->addComponent( mat );
130-
entity->setParent( this );
142+
entity->setParent( parent );
131143
}
132144

133-
void PointEntity::addEntityForNotSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol )
145+
void InstancedPointEntityFactory::addEntityForNotSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, PointEntity* parent )
134146
{
135147
// build the default material
136148
Qt3DRender::QMaterial *mat = material( symbol );
@@ -144,19 +156,19 @@ void PointEntity::addEntityForNotSelectedPoints( const Map3D &map, QgsVectorLaye
144156
req.setFilterFids( notSelected );
145157

146158
// build the entity
147-
PointEntityNode *entity = new PointEntityNode( map, layer, symbol, req );
159+
InstancedPointEntityNode *entity = new InstancedPointEntityNode( map, layer, symbol, req );
148160
entity->addComponent( mat );
149-
entity->setParent( this );
161+
entity->setParent( parent );
150162
}
151163

152-
PointEntityNode::PointEntityNode( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, const QgsFeatureRequest &req, Qt3DCore::QNode *parent )
164+
InstancedPointEntityNode::InstancedPointEntityNode( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, const QgsFeatureRequest &req, Qt3DCore::QNode *parent )
153165
: Qt3DCore::QEntity( parent )
154166
{
155-
QList<QVector3D> pos = positions( map, layer, req );
167+
QList<QVector3D> pos = Utils::positions( map, layer, req );
156168
addComponent( renderer( symbol, pos ) );
157169
}
158170

159-
Qt3DRender::QGeometryRenderer *PointEntityNode::renderer( const Point3DSymbol &symbol, const QList<QVector3D> &positions ) const
171+
Qt3DRender::QGeometryRenderer *InstancedPointEntityNode::renderer( const Point3DSymbol &symbol, const QList<QVector3D> &positions ) const
160172
{
161173
int count = positions.count();
162174

@@ -263,28 +275,91 @@ Qt3DRender::QGeometryRenderer *PointEntityNode::renderer( const Point3DSymbol &s
263275
return renderer;
264276
}
265277

266-
QList<QVector3D> PointEntityNode::positions( const Map3D &map, const QgsVectorLayer *layer, const QgsFeatureRequest &request ) const
278+
//* 3D MODEL RENDERING *//
279+
280+
static Qt3DExtras::QPhongMaterial* phongMaterial(const Point3DSymbol &symbol) {
281+
Qt3DExtras::QPhongMaterial* phong = new Qt3DExtras::QPhongMaterial;
282+
283+
phong->setAmbient(symbol.material.ambient());
284+
phong->setDiffuse(symbol.material.diffuse());
285+
phong->setSpecular(symbol.material.specular());
286+
phong->setShininess(symbol.material.shininess());
287+
288+
return phong;
289+
}
290+
291+
void Model3DPointEntityFactory::addEntitiesForSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, PointEntity* parent )
267292
{
268-
QList<QVector3D> positions;
269-
QgsFeature f;
270-
QgsFeatureIterator fi = layer->getFeatures( request );
271-
while ( fi.nextFeature( f ) )
272-
{
273-
if ( f.geometry().isNull() )
274-
continue;
275-
276-
QgsAbstractGeometry *g = f.geometry().geometry();
277-
if ( QgsWkbTypes::flatType( g->wkbType() ) == QgsWkbTypes::Point )
278-
{
279-
QgsPoint *pt = static_cast<QgsPoint *>( g );
280-
// TODO: use Z coordinates if the point is 3D
281-
float h = map.terrainGenerator()->heightAt( pt->x(), pt->y(), map ) * map.terrainVerticalScale();
282-
positions.append( QVector3D( pt->x() - map.originX, h, -( pt->y() - map.originY ) ) );
283-
//qDebug() << positions.last();
284-
}
285-
else
286-
qDebug() << "not a point";
293+
QgsFeatureRequest req;
294+
req.setDestinationCrs( map.crs );
295+
req.setFilterFids( layer->selectedFeatureIds() );
296+
297+
addMeshEntities(map, layer, req, symbol, parent, true);
298+
}
299+
300+
301+
302+
void Model3DPointEntityFactory::addEntitiesForNotSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, PointEntity* parent )
303+
{
304+
// build the feature request to select features
305+
QgsFeatureRequest req;
306+
req.setDestinationCrs( map.crs );
307+
QgsFeatureIds notSelected = layer->allFeatureIds();
308+
notSelected.subtract( layer->selectedFeatureIds() );
309+
req.setFilterFids( notSelected );
310+
311+
if (symbol.shapeProperties["overwriteMaterial"].toBool()) {
312+
addMeshEntities(map, layer, req, symbol, parent, false);
313+
} else {
314+
addSceneEntities(map, layer, req, symbol, parent);
287315
}
316+
}
317+
318+
void Model3DPointEntityFactory::addSceneEntities(const Map3D &map, QgsVectorLayer *layer, const QgsFeatureRequest &req, const Point3DSymbol &symbol, PointEntity* parent) {
319+
QList<QVector3D> positions = Utils::positions( map, layer, req );
320+
Q_FOREACH(const QVector3D& position, positions) {
321+
// build the entity
322+
Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
323+
324+
QUrl url = QUrl::fromLocalFile(symbol.shapeProperties["model"].toString());
325+
Qt3DRender::QSceneLoader * modelLoader = new Qt3DRender::QSceneLoader;
326+
modelLoader->setSource(url);
327+
328+
entity->addComponent( modelLoader );
329+
entity->addComponent(transform(position, symbol));
330+
entity->setParent( parent );
331+
}
332+
}
333+
334+
void Model3DPointEntityFactory::addMeshEntities(const Map3D &map, QgsVectorLayer *layer, const QgsFeatureRequest &req, const Point3DSymbol &symbol, PointEntity* parent, bool are_selected) {
335+
// build the default material
336+
Qt3DExtras::QPhongMaterial *mat = phongMaterial(symbol);
337+
338+
if (are_selected) {
339+
mat->setDiffuse(map.selectionColor());
340+
mat->setAmbient(map.selectionColor().darker());
341+
}
342+
343+
// get nodes
344+
QList<QVector3D> positions = Utils::positions( map, layer, req );
345+
Q_FOREACH(const QVector3D& position, positions) {
346+
// build the entity
347+
Qt3DCore::QEntity *entity = new Qt3DCore::QEntity;
348+
349+
QUrl url = QUrl::fromLocalFile(symbol.shapeProperties["model"].toString());
350+
Qt3DRender::QMesh * mesh = new Qt3DRender::QMesh;
351+
mesh->setSource(url);
352+
353+
entity->addComponent( mesh );
354+
entity->addComponent( mat );
355+
entity->addComponent(transform(position, symbol));
356+
entity->setParent( parent );
357+
}
358+
}
288359

289-
return positions;
360+
Qt3DCore::QTransform* Model3DPointEntityFactory::transform(const QVector3D& position, const Point3DSymbol &symbol) {
361+
Qt3DCore::QTransform* tr = new Qt3DCore::QTransform;
362+
tr->setMatrix(symbol.transform);
363+
tr->setTranslation(position + tr->translation());
364+
return tr;
290365
}

src/3d/pointentity.h

+24-7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <Qt3DCore/QEntity>
55
#include <Qt3DRender/QMaterial>
66
#include <Qt3DRender/QGeometryRenderer>
7+
#include <Qt3DCore/QTransform>
78

89
class Map3D;
910
class Point3DSymbol;
@@ -17,22 +18,38 @@ class PointEntity : public Qt3DCore::QEntity
1718
{
1819
public:
1920
PointEntity( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, Qt3DCore::QNode *parent = nullptr );
21+
};
2022

21-
private:
22-
void addEntityForSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol );
23-
void addEntityForNotSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol );
23+
class InstancedPointEntityFactory
24+
{
25+
public:
26+
static void addEntityForSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, PointEntity* parent);
27+
static void addEntityForNotSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, PointEntity* parent);
2428

25-
Qt3DRender::QMaterial *material( const Point3DSymbol &symbol ) const;
29+
private:
30+
static Qt3DRender::QMaterial *material( const Point3DSymbol &symbol);
2631
};
2732

28-
class PointEntityNode : public Qt3DCore::QEntity
33+
class InstancedPointEntityNode : public Qt3DCore::QEntity
2934
{
3035
public:
31-
PointEntityNode( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, const QgsFeatureRequest &req, Qt3DCore::QNode *parent = nullptr );
36+
InstancedPointEntityNode( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, const QgsFeatureRequest &req, Qt3DCore::QNode *parent = nullptr );
3237

3338
private:
3439
Qt3DRender::QGeometryRenderer *renderer( const Point3DSymbol &symbol, const QList<QVector3D> &positions ) const;
35-
QList<QVector3D> positions( const Map3D &map, const QgsVectorLayer *layer, const QgsFeatureRequest &req ) const;
40+
};
41+
42+
class Model3DPointEntityFactory
43+
{
44+
public:
45+
static void addEntitiesForSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, PointEntity* parent);
46+
static void addEntitiesForNotSelectedPoints( const Map3D &map, QgsVectorLayer *layer, const Point3DSymbol &symbol, PointEntity* parent);
47+
48+
private:
49+
static void addSceneEntities(const Map3D &map, QgsVectorLayer *layer, const QgsFeatureRequest &req, const Point3DSymbol &symbol, PointEntity* parent);
50+
static void addMeshEntities(const Map3D &map, QgsVectorLayer *layer, const QgsFeatureRequest &req, const Point3DSymbol &symbol, PointEntity* parent, bool are_selected);
51+
52+
static Qt3DCore::QTransform* transform(const QVector3D& position, const Point3DSymbol &symbol);
3653
};
3754

3855
#endif // POINTENTITY_H

src/3d/utils.cpp

+30
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
#include "qgslinestring.h"
44
#include "qgspolygon.h"
5+
#include "qgsfeaturerequest.h"
6+
#include "qgsfeatureiterator.h"
7+
#include "qgsfeature.h"
8+
#include "qgsabstractgeometry.h"
9+
#include "qgsvectorlayer.h"
510

611
#include "terraingenerator.h"
712

@@ -189,3 +194,28 @@ bool Utils::isCullable( const AABB &bbox, const QMatrix4x4 &viewProjectionMatrix
189194
}
190195
return out;
191196
}
197+
198+
QList<QVector3D> Utils::positions(const Map3D &map, QgsVectorLayer *layer, const QgsFeatureRequest &request) {
199+
QList<QVector3D> positions;
200+
QgsFeature f;
201+
QgsFeatureIterator fi = layer->getFeatures( request );
202+
while ( fi.nextFeature( f ) )
203+
{
204+
if ( f.geometry().isNull() )
205+
continue;
206+
207+
QgsAbstractGeometry *g = f.geometry().geometry();
208+
if ( QgsWkbTypes::flatType( g->wkbType() ) == QgsWkbTypes::Point )
209+
{
210+
QgsPoint *pt = static_cast<QgsPoint *>( g );
211+
// TODO: use Z coordinates if the point is 3D
212+
float h = map.terrainGenerator()->heightAt( pt->x(), pt->y(), map ) * map.terrainVerticalScale();
213+
positions.append( QVector3D( pt->x() - map.originX, h, -( pt->y() - map.originY ) ) );
214+
//qDebug() << positions.last();
215+
}
216+
else
217+
qDebug() << "not a point";
218+
}
219+
220+
return positions;
221+
}

src/3d/utils.h

+5
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ class _3D_EXPORT Utils
5151
This is used to perform object culling checks.
5252
*/
5353
static bool isCullable(const AABB &bbox, const QMatrix4x4 &viewProjectionMatrix );
54+
55+
/*
56+
* Calculates (x,y,z) position of point in the Point vector layers
57+
*/
58+
static QList<QVector3D> positions(const Map3D &map, QgsVectorLayer *layer, const QgsFeatureRequest &req);
5459
};
5560

5661
#endif // UTILS_H

0 commit comments

Comments
 (0)