Skip to content

Commit

Permalink
misc optimization for geometries and fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterPetrik committed May 30, 2018
1 parent f26bbd9 commit 7af2e68
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 89 deletions.
66 changes: 66 additions & 0 deletions python/core/auto_generated/qgstessellator.sip.in
@@ -0,0 +1,66 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgstessellator.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/





class QgsTessellator
{
%Docstring
Class that takes care of tessellation of polygons into triangles.

It is expected that client code will create the tessellator object, then repeatedly call
addPolygon() method that will generate triangles, and finally call data() to get final vertex data.

Optionally provides extrusion by adding triangles that serve as walls when extrusion height is non-zero.

.. versionadded:: 3.4
%End

%TypeHeaderCode
#include "qgstessellator.h"
%End
public:
QgsTessellator( double originX, double originY, bool addNormals, bool invertNormals = false, bool addBackFaces = false );
%Docstring
Creates tessellator with a specified origin point of the world (in map coordinates)
%End

void addPolygon( const QgsPolygon &polygon, float extrusionHeight );
%Docstring
Tessellates a triangle and adds its vertex entries to the output data array
%End

QVector<float> data() const;
%Docstring
Returns array of triangle vertex data

Vertice coordinates are stored as (x, z, -y)
%End

int dataVerticesCount() const;
%Docstring
Return number of vertices stored in the output data array
%End

int stride() const;
%Docstring
Returns size of one vertex entry in bytes
%End


};

/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgstessellator.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
1 change: 1 addition & 0 deletions python/core/core_auto.sip
Expand Up @@ -348,6 +348,7 @@
%Include auto_generated/qgsrunprocess.sip
%Include auto_generated/qgssnappingconfig.sip
%Include auto_generated/qgstaskmanager.sip
%Include auto_generated/qgstessellator.sip
%Include auto_generated/qgstolerance.sip
%Include auto_generated/qgstrackedvectorlayertools.sip
%Include auto_generated/qgstransaction.sip
Expand Down
5 changes: 5 additions & 0 deletions src/core/qgstessellator.cpp
Expand Up @@ -540,6 +540,11 @@ QgsPoint getPointFromData( QVector< float >::const_iterator &it )
return QgsPoint( x, y, z );
}

int QgsTessellator::dataVerticesCount() const
{
return mData.size() / 3;
}

std::unique_ptr<QgsMultiPolygon> QgsTessellator::asMultiPolygon() const
{
std::unique_ptr< QgsMultiPolygon > mp = qgis::make_unique< QgsMultiPolygon >();
Expand Down
16 changes: 12 additions & 4 deletions src/core/qgstessellator.h
Expand Up @@ -16,15 +16,15 @@
#ifndef QGSTESSELLATOR_H
#define QGSTESSELLATOR_H

#define SIP_NO_FILE

#include "qgis_core.h"
#include "qgis.h"

class QgsPolygon;
class QgsMultiPolygon;

#include <QVector>
#include <memory>
#include "qgspoint.h"

/**
* \ingroup core
Expand All @@ -46,15 +46,23 @@ class CORE_EXPORT QgsTessellator
//! Tessellates a triangle and adds its vertex entries to the output data array
void addPolygon( const QgsPolygon &polygon, float extrusionHeight );

//! Returns array of triangle vertex data
/**
* Returns array of triangle vertex data
*
* Vertice coordinates are stored as (x, z, -y)
*/
QVector<float> data() const { return mData; }

//! Return number of vertices stored in the output data array
int dataVerticesCount() const;

//! Returns size of one vertex entry in bytes
int stride() const { return mStride; }

/**
* Returns the triangulation as a multipolygon geometry.
*/
std::unique_ptr< QgsMultiPolygon > asMultiPolygon() const;
std::unique_ptr< QgsMultiPolygon > asMultiPolygon() const SIP_SKIP;

private:
double mOriginX = 0, mOriginY = 0;
Expand Down
21 changes: 14 additions & 7 deletions src/quickgui/qgsquickfeaturehighlight.cpp
Expand Up @@ -29,7 +29,7 @@ QgsQuickFeatureHighlight::QgsQuickFeatureHighlight( QQuickItem *parent )
setAntialiasing( true );

// transform to device coords
mTransform.appendToItem(this);
mTransform.appendToItem( this );

connect( this, &QgsQuickFeatureHighlight::mapSettingsChanged, this, &QgsQuickFeatureHighlight::onMapSettingsChanged );
connect( this, &QgsQuickFeatureHighlight::featureLayerPairChanged, this, &QgsQuickFeatureHighlight::markDirty );
Expand All @@ -45,7 +45,7 @@ void QgsQuickFeatureHighlight::markDirty()

void QgsQuickFeatureHighlight::onMapSettingsChanged()
{
mTransform.setMapSettings(mMapSettings);
mTransform.setMapSettings( mMapSettings );
markDirty();
}

Expand All @@ -65,12 +65,19 @@ QSGNode *QgsQuickFeatureHighlight::updatePaintNode( QSGNode *n, QQuickItem::Upda
if ( feature.hasGeometry() )
{
QgsGeometry geom( feature.geometry() );
geom.transform( transf );
std::unique_ptr<QgsQuickHighlightSGNode> rb( new QgsQuickHighlightSGNode( geom, mColor, mWidth ) );
rb->setFlag( QSGNode::OwnedByParent );
n->appendChildNode( rb.release() );
try
{
geom.transform( transf );
std::unique_ptr<QgsQuickHighlightSGNode> rb( new QgsQuickHighlightSGNode( geom, mColor, mWidth ) );
rb->setFlag( QSGNode::OwnedByParent );
n->appendChildNode( rb.release() );
}
catch ( QgsCsException &e )
{
Q_UNUSED( e );
// Caught an error in transform
}
}

mDirty = false;

return n;
Expand Down
114 changes: 60 additions & 54 deletions src/quickgui/qgsquickhighlightsgnode.cpp
Expand Up @@ -14,70 +14,65 @@
***************************************************************************/

#include "qgsquickhighlightsgnode.h"

#include "qgstessellator.h"
#include "qgsmultipolygon.h"
#include "qgsgeometrycollection.h"
#include "qgsgeometry.h"
#include "qgstriangle.h"
#include "qgslinestring.h"
#include "qgspoint.h"
#include "qgspolygon.h"

QgsQuickHighlightSGNode::QgsQuickHighlightSGNode( const QgsGeometry &geom,
const QColor &color, float width )
: QSGNode()
, mWidth( width )
{
mMaterial.setColor( color );
handleGeometryCollection( geom );
handleGeometryCollection( geom.constGet(), geom.type() );
}

void QgsQuickHighlightSGNode::handleGeometryCollection( const QgsGeometry &geom )
void QgsQuickHighlightSGNode::handleGeometryCollection( const QgsAbstractGeometry *geom, QgsWkbTypes::GeometryType type )
{
const QgsGeometryCollection *collection = qgsgeometry_cast<const QgsGeometryCollection *>( geom.constGet() );
const QgsGeometryCollection *collection = qgsgeometry_cast<const QgsGeometryCollection *>( geom );
if ( collection && !collection->isEmpty() )
{
for ( int i = 0; i < collection->numGeometries(); ++i )
{
QgsGeometry geomN( collection->geometryN( i )->clone() );
handleSingleGeometry( geomN );
const QgsAbstractGeometry *geomN = collection->geometryN( i );
handleSingleGeometry( geomN, type );
}
}
else
{
handleSingleGeometry( geom );
handleSingleGeometry( geom, type );
}
}

void QgsQuickHighlightSGNode::handleSingleGeometry( const QgsGeometry &geom )
void QgsQuickHighlightSGNode::handleSingleGeometry( const QgsAbstractGeometry *geom, QgsWkbTypes::GeometryType type )
{
Q_ASSERT( !geom.isMultipart() );

switch ( geom.type() )
switch ( type )
{
case QgsWkbTypes::PointGeometry:
{
QVector<QgsPoint> points;
for ( auto it = geom.vertices_begin(); it != geom.vertices_end(); ++it )
points.append( *it );

if ( !points.isEmpty() )
appendChildNode( createPointGeometry( points.at( 0 ) ) );
const QgsPoint *point = qgsgeometry_cast<const QgsPoint *>( geom );
if ( point )
appendChildNode( createPointGeometry( point ) );
break;
}

case QgsWkbTypes::LineGeometry:
{
QVector<QgsPoint> points;
for ( auto it = geom.vertices_begin(); it != geom.vertices_end(); ++it )
points.append( *it );

appendChildNode( createLineGeometry( points ) );
const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( geom );
if ( line )
appendChildNode( createLineGeometry( line ) );
break;
}

case QgsWkbTypes::PolygonGeometry:
{
const QgsPolygon *poly = qgsgeometry_cast<const QgsPolygon *>( geom.constGet() );
const QgsPolygon *poly = qgsgeometry_cast<const QgsPolygon *>( geom );
if ( poly )
appendChildNode( createPolygonGeometry( *poly ) );
appendChildNode( createPolygonGeometry( poly ) );
break;
}

Expand All @@ -87,18 +82,22 @@ void QgsQuickHighlightSGNode::handleSingleGeometry( const QgsGeometry &geom )
}
}

QSGGeometryNode *QgsQuickHighlightSGNode::createLineGeometry( const QVector<QgsPoint> &points )
QSGGeometryNode *QgsQuickHighlightSGNode::createLineGeometry( const QgsLineString *line )
{
Q_ASSERT( line );

std::unique_ptr<QSGGeometryNode> node = qgis::make_unique< QSGGeometryNode>();
std::unique_ptr<QSGGeometry> sgGeom = qgis::make_unique< QSGGeometry>( QSGGeometry::defaultAttributes_Point2D(), points.count() );
std::unique_ptr<QSGGeometry> sgGeom = qgis::make_unique< QSGGeometry>( QSGGeometry::defaultAttributes_Point2D(), line->numPoints() );
QSGGeometry::Point2D *vertices = sgGeom->vertexDataAsPoint2D();

int i = 0;
for ( const QgsPoint &pt : points )
const double *x = line->xData();
const double *y = line->yData();

for ( int i = 0; i < line->numPoints(); ++i )
{
vertices[i++].set(
static_cast< float >( pt.x() ),
static_cast< float >( pt.y() )
vertices[i].set(
static_cast< float >( x[i] ),
static_cast< float >( y[i] )
);
}

Expand All @@ -111,15 +110,17 @@ QSGGeometryNode *QgsQuickHighlightSGNode::createLineGeometry( const QVector<QgsP
return node.release();
}

QSGGeometryNode *QgsQuickHighlightSGNode::createPointGeometry( const QgsPoint &point )
QSGGeometryNode *QgsQuickHighlightSGNode::createPointGeometry( const QgsPoint *point )
{
Q_ASSERT( point );

std::unique_ptr<QSGGeometryNode> node = qgis::make_unique< QSGGeometryNode>();
std::unique_ptr<QSGGeometry> sgGeom = qgis::make_unique<QSGGeometry>( QSGGeometry::defaultAttributes_Point2D(), 1 );

QSGGeometry::Point2D *vertices = sgGeom->vertexDataAsPoint2D();
vertices[0].set(
static_cast< float >( point.x() ),
static_cast< float >( point.y() )
static_cast< float >( point->x() ),
static_cast< float >( point->y() )
);
sgGeom->setDrawingMode( GL_POINTS );
sgGeom->setLineWidth( mWidth );
Expand All @@ -131,33 +132,38 @@ QSGGeometryNode *QgsQuickHighlightSGNode::createPointGeometry( const QgsPoint &p
return node.release();
}

QSGGeometryNode *QgsQuickHighlightSGNode::createPolygonGeometry( const QgsPolygon &polygon )
QSGGeometryNode *QgsQuickHighlightSGNode::createPolygonGeometry( const QgsPolygon *polygon )
{
QgsRectangle bounds = polygon.boundingBox();
QgsTessellator tes( bounds.xMinimum(), bounds.yMinimum(), false, false, false );
std::unique_ptr< QgsPolygon > p( qgsgeometry_cast< QgsPolygon * >( polygon.segmentize() ) );
tes.addPolygon( *p.get(), 0.0 );
Q_ASSERT( polygon );

std::unique_ptr<QgsMultiPolygon> triangles = tes.asMultiPolygon();
int ntris = triangles->numGeometries();
const QgsRectangle bounds = polygon->boundingBox();
QgsTessellator tes( bounds.xMinimum(), bounds.yMinimum(), false, false, false );
tes.addPolygon( *polygon, 0.0 );

QSGGeometryNode *node = new QSGGeometryNode;
QSGGeometry *sgGeom = new QSGGeometry( QSGGeometry::defaultAttributes_Point2D(), ntris * 3 );
QSGGeometry *sgGeom = new QSGGeometry( QSGGeometry::defaultAttributes_Point2D(), tes.dataVerticesCount() );

QSGGeometry::Point2D *vertices = sgGeom->vertexDataAsPoint2D();

for ( int j = 0; j < ntris; j++ )
// we need to revert translation in tessellator
float translateX = static_cast< float >( bounds.xMinimum() );
float translateY = static_cast< float >( bounds.yMinimum() );

const QVector<float> data = tes.data();
int i = 0;
for ( auto it = data.constBegin(); it != data.constEnd(); )
{
const QgsTriangle *triangle = qgsgeometry_cast<const QgsTriangle *>( triangles->geometryN( j ) );
if ( triangle )
{
for ( int v = 0; v < 3; ++v )
{
const QgsPoint vertex = triangle->vertexAt( v );
vertices[3 * j + v].x = static_cast< float >( vertex.x() + bounds.xMinimum() ) ;
vertices[3 * j + v].y = static_cast< float >( vertex.y() + bounds.yMinimum() );
}
}
float x = *it;
vertices[i].x = translateX + x;
++it;

++it; // we do not need z coordinate

float y = -( *it );
vertices[i].y = translateY + y;
++it;

++i;
}
sgGeom->setDrawingMode( GL_TRIANGLES );
node->setGeometry( sgGeom );
Expand Down

0 comments on commit 7af2e68

Please sign in to comment.