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 );
612 mData << static_cast<float>( fx ) <<
static_cast<float>( fy ) <<
static_cast<float>( fz );
614 mData << normal.x() << normal.y() << normal.z();
618 mData << static_cast<float>( fx ) <<
static_cast<float>( fz ) <<
static_cast<float>( -fy );
620 mData << normal.x() << normal.z() << - normal.y();
624 if ( mAddTextureCoords )
626 const std::pair<float, float> pr = rotateCoords(
static_cast<float>( pt.x() ),
static_cast<float>( pt.y() ), 0.0f, 0.0f, mTextureRotation );
627 mData << pr.first << pr.second;
632void QgsTessellator::ringToEarcutPoints(
const QgsLineString *ring, std::vector<std::array<double, 2>> &polyline, QHash<std::array<double, 2>*,
float> *zHash )
636 polyline.reserve( pCount );
638 const double *srcXData = ring->
xData();
639 const double *srcYData = ring->
yData();
640 const double *srcZData = ring->
zData();
643 for (
int i = 0; i < pCount - 1; ++i )
645 const float x =
static_cast<float>( *srcXData++ );
646 const float y =
static_cast<float>( *srcYData++ );
648 std::array<double, 2> pt = { x, y };
649 polyline.push_back( pt );
651 if ( zHash && srcZData )
653 ( *zHash )[ &pt ] = *srcZData++;
658std::vector<QVector3D> QgsTessellator::generateConstrainedDelaunayTriangles(
const QgsPolygon *polygonNew )
660 QList<std::vector<p2t::Point *>> polylinesToDelete;
661 QHash<p2t::Point *, float> z;
664 std::vector<p2t::Point *> polyline;
666 polylinesToDelete << polyline;
668 p2t::CDT cdt = p2t::CDT( polyline );
673 std::vector<p2t::Point *> holePolyline;
676 _ringToPoly2tri( hole, holePolyline, mInputZValueIgnored ?
nullptr : &z );
678 cdt.AddHole( holePolyline );
679 polylinesToDelete << holePolyline;
683 std::vector<p2t::Triangle *> triangles = cdt.GetTriangles();
685 std::vector<QVector3D> trianglePoints;
686 trianglePoints.reserve( triangles.size() * 3 );
688 for ( p2t::Triangle *t : triangles )
690 trianglePoints.emplace_back( t->GetPoint( 0 )->x / mScale, t->GetPoint( 0 )->y / mScale, z.value( t->GetPoint( 0 ) ) );
691 trianglePoints.emplace_back( t->GetPoint( 1 )->x / mScale, t->GetPoint( 1 )->y / mScale, z.value( t->GetPoint( 1 ) ) );
692 trianglePoints.emplace_back( t->GetPoint( 2 )->x / mScale, t->GetPoint( 2 )->y / mScale, z.value( t->GetPoint( 2 ) ) );
695 for (
int i = 0; i < polylinesToDelete.count(); ++i )
696 qDeleteAll( polylinesToDelete[i] );
698 return trianglePoints;
701std::vector<QVector3D> QgsTessellator::generateEarcutTriangles(
const QgsPolygon *polygonNew )
703 QHash<std::array<double, 2>*,
float> z;
704 std::vector<std::vector<std::array<double, 2>>> rings;
705 std::vector<std::array<double, 2>> polyline;
708 rings.push_back( polyline );
712 std::vector<std::array<double, 2>> holePolyline;
714 rings.push_back( holePolyline );
717 std::vector<std::array<double, 2>> points;
718 for (
const auto &ring : rings )
720 points.insert( points.end(), ring.begin(), ring.end() );
723 std::vector<uint32_t> indices = mapbox::earcut<uint32_t>( rings );
724 std::vector<QVector3D> trianglePoints;
725 trianglePoints.reserve( points.size() );
727 for (
size_t i = 0; i < indices.size(); i++ )
729 uint32_t vertexIndex = indices[ i ];
730 std::array<double, 2> vertex = points[ vertexIndex ];
732 double x = vertex[ 0 ];
733 double y = vertex[ 1 ];
735 float zValue = z.value( &vertex, 0.0f );
737 trianglePoints.emplace_back( x / mScale, y / mScale, zValue );
740 return trianglePoints;
749 const QVector3D pNormal = !mInputZValueIgnored ? calculateNormal( exterior, mOrigin.x(), mOrigin.y(), mOrigin.z(), mInvertNormals, extrusionHeight ) : QVector3D();
750 const int pCount = exterior->
numPoints();
757 std::unique_ptr<QgsPolygon> polygonNew;
759 if ( !mInputZValueIgnored && !
qgsDoubleNear( pNormal.length(), 1, 0.001 ) )
766 if ( buildFloor || buildRoof )
768 calculateBaseTransform( pNormal, &base );
769 polygonNew.reset( _transform_polygon_to_new_base( polygon, extrusionOrigin, &base, mScale ) );
772 base = base.transposed();
776 Q_ASSERT( polygonNew->exteriorRing()->numPoints() >= 3 );
779 const QVector3D p1(
static_cast<float>( triangle->
xAt( 0 ) ),
static_cast<float>( triangle->
yAt( 0 ) ),
static_cast<float>( triangle->
zAt( 0 ) ) );
780 const QVector3D p2(
static_cast<float>( triangle->
xAt( 1 ) ),
static_cast<float>( triangle->
yAt( 1 ) ),
static_cast<float>( triangle->
zAt( 1 ) ) );
781 const QVector3D p3(
static_cast<float>( triangle->
xAt( 2 ) ),
static_cast<float>( triangle->
yAt( 2 ) ),
static_cast<float>( triangle->
zAt( 2 ) ) );
782 const std::array<QVector3D, 3> points = { { p1, p2, p3 } };
784 addTriangleVertices( points, pNormal, extrusionHeight, &base, &extrusionOrigin,
false );
788 addTriangleVertices( points, pNormal, extrusionHeight, &base, &extrusionOrigin,
true );
791 if ( extrusionHeight != 0 && buildFloor )
793 addTriangleVertices( points, pNormal, 0, &base, &extrusionOrigin,
false );
796 addTriangleVertices( points, pNormal, 0, &base, &extrusionOrigin,
true );
809 if ( polygonSimplified.
isNull() )
811 mError = QObject::tr(
"geometry simplification failed - skipping" );
819 mError = QObject::tr(
"geometry's coordinates are too close to each other and simplification failed - skipping" );
824 polygonNew.reset( polygonSimplifiedData->
clone() );
831 std::vector<QVector3D> trianglePoints;
833 switch ( mTriangulationAlgorithm )
836 trianglePoints = generateConstrainedDelaunayTriangles( polygonNew.get() );
839 trianglePoints = generateEarcutTriangles( polygonNew.get() );
844 if ( trianglePoints.empty() )
846 mError = QObject::tr(
"Failed to triangulate polygon." );
850 Q_ASSERT( trianglePoints.size() % 3 == 0 );
852 mData.reserve( mData.size() + trianglePoints.size() * 3 * (
stride() /
sizeof(
float ) ) );
854 for (
size_t i = 0; i < trianglePoints.size(); i += 3 )
856 const QVector3D p1 = trianglePoints[ i + 0 ];
857 const QVector3D p2 = trianglePoints[ i + 1 ];
858 const QVector3D p3 = trianglePoints[ i + 2 ];
859 const std::array<QVector3D, 3> points = { { p1, p2, p3 } };
861 addTriangleVertices( points, pNormal, extrusionHeight, &base, &extrusionOrigin,
false );
865 addTriangleVertices( points, pNormal, extrusionHeight, &base, &extrusionOrigin,
true );
868 if ( extrusionHeight != 0 && buildFloor )
870 addTriangleVertices( points, pNormal, 0, &base, &extrusionOrigin,
true );
873 addTriangleVertices( points, pNormal, 0, &base, &extrusionOrigin,
false );
878 catch ( std::runtime_error &err )
884 mError = QObject::tr(
"An unknown error occurred" );
890 if ( extrusionHeight != 0 && buildWalls )
892 _makeWalls( *exterior,
false, extrusionHeight, mData, mAddNormals, mAddTextureCoords, mOrigin.x(), mOrigin.y(), mOrigin.z(), mTextureRotation, mOutputZUp );
895 _makeWalls( *
qgsgeometry_cast< const QgsLineString * >( polygon.
interiorRing( i ) ),
true, extrusionHeight, mData, mAddNormals, mAddTextureCoords, mOrigin.x(), mOrigin.y(), mOrigin.z(), mTextureRotation, mOutputZUp );
901 if ( mData.size() == 0 )
904 return mData.size() / (
stride() /
sizeof( float ) );
909 auto mp = std::make_unique< QgsMultiPolygon >();
910 const auto nVals = mData.size();
911 mp->reserve( nVals / 9 );
912 for (
auto i =
decltype( nVals ) {0}; i + 8 < nVals; i += 9 )
916 const QgsPoint p1( mData[i + 0], mData[i + 1], mData[i + 2] );
917 const QgsPoint p2( mData[i + 3], mData[i + 4], mData[i + 5] );
918 const QgsPoint p3( mData[i + 6], mData[i + 7], mData[i + 8] );
924 const QgsPoint p1( mData[i + 0], -mData[i + 2], mData[i + 1] );
925 const QgsPoint p2( mData[i + 3], -mData[i + 5], mData[i + 4] );
926 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