20#include <unordered_set>
37static std::pair<float, float> rotateCoords(
float x,
float y,
float origin_x,
float origin_y,
float r )
39 r = qDegreesToRadians( r );
40 float x0 = x - origin_x, y0 = y - origin_y;
44 const float x1 = origin_x + x0 * qCos( r ) - y0 * qSin( r );
45 const float y1 = origin_y + x0 * qSin( r ) + y0 * qCos( r );
46 return std::make_pair( x1, y1 );
49static void make_quad(
float x0,
float y0,
float z0,
float x1,
float y1,
float z1,
float height, QVector<float> &data,
bool addNormals,
bool addTextureCoords,
float textureRotation,
bool zUp )
51 const float dx = x1 - x0;
52 const float dy = y1 - y0;
55 QVector3D vn = zUp ? QVector3D( -dy, dx, 0 ) : QVector3D( -dy, 0, -dx );
63 QVector<double> textureCoordinates;
64 textureCoordinates.reserve( 12 );
66 if ( fabsf( dy ) <= fabsf( dx ) )
97 textureCoordinates.push_back( u0 );
98 textureCoordinates.push_back( v0 );
100 textureCoordinates.push_back( u1 );
101 textureCoordinates.push_back( v1 );
103 textureCoordinates.push_back( u2 );
104 textureCoordinates.push_back( v2 );
106 textureCoordinates.push_back( u2 );
107 textureCoordinates.push_back( v2 );
109 textureCoordinates.push_back( u1 );
110 textureCoordinates.push_back( v1 );
112 textureCoordinates.push_back( u3 );
113 textureCoordinates.push_back( v3 );
115 for (
int i = 0; i < textureCoordinates.size(); i += 2 )
117 const std::pair<float, float> rotated = rotateCoords( textureCoordinates[i], textureCoordinates[i + 1], 0, 0, textureRotation );
118 textureCoordinates[i] = rotated.first;
119 textureCoordinates[i + 1] = rotated.second;
125 data << x0 << y0 << z0 + height;
127 data << x0 << z0 + height << -y0;
129 data << vn.x() << vn.y() << vn.z();
130 if ( addTextureCoords )
131 data << textureCoordinates[0] << textureCoordinates[1];
134 data << x1 << y1 << z1 + height;
136 data << x1 << z1 + height << -y1;
138 data << vn.x() << vn.y() << vn.z();
139 if ( addTextureCoords )
140 data << textureCoordinates[2] << textureCoordinates[3];
143 data << x0 << y0 << z0;
145 data << x0 << z0 << -y0;
147 data << vn.x() << vn.y() << vn.z();
148 if ( addTextureCoords )
149 data << textureCoordinates[4] << textureCoordinates[5];
154 data << x0 << y0 << z0;
156 data << x0 << z0 << -y0;
158 data << vn.x() << vn.y() << vn.z();
159 if ( addTextureCoords )
160 data << textureCoordinates[6] << textureCoordinates[7];
163 data << x1 << y1 << z1 + height;
165 data << x1 << z1 + height << -y1;
167 data << vn.x() << vn.y() << vn.z();
168 if ( addTextureCoords )
169 data << textureCoordinates[8] << textureCoordinates[9];
172 data << x1 << y1 << z1;
174 data << x1 << z1 << -y1;
176 data << vn.x() << vn.y() << vn.z();
177 if ( addTextureCoords )
178 data << textureCoordinates[10] << textureCoordinates[11];
189 setExtrusionFacesLegacy( facade );
200 setExtrusionFacesLegacy( facade );
217 mScale = bounds.
isNull() ? 1.0 : std::max( 10000.0 / bounds.
width(), 10000.0 / bounds.
height() );
222 mInputZValueIgnored = ignore;
227 mExtrusionFaces = faces;
230void QgsTessellator::setExtrusionFacesLegacy(
int facade )
256 mTextureRotation = rotation;
261 mAddBackFaces = addBackFaces;
266 mInvertNormals = invertNormals;
271 mAddNormals = addNormals;
277 mAddTextureCoords = addTextureUVs;
286void QgsTessellator::updateStride()
288 mStride = 3 *
sizeof( float );
290 mStride += 3 *
sizeof( float );
291 if ( mAddTextureCoords )
292 mStride += 2 *
sizeof( float );
295static void _makeWalls(
const QgsLineString &ring,
bool ccw,
float extrusionHeight, QVector<float> &data,
296 bool addNormals,
bool addTextureCoords,
double originX,
double originY,
double originZ,
float textureRotation,
bool zUp )
305 for (
int i = 1; i < ring.
numPoints(); ++i )
307 pt = ring.
pointN( is_counter_clockwise == ccw ? i : ring.
numPoints() - i - 1 );
308 const double x0 = ptPrev.
x() - originX, y0 = ptPrev.
y() - originY;
309 const double x1 = pt.
x() - originX, y1 = pt.
y() - originY;
310 const double z0 = std::isnan( ptPrev.
z() ) ? 0.0 : ptPrev.
z() - originZ;
311 const double z1 = std::isnan( pt.
z() ) ? 0.0 : pt.
z() - originZ;
314 make_quad(
static_cast<float>( x0 ),
static_cast<float>( y0 ),
static_cast<float>( z0 ),
static_cast<float>( x1 ),
static_cast<float>( y1 ),
static_cast<float>( z1 ), extrusionHeight, data, addNormals, addTextureCoords, textureRotation, zUp );
319static QVector3D calculateNormal(
const QgsLineString *curve,
double originX,
double originY,
double originZ,
bool invertNormal,
float extrusionHeight )
324 if ( extrusionHeight != 0 )
325 return QVector3D( 0, 0, 1 );
328 float orientation = 1.f;
330 orientation = -orientation;
332 orientation = -orientation;
333 return QVector3D( 0, 0, orientation );
341 for (
int i = 1; i < curve->
numPoints(); i++ )
344 if ( pt1.
z() != pt2.
z() )
350 if ( sameZ && extrusionHeight != 0 )
351 return QVector3D( 0, 0, 1 );
358 double nx = 0, ny = 0, nz = 0;
361 pt1.
setX( pt1.
x() - originX );
362 pt1.
setY( pt1.
y() - originY );
363 pt1.
setZ( std::isnan( pt1.
z() ) ? 0.0 : pt1.
z() - originZ );
364 for (
int i = 1; i < curve->
numPoints(); i++ )
367 pt2.
setX( pt2.
x() - originX );
368 pt2.
setY( pt2.
y() - originY );
369 pt2.
setZ( std::isnan( pt2.
z() ) ? 0.0 : pt2.
z() - originZ );
371 nx += ( pt1.
y() - pt2.
y() ) * ( pt1.
z() + pt2.
z() );
372 ny += ( pt1.
z() - pt2.
z() ) * ( pt1.
x() + pt2.
x() );
373 nz += ( pt1.
x() - pt2.
x() ) * ( pt1.
y() + pt2.
y() );
378 QVector3D normal( nx, ny, nz );
386static void _normalVectorToXYVectors(
const QVector3D &pNormal, QVector3D &pXVector, QVector3D &pYVector )
391 if ( pNormal.z() > 0.001 || pNormal.z() < -0.001 )
393 pXVector = QVector3D( 1, 0, -pNormal.x() / pNormal.z() );
395 else if ( pNormal.y() > 0.001 || pNormal.y() < -0.001 )
397 pXVector = QVector3D( 1, -pNormal.x() / pNormal.y(), 0 );
401 pXVector = QVector3D( -pNormal.y() / pNormal.x(), 1, 0 );
403 pXVector.normalize();
404 pYVector = QVector3D::normal( pNormal, pXVector );
409 std::size_t
operator()(
const std::pair<float, float> pair )
const
411 const std::size_t h1 = std::hash<float>()( pair.first );
412 const std::size_t h2 = std::hash<float>()( pair.second );
418static void _ringToPoly2tri(
const QgsLineString *ring, std::vector<p2t::Point *> &polyline, QHash<p2t::Point *, float> *zHash )
422 polyline.reserve( pCount );
424 const double *srcXData = ring->
xData();
425 const double *srcYData = ring->
yData();
426 const double *srcZData = ring->
zData();
427 std::unordered_set<std::pair<float, float>,
float_pair_hash> foundPoints;
429 for (
int i = 0; i < pCount - 1; ++i )
431 const float x = *srcXData++;
432 const float y = *srcYData++;
434 const auto res = foundPoints.insert( std::make_pair( x, y ) );
441 p2t::Point *pt2 =
new p2t::Point( x, y );
442 polyline.push_back( pt2 );
445 ( *zHash )[pt2] = *srcZData++;
453 const double exp = 1e10;
454 return round( x * exp ) / exp;
458static QgsCurve *_transform_ring_to_new_base(
const QgsLineString &curve,
const QgsPoint &pt0,
const QMatrix4x4 *toNewBase,
const float scale )
467 double *xData = x.data();
468 double *yData = y.data();
469 double *zData = z.data();
471 const double *srcXData = curve.
xData();
472 const double *srcYData = curve.
yData();
473 const double *srcZData = curve.
is3D() ? curve.
zData() :
nullptr;
475 for (
int i = 0; i < count; ++i )
477 QVector4D v( *srcXData++ - pt0.
x(),
478 *srcYData++ - pt0.
y(),
479 srcZData ? *srcZData++ - pt0.
z() : 0,
482 v = toNewBase->map( v );
485 v.setX( v.x() * scale );
486 v.setY( v.y() * scale );
506static QgsPolygon *_transform_polygon_to_new_base(
const QgsPolygon &polygon,
const QgsPoint &pt0,
const QMatrix4x4 *toNewBase,
const float scale )
520 std::vector< const QgsLineString * > rings;
529 if ( numPoints <= 1 )
532 const double *srcXData = ring->
xData();
533 const double *srcYData = ring->
yData();
534 double x0 = *srcXData++;
535 double y0 = *srcYData++;
536 for (
int i = 1; i < numPoints; ++i )
538 const double x1 = *srcXData++;
539 const double y1 = *srcYData++;
548 return min_d != 1e20 ? std::sqrt( min_d ) : 1e20;
551void QgsTessellator::calculateBaseTransform(
const QVector3D &pNormal, QMatrix4x4 *base )
const
553 if ( !mInputZValueIgnored && pNormal != QVector3D( 0, 0, 1 ) )
557 QVector3D pXVector, pYVector;
558 _normalVectorToXYVectors( pNormal, pXVector, pYVector );
564 pXVector.x(), pXVector.y(), pXVector.z(), 0,
565 pYVector.x(), pYVector.y(), pYVector.z(), 0,
566 pNormal.x(), pNormal.y(), pNormal.z(), 0,
571 base->setToIdentity();
575void QgsTessellator::addTriangleVertices(
576 const std::array<QVector3D, 3> &points,
578 float extrusionHeight,
579 QMatrix4x4 *transformMatrix,
585 const QVector3D normal = reverse ? -pNormal : pNormal;
586 for (
int i = 0; i < 3; ++i )
588 const int index = reverse ? 2 - i : i;
591 QVector3D point = points[ index ];
592 const float z = mInputZValueIgnored ? 0.0f : point.z();
593 QVector4D pt( point.x(), point.y(), z, 0 );
595 pt = *transformMatrix * pt;
597 const double fx = pt.
x() - mOrigin.x() + originOffset->
x();
598 const double fy = pt.y() - mOrigin.y() + originOffset->
y();
599 const double baseHeight = mInputZValueIgnored ? 0 : pt.z() - mOrigin.z() + originOffset->
z();
600 const double fz = mInputZValueIgnored ? 0.0 : ( baseHeight + extrusionHeight );
602 if ( baseHeight < mZMin )
603 mZMin =
static_cast<float>( baseHeight );
604 if ( baseHeight > mZMax )
605 mZMax =
static_cast<float>( baseHeight );
607 mZMax =
static_cast<float>( fz );
611 mData << static_cast<float>( fx ) <<
static_cast<float>( fy ) <<
static_cast<float>( fz );
613 mData << normal.x() << normal.y() << normal.z();
617 mData << static_cast<float>( fx ) <<
static_cast<float>( fz ) <<
static_cast<float>( -fy );
619 mData << normal.x() << normal.z() << - normal.y();
622 if ( mAddTextureCoords )
624 const std::pair<float, float> pr = rotateCoords(
static_cast<float>( pt.x() ),
static_cast<float>( pt.y() ), 0.0f, 0.0f, mTextureRotation );
625 mData << pr.first << pr.second;
630void QgsTessellator::ringToEarcutPoints(
const QgsLineString *ring, std::vector<std::array<double, 2>> &polyline, QHash<std::array<double, 2>*,
float> *zHash )
634 polyline.reserve( pCount );
636 const double *srcXData = ring->
xData();
637 const double *srcYData = ring->
yData();
638 const double *srcZData = ring->
zData();
641 for (
int i = 0; i < pCount - 1; ++i )
643 const float x =
static_cast<float>( *srcXData++ );
644 const float y =
static_cast<float>( *srcYData++ );
646 std::array<double, 2> pt = { x, y };
647 polyline.push_back( pt );
649 if ( zHash && srcZData )
651 ( *zHash )[ &pt ] = *srcZData++;
656std::vector<QVector3D> QgsTessellator::generateConstrainedDelaunayTriangles(
const QgsPolygon *polygonNew )
658 QList<std::vector<p2t::Point *>> polylinesToDelete;
659 QHash<p2t::Point *, float> z;
662 std::vector<p2t::Point *> polyline;
664 polylinesToDelete << polyline;
666 p2t::CDT cdt = p2t::CDT( polyline );
671 std::vector<p2t::Point *> holePolyline;
674 _ringToPoly2tri( hole, holePolyline, mInputZValueIgnored ?
nullptr : &z );
676 cdt.AddHole( holePolyline );
677 polylinesToDelete << holePolyline;
681 std::vector<p2t::Triangle *> triangles = cdt.GetTriangles();
683 std::vector<QVector3D> trianglePoints;
684 trianglePoints.reserve( triangles.size() * 3 );
686 for ( p2t::Triangle *t : triangles )
688 trianglePoints.emplace_back( t->GetPoint( 0 )->x / mScale, t->GetPoint( 0 )->y / mScale, z.value( t->GetPoint( 0 ) ) );
689 trianglePoints.emplace_back( t->GetPoint( 1 )->x / mScale, t->GetPoint( 1 )->y / mScale, z.value( t->GetPoint( 1 ) ) );
690 trianglePoints.emplace_back( t->GetPoint( 2 )->x / mScale, t->GetPoint( 2 )->y / mScale, z.value( t->GetPoint( 2 ) ) );
693 for (
int i = 0; i < polylinesToDelete.count(); ++i )
694 qDeleteAll( polylinesToDelete[i] );
696 return trianglePoints;
699std::vector<QVector3D> QgsTessellator::generateEarcutTriangles(
const QgsPolygon *polygonNew )
701 QHash<std::array<double, 2>*,
float> z;
702 std::vector<std::vector<std::array<double, 2>>> rings;
703 std::vector<std::array<double, 2>> polyline;
706 rings.push_back( polyline );
710 std::vector<std::array<double, 2>> holePolyline;
712 rings.push_back( holePolyline );
715 std::vector<std::array<double, 2>> points;
716 for (
const auto &ring : rings )
718 points.insert( points.end(), ring.begin(), ring.end() );
721 std::vector<uint32_t> indices = mapbox::earcut<uint32_t>( rings );
722 std::vector<QVector3D> trianglePoints;
723 trianglePoints.reserve( points.size() );
725 for (
size_t i = 0; i < indices.size(); i++ )
727 uint32_t vertexIndex = indices[ i ];
728 std::array<double, 2> vertex = points[ vertexIndex ];
730 double x = vertex[ 0 ];
731 double y = vertex[ 1 ];
733 float zValue = z.value( &vertex, 0.0f );
735 trianglePoints.emplace_back( x / mScale, y / mScale, zValue );
738 return trianglePoints;
747 const QVector3D pNormal = !mInputZValueIgnored ? calculateNormal( exterior, mOrigin.x(), mOrigin.y(), mOrigin.z(), mInvertNormals, extrusionHeight ) : QVector3D();
748 const int pCount = exterior->
numPoints();
755 std::unique_ptr<QgsPolygon> polygonNew;
757 if ( !mInputZValueIgnored && !
qgsDoubleNear( pNormal.length(), 1, 0.001 ) )
764 if ( buildFloor || buildRoof )
766 calculateBaseTransform( pNormal, &base );
767 polygonNew.reset( _transform_polygon_to_new_base( polygon, extrusionOrigin, &base, mScale ) );
770 base = base.transposed();
774 Q_ASSERT( polygonNew->exteriorRing()->numPoints() >= 3 );
777 const QVector3D p1(
static_cast<float>( triangle->
xAt( 0 ) ),
static_cast<float>( triangle->
yAt( 0 ) ),
static_cast<float>( triangle->
zAt( 0 ) ) );
778 const QVector3D p2(
static_cast<float>( triangle->
xAt( 1 ) ),
static_cast<float>( triangle->
yAt( 1 ) ),
static_cast<float>( triangle->
zAt( 1 ) ) );
779 const QVector3D p3(
static_cast<float>( triangle->
xAt( 2 ) ),
static_cast<float>( triangle->
yAt( 2 ) ),
static_cast<float>( triangle->
zAt( 2 ) ) );
780 const std::array<QVector3D, 3> points = { { p1, p2, p3 } };
782 addTriangleVertices( points, pNormal, extrusionHeight, &base, &extrusionOrigin,
false );
786 addTriangleVertices( points, pNormal, extrusionHeight, &base, &extrusionOrigin,
true );
789 if ( extrusionHeight != 0 && buildFloor )
791 addTriangleVertices( points, pNormal, 0, &base, &extrusionOrigin,
false );
794 addTriangleVertices( points, pNormal, 0, &base, &extrusionOrigin,
true );
807 if ( polygonSimplified.
isNull() )
809 mError = QObject::tr(
"geometry simplification failed - skipping" );
817 mError = QObject::tr(
"geometry's coordinates are too close to each other and simplification failed - skipping" );
822 polygonNew.reset( polygonSimplifiedData->
clone() );
829 std::vector<QVector3D> trianglePoints;
830 switch ( mTriangulationAlgorithm )
833 trianglePoints = generateConstrainedDelaunayTriangles( polygonNew.get() );
836 trianglePoints = generateEarcutTriangles( polygonNew.get() );
840 if ( trianglePoints.empty() )
842 mError = QObject::tr(
"Failed to triangulate polygon." );
846 Q_ASSERT( trianglePoints.size() % 3 == 0 );
848 mData.reserve( mData.size() + trianglePoints.size() * 3 * (
stride() /
sizeof(
float ) ) );
850 for (
size_t i = 0; i < trianglePoints.size(); i += 3 )
852 const QVector3D p1 = trianglePoints[ i + 0 ];
853 const QVector3D p2 = trianglePoints[ i + 1 ];
854 const QVector3D p3 = trianglePoints[ i + 2 ];
855 const std::array<QVector3D, 3> points = { { p1, p2, p3 } };
857 addTriangleVertices( points, pNormal, extrusionHeight, &base, &extrusionOrigin,
false );
861 addTriangleVertices( points, pNormal, extrusionHeight, &base, &extrusionOrigin,
true );
864 if ( extrusionHeight != 0 && buildFloor )
866 addTriangleVertices( points, pNormal, 0, &base, &extrusionOrigin,
true );
869 addTriangleVertices( points, pNormal, 0, &base, &extrusionOrigin,
false );
874 catch ( std::runtime_error &err )
880 mError = QObject::tr(
"An unknown error occurred" );
886 if ( extrusionHeight != 0 && buildWalls )
888 _makeWalls( *exterior,
false, extrusionHeight, mData, mAddNormals, mAddTextureCoords, mOrigin.x(), mOrigin.y(), mOrigin.z(), mTextureRotation, mOutputZUp );
891 _makeWalls( *
qgsgeometry_cast< const QgsLineString * >( polygon.
interiorRing( i ) ),
true, extrusionHeight, mData, mAddNormals, mAddTextureCoords, mOrigin.x(), mOrigin.y(), mOrigin.z(), mTextureRotation, mOutputZUp );
897 if ( mData.size() == 0 )
900 return mData.size() / (
stride() /
sizeof( float ) );
905 auto mp = std::make_unique< QgsMultiPolygon >();
906 const auto nVals = mData.size();
907 mp->reserve( nVals / 9 );
908 for (
auto i =
decltype( nVals ) {0}; i + 8 < nVals; i += 9 )
912 const QgsPoint p1( mData[i + 0], mData[i + 1], mData[i + 2] );
913 const QgsPoint p2( mData[i + 3], mData[i + 4], mData[i + 5] );
914 const QgsPoint p3( mData[i + 6], mData[i + 7], mData[i + 8] );
920 const QgsPoint p1( mData[i + 0], -mData[i + 2], mData[i + 1] );
921 const QgsPoint p2( mData[i + 3], -mData[i + 5], mData[i + 4] );
922 const QgsPoint p3( mData[i + 6], -mData[i + 8], mData[i + 7] );
@ CounterClockwise
Counter-clockwise direction.
@ Clockwise
Clockwise direction.
TriangulationAlgorithm
Triangulation algorithms.
QFlags< ExtrusionFace > ExtrusionFaces
Tessellator extrusion face types.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
Abstract base class for curved geometry type.
Qgis::AngularDirection orientation() const
Returns the curve's orientation, e.g.
static double sqrDistance2D(double x1, double y1, double x2, double y2)
Returns the squared 2D distance between (x1, y1) and (x2, y2).
A geometry is the spatial representation of a feature.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsGeometry simplify(double tolerance) const
Returns a simplified version of this geometry using a specified tolerance value.
Line string geometry type, with support for z-dimension and m-values.
const double * yData() const
Returns a const pointer to the y vertex data.
const double * xData() const
Returns a const pointer to the x vertex data.
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values.
QgsPoint startPoint() const override
Returns the starting point of the curve.
int numPoints() const override
Returns the number of points in the curve.
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
double zAt(int index) const override
Returns the z-coordinate of the specified node in the line string.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
Point geometry type, with support for z-dimension and m-values.
void setY(double y)
Sets the point's y-coordinate.
void setX(double x)
Sets the point's x-coordinate.
void setZ(double z)
Sets the point's z-coordinate.
void setExteriorRing(QgsCurve *ring) override
Sets the exterior ring of the polygon.
void addInteriorRing(QgsCurve *ring) override
Adds an interior ring to the geometry (takes ownership).
QgsPolygon * clone() const override
Clones the geometry by performing a deep copy.
A rectangle specified with double values.
std::unique_ptr< QgsMultiPolygon > asMultiPolygon() const
Returns the triangulation as a multipolygon geometry.
float textureRotation() const
Returns the rotation of texture UV coordinates (in degrees).
void setTextureRotation(float rotation)
Sets the rotation of texture UV coordinates (in degrees).
void setOrigin(const QgsVector3D &origin)
Sets the origin point of the map.
void setTriangulationAlgorithm(Qgis::TriangulationAlgorithm algorithm)
Sets the triangulation algorithm.
int stride() const
Returns size of one vertex entry in bytes.
void setBounds(const QgsRectangle &bounds)
Sets scaling and the bounds of the input geometry coordinates.
void addPolygon(const QgsPolygon &polygon, float extrusionHeight)
Tessellates a triangle and adds its vertex entries to the output data array.
QgsVector3D origin() const
Returns the origin point of the map.
void setInvertNormals(bool invertNormals)
Sets whether normals should be inverted (true) or not (false).
void setBackFacesEnabled(bool addBackFaces)
Sets whether back faces should be added to the output data (true) or not (false).
int dataVerticesCount() const
Returns the number of vertices stored in the output data array.
void setExtrusionFaces(Qgis::ExtrusionFaces faces)
Sets which faces should be generated during extrusion.
void setInputZValueIgnored(bool ignore)
Sets whether Z values from the input geometries are ignored (true) or not (false).
void setAddTextureUVs(bool addTextureUVs)
Sets whether texture UV coordinates should be added to the output data (true) or not (false).
void setAddNormals(bool addNormals)
Sets whether normals should be added to the output data (true) or not (false).
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
static Q_INVOKABLE bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
T qgsgeometry_cast(QgsAbstractGeometry *geom)
double _round_coord(double x)
double _minimum_distance_between_coordinates(const QgsPolygon &polygon)
std::size_t operator()(const std::pair< float, float > pair) const