35 static void make_quad( 
float x0, 
float y0, 
float z0, 
float x1, 
float y1, 
float z1, 
float height, QVector<float> &data, 
bool addNormals )
    38   float dy = -( y1 - y0 );
    41   QVector3D vn( -dy, 0, dx );
    46   data << x0 << z0 + height << -y0;
    48     data << vn.x() << vn.y() << vn.z();
    49   data << x1 << z1 + height << -y1;
    51     data << vn.x() << vn.y() << vn.z();
    52   data << x0 << z0 << -y0;
    54     data << vn.x() << vn.y() << vn.z();
    57   data << x0 << z0 << -y0;
    59     data << vn.x() << vn.y() << vn.z();
    60   data << x1 << z1 + height << -y1;
    62     data << vn.x() << vn.y() << vn.z();
    63   data << x1 << z1 << -y1;
    65     data << vn.x() << vn.y() << vn.z();
    72   , mAddNormals( addNormals )
    73   , mInvertNormals( invertNormals )
    74   , mAddBackFaces( addBackFaces )
    76   mStride = 3 * 
sizeof( float );
    78     mStride += 3 * 
sizeof( float );
    82 static bool _isRingCounterClockWise( 
const QgsCurve &ring )
    89   for ( 
int i = 1; i < count + 1; ++i )
    91     ring.
pointAt( i % count, pt, vt );
    92     a += ptPrev.
x() * pt.
y() - ptPrev.
y() * pt.
x();
    98 static void _makeWalls( 
const QgsCurve &ring, 
bool ccw, 
float extrusionHeight, QVector<float> &data, 
bool addNormals, 
double originX, 
double originY )
   103   bool is_counter_clockwise = _isRingCounterClockWise( ring );
   109   ring.
pointAt( is_counter_clockwise == ccw ? 0 : ring.
numPoints() - 1, ptPrev, vt );
   110   for ( 
int i = 1; i < ring.
numPoints(); ++i )
   112     ring.
pointAt( is_counter_clockwise == ccw ? i : ring.
numPoints() - i - 1, pt, vt );
   113     float x0 = ptPrev.
x() - originX, y0 = ptPrev.
y() - originY;
   114     float x1 = pt.x() - originX, y1 = pt.y() - originY;
   115     float z0 = std::isnan( ptPrev.
z() ) ? 0 : ptPrev.
z();
   116     float z1 = std::isnan( pt.z() ) ? 0 : pt.z();
   119     make_quad( x0, y0, z0, x1, y1, z1, extrusionHeight, data, addNormals );
   124 static QVector3D _calculateNormal( 
const QgsCurve *curve, 
double originX, 
double originY, 
bool invertNormal )
   132     return QVector3D( 0, 0, 1 );
   139   for ( 
int i = 1; i < curve->
numPoints(); i++ )
   142     if ( pt1.
z() != pt2.
z() )
   149     return QVector3D( 0, 0, 1 );
   156   double nx = 0, ny = 0, nz = 0;
   157   for ( 
int i = 0; i < curve->
numPoints() - 1; i++ )
   160     curve->
pointAt( i + 1, pt2, vt );
   163     pt1.
setX( pt1.
x() - originX );
   164     pt1.
setY( pt1.
y() - originY );
   165     pt2.
setX( pt2.
x() - originX );
   166     pt2.
setY( pt2.
y() - originY );
   168     if ( std::isnan( pt1.
z() ) || std::isnan( pt2.
z() ) )
   171     nx += ( pt1.
y() - pt2.
y() ) * ( pt1.
z() + pt2.
z() );
   172     ny += ( pt1.
z() - pt2.
z() ) * ( pt1.
x() + pt2.
x() );
   173     nz += ( pt1.
x() - pt2.
x() ) * ( pt1.
y() + pt2.
y() );
   176   QVector3D normal( nx, ny, nz );
   184 static void _normalVectorToXYVectors( 
const QVector3D &pNormal, QVector3D &pXVector, QVector3D &pYVector )
   189   if ( pNormal.z() > 0.001 || pNormal.z() < -0.001 )
   191     pXVector = QVector3D( 1, 0, -pNormal.x() / pNormal.z() );
   193   else if ( pNormal.y() > 0.001 || pNormal.y() < -0.001 )
   195     pXVector = QVector3D( 1, -pNormal.x() / pNormal.y(), 0 );
   199     pXVector = QVector3D( -pNormal.y() / pNormal.x(), 1, 0 );
   201   pXVector.normalize();
   202   pYVector = QVector3D::normal( pNormal, pXVector );
   206 static void _ringToPoly2tri( 
const QgsCurve *ring, std::vector<p2t::Point *> &polyline, QHash<p2t::Point *, float> &zHash )
   213   polyline.reserve( pCount );
   215   for ( 
int i = 0; i < pCount - 1; ++i )
   218     const float x = pt.
x();
   219     const float y = pt.
y();
   220     const float z = pt.
z();
   222     const bool found = std::find_if( polyline.begin(), polyline.end(), [x, y]( p2t::Point *&p ) { 
return *p == p2t::Point( x, y ); } ) != polyline.end();
   229     p2t::Point *pt2 = 
new p2t::Point( x, y );
   230     polyline.push_back( pt2 );
   238   const double exp = 1e10;   
   239   return round( x * exp ) / exp;
   243 static QgsCurve *_transform_ring_to_new_base( 
const QgsCurve &curve, 
const QgsPoint &pt0, 
const QMatrix4x4 *toNewBase )
   246   QVector<QgsPoint> pts;
   247   pts.reserve( count );
   249   for ( 
int i = 0; i < count; ++i )
   254     QVector4D v( pt2.x(), pt2.y(), pt2.z(), 0 );
   256       v = toNewBase->map( v );
   284 static bool _check_intersecting_rings( 
const QgsPolygon &polygon )
   286   QList<QgsGeometry> geomRings;
   295   for ( 
int i = 0; i < geomRings.count(); ++i )
   297     if ( !geomRings[i].isSimple() )
   320     for ( 
int i = 0; i < geomRings.count(); ++i )
   321       for ( 
int j = i + 1; j < geomRings.count(); ++j )
   323         if ( geomRings[i].intersects( geomRings[j] ) )
   357   const QVector3D pNormal = _calculateNormal( exterior, mOriginX, mOriginY, mInvertNormals );
   358   const int pCount = exterior->
numPoints();
   365     for ( 
int i = 0; i < 3; i++ )
   367       exterior->
pointAt( i, pt, vt );
   368       mData << pt.
x() - mOriginX << pt.
z() << - pt.
y() + mOriginY;
   370         mData << pNormal.x() << pNormal.z() << - pNormal.y();
   376       for ( 
int i = 2; i >= 0; i-- )
   378         exterior->
pointAt( i, pt, vt );
   379         mData << pt.
x() - mOriginX << pt.
z() << - pt.
y() + mOriginY;
   381           mData << -pNormal.x() << -pNormal.z() << pNormal.y();
   390     std::unique_ptr<QMatrix4x4> toNewBase, toOldBase;
   391     if ( pNormal != QVector3D( 0, 0, 1 ) )
   396       QVector3D pXVector, pYVector;
   397       _normalVectorToXYVectors( pNormal, pXVector, pYVector );
   402       toNewBase.reset( 
new QMatrix4x4(
   403                          pXVector.x(), pXVector.y(), pXVector.z(), 0,
   404                          pYVector.x(), pYVector.y(), pYVector.z(), 0,
   405                          pNormal.x(), pNormal.y(), pNormal.z(), 0,
   409       toOldBase.reset( 
new QMatrix4x4( toNewBase->transposed() ) );
   417     std::unique_ptr<QgsPolygon> polygonNew( _transform_polygon_to_new_base( polygon, pt0, toNewBase.get() ) );
   431         QgsMessageLog::logMessage( QObject::tr( 
"geometry's coordinates are too close to each other and simplification failed - skipping" ), QObject::tr( 
"3D" ) );
   436         polygonNew.reset( polygonSimplifiedData->
clone() );
   440     if ( !_check_intersecting_rings( *polygonNew ) )
   443       QgsMessageLog::logMessage( QObject::tr( 
"polygon rings self-intersect or intersect each other - skipping" ), QObject::tr( 
"3D" ) );
   447     QList< std::vector<p2t::Point *> > polylinesToDelete;
   448     QHash<p2t::Point *, float> z;
   451     std::vector<p2t::Point *> polyline;
   452     _ringToPoly2tri( polygonNew->exteriorRing(), polyline, z );
   453     polylinesToDelete << polyline;
   455     std::unique_ptr<p2t::CDT> cdt( 
new p2t::CDT( polyline ) );
   458     for ( 
int i = 0; i < polygonNew->numInteriorRings(); ++i )
   460       std::vector<p2t::Point *> holePolyline;
   461       const QgsCurve *hole = polygonNew->interiorRing( i );
   463       _ringToPoly2tri( hole, holePolyline, z );
   465       cdt->AddHole( holePolyline );
   466       polylinesToDelete << holePolyline;
   474       std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
   476       for ( 
size_t i = 0; i < triangles.size(); ++i )
   478         p2t::Triangle *t = triangles[i];
   479         for ( 
int j = 0; j < 3; ++j )
   481           p2t::Point *p = t->GetPoint( j );
   482           QVector4D pt( p->x, p->y, z[p], 0 );
   484             pt = *toOldBase * pt;
   485           const double fx = pt.x() - mOriginX + pt0.
x();
   486           const double fy = pt.y() - mOriginY + pt0.
y();
   487           const double fz = pt.z() + extrusionHeight + pt0.
z();
   488           mData << fx << fz << -fy;
   490             mData << pNormal.x() << pNormal.z() << - pNormal.y();
   496           for ( 
int j = 2; j >= 0; --j )
   498             p2t::Point *p = t->GetPoint( j );
   499             QVector4D pt( p->x, p->y, z[p], 0 );
   501               pt = *toOldBase * pt;
   502             const double fx = pt.x() - mOriginX + pt0.
x();
   503             const double fy = pt.y() - mOriginY + pt0.
y();
   504             const double fz = pt.z() + extrusionHeight + pt0.
z();
   505             mData << fx << fz << -fy;
   507               mData << -pNormal.x() << -pNormal.z() << pNormal.y();
   517     for ( 
int i = 0; i < polylinesToDelete.count(); ++i )
   518       qDeleteAll( polylinesToDelete[i] );
   522   if ( extrusionHeight != 0 )
   524     _makeWalls( *exterior, 
false, extrusionHeight, mData, mAddNormals, mOriginX, mOriginY );
   527       _makeWalls( *polygon.
interiorRing( i ), 
true, extrusionHeight, mData, mAddNormals, mOriginX, mOriginY );
   545   return mData.size() / ( mAddNormals ? 6 : 3 );
   550   std::unique_ptr< QgsMultiPolygon > mp = qgis::make_unique< QgsMultiPolygon >();
   551   const QVector<float> data = mData;
   552   for ( 
auto it = data.constBegin(); it != data.constEnd(); )
 
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate. 
 
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference) 
 
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon. 
 
A geometry is the spatial representation of a feature. 
 
int dataVerticesCount() const
Returns the number of vertices stored in the output data array. 
 
virtual bool pointAt(int node, QgsPoint &point, QgsVertexId::VertexType &type) const =0
Returns the point and vertex id of a point within the curve. 
 
std::unique_ptr< QgsMultiPolygon > asMultiPolygon() const
Returns the triangulation as a multipolygon geometry. 
 
QgsPoint getPointFromData(QVector< float >::const_iterator &it)
 
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension. 
 
void addInteriorRing(QgsCurve *ring) override
Adds an interior ring to the geometry (takes ownership) 
 
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon. 
 
double _round_coord(double x)
 
void addPolygon(const QgsPolygon &polygon, float extrusionHeight)
Tessellates a triangle and adds its vertex entries to the output data array. 
 
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary). 
 
vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry...
 
T qgsgeometry_cast(const QgsAbstractGeometry *geom)
 
QgsTessellator(double originX, double originY, bool addNormals, bool invertNormals=false, bool addBackFaces=false)
Creates tessellator with a specified origin point of the world (in map coordinates) ...
 
Abstract base class for curved geometry type. 
 
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry. 
 
Point geometry type, with support for z-dimension and m-values. 
 
double _minimum_distance_between_coordinates(const QgsPolygon &polygon)
 
void setX(double x)
Sets the point's x-coordinate. 
 
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive. 
 
void setY(double y)
Sets the point's y-coordinate. 
 
void setExteriorRing(QgsCurve *ring) override
Sets the exterior ring of the polygon. 
 
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy. 
 
Line string geometry type, with support for z-dimension and m-values. 
 
QgsPolygon * clone() const override
Clones the geometry by performing a deep copy. 
 
vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry. 
 
virtual QgsPoint startPoint() const =0
Returns the starting point of the curve. 
 
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring. 
 
virtual int numPoints() const =0
Returns the number of points in the curve.