20#include <unordered_set>
37void QgsTessellator::addExtrusionWallQuad(
const QVector3D &pt1,
const QVector3D &pt2,
float height,
float u1,
float u2 )
39 const float dx = pt2.x() - pt1.x();
40 const float dy = pt2.y() - pt1.y();
43 QVector3D vn = QVector3D( -dy, dx, 0 );
50 QVector3D tangentDir( dx, dy, 0 );
51 tangentDir.normalize();
57 tangentDir = -tangentDir;
60 vt = QVector4D( tangentDir.x(), tangentDir.y(), tangentDir.z(), 1.0f );
68 const float v0 = -height;
69 const float v1 = -height;
70 const float v2 = 0.0f;
71 const float v3 = 0.0f;
75 mData << pt1.x() << pt1.y() << pt1.z() + height;
77 mData << vn.x() << vn.y() << vn.z();
79 mData << vt.x() << vt.y() << vt.z() << vt.w();
80 if ( mAddTextureCoords )
85 mData << pt2.x() << pt2.y() << pt2.z() + height;
87 mData << vn.x() << vn.y() << vn.z();
89 mData << vt.x() << vt.y() << vt.z() << vt.w();
90 if ( mAddTextureCoords )
95 mData << pt1.x() << pt1.y() << pt1.z();
97 mData << vn.x() << vn.y() << vn.z();
99 mData << vt.x() << vt.y() << vt.z() << vt.w();
100 if ( mAddTextureCoords )
111 mData << pt2.x() << pt2.y() << pt2.z();
113 mData << vn.x() << vn.y() << vn.z();
115 mData << vt.x() << vt.y() << vt.z() << vt.w();
116 if ( mAddTextureCoords )
122QgsTessellator::QgsTessellator(
double originX,
double originY,
bool addNormals,
bool invertNormals,
bool addBackFaces,
bool noZ,
bool addTextureCoords,
int facade,
float )
127 setExtrusionFacesLegacy( facade );
136 setExtrusionFacesLegacy( facade );
152 mScale = bounds.
isNull() ? 1.0 : std::max( 10000.0 / bounds.
width(), 10000.0 / bounds.
height() );
157 mInputZValueIgnored = ignore;
162 mExtrusionFaces = faces;
165void QgsTessellator::setExtrusionFacesLegacy(
int facade )
194 mAddBackFaces = addBackFaces;
199 mInvertNormals = invertNormals;
204 mAddNormals = addNormals;
210 mAddTangents = addTangents;
216 mAddTextureCoords = addTextureUVs;
228void QgsTessellator::updateStride()
230 mStride = 3 *
sizeof( float );
232 mStride += 3 *
sizeof( float );
234 mStride += 4 *
sizeof( float );
235 if ( mAddTextureCoords )
236 mStride += 2 *
sizeof( float );
239void QgsTessellator::makeWalls(
const QgsLineString &ring,
bool ccw,
float extrusionHeight )
251 float accumulatedU = 0.0f;
252 for (
int i = 1; i < ring.
numPoints(); ++i )
256 const QVector3D pt1(
static_cast<float>( ptPrev.
x() - mOrigin.x() ),
static_cast<float>( ptPrev.
y() - mOrigin.y() ),
static_cast<float>( std::isnan( ptPrev.
z() ) ? 0 : ptPrev.
z() - mOrigin.z() ) );
258 const QVector3D pt2(
static_cast<float>( pt.
x() - mOrigin.x() ),
static_cast<float>( pt.
y() - mOrigin.y() ),
static_cast<float>( std::isnan( pt.
z() ) ? 0 : pt.
z() - mOrigin.z() ) );
260 const float segmentLength = pt1.distanceToPoint( pt2 );
263 addExtrusionWallQuad( pt1, pt2, extrusionHeight, -accumulatedU, -( accumulatedU + segmentLength ) );
268 addExtrusionWallQuad( pt2, pt1, extrusionHeight, accumulatedU + segmentLength, accumulatedU );
271 accumulatedU += segmentLength;
276static QVector3D calculateNormal(
const QgsLineString *curve,
double originX,
double originY,
double originZ,
bool invertNormal,
float extrusionHeight )
281 if ( extrusionHeight != 0 )
282 return QVector3D( 0, 0, 1 );
285 float orientation = 1.f;
287 orientation = -orientation;
289 orientation = -orientation;
290 return QVector3D( 0, 0, orientation );
298 for (
int i = 1; i < curve->
numPoints(); i++ )
301 if ( pt1.
z() != pt2.
z() )
307 if ( sameZ && extrusionHeight != 0 )
308 return QVector3D( 0, 0, 1 );
315 double nx = 0, ny = 0, nz = 0;
318 pt1.
setX( pt1.
x() - originX );
319 pt1.
setY( pt1.
y() - originY );
320 pt1.
setZ( std::isnan( pt1.
z() ) ? 0.0 : pt1.
z() - originZ );
321 for (
int i = 1; i < curve->
numPoints(); i++ )
324 pt2.
setX( pt2.
x() - originX );
325 pt2.
setY( pt2.
y() - originY );
326 pt2.
setZ( std::isnan( pt2.
z() ) ? 0.0 : pt2.
z() - originZ );
328 nx += ( pt1.
y() - pt2.
y() ) * ( pt1.
z() + pt2.
z() );
329 ny += ( pt1.
z() - pt2.
z() ) * ( pt1.
x() + pt2.
x() );
330 nz += ( pt1.
x() - pt2.
x() ) * ( pt1.
y() + pt2.
y() );
335 QVector3D normal( nx, ny, nz );
343static void normalVectorToXYVectors(
const QVector3D &pNormal, QVector3D &pXVector, QVector3D &pYVector )
348 if ( pNormal.z() > 0.001 || pNormal.z() < -0.001 )
350 pXVector = QVector3D( 1, 0, -pNormal.x() / pNormal.z() );
352 else if ( pNormal.y() > 0.001 || pNormal.y() < -0.001 )
354 pXVector = QVector3D( 1, -pNormal.x() / pNormal.y(), 0 );
358 pXVector = QVector3D( -pNormal.y() / pNormal.x(), 1, 0 );
360 pXVector.normalize();
361 pYVector = QVector3D::normal( pNormal, pXVector );
366 std::size_t
operator()(
const std::pair<float, float> pair )
const
368 const std::size_t h1 = std::hash<float>()( pair.first );
369 const std::size_t h2 = std::hash<float>()( pair.second );
379 polyline.reserve( pCount );
381 const double *srcXData = ring->
xData();
382 const double *srcYData = ring->
yData();
383 const double *srcZData = ring->
zData();
384 std::unordered_set<std::pair<float, float>,
float_pair_hash> foundPoints;
386 for (
int i = 0; i < pCount - 1; ++i )
388 const float x = *srcXData++;
389 const float y = *srcYData++;
391 const auto res = foundPoints.insert( std::make_pair( x, y ) );
398 p2t::Point *pt2 =
new p2t::Point( x, y );
399 polyline.push_back( pt2 );
402 ( *zHash )[pt2] = *srcZData++;
410 const double exp = 1e10;
411 return round( x * exp ) / exp;
424 double *xData = x.data();
425 double *yData = y.data();
426 double *zData = z.data();
428 const double *srcXData = curve.
xData();
429 const double *srcYData = curve.
yData();
430 const double *srcZData = curve.
is3D() ? curve.
zData() :
nullptr;
432 for (
int i = 0; i < count; ++i )
434 QVector4D v( *srcXData++ - pt0.
x(), *srcYData++ - pt0.
y(), srcZData ? *srcZData++ - pt0.
z() : 0, 0 );
436 v = toNewBase->map( v );
439 v.setX( v.x() * scale );
440 v.setY( v.y() * scale );
474 std::vector< const QgsLineString * > rings;
483 if ( numPoints <= 1 )
486 const double *srcXData = ring->
xData();
487 const double *srcYData = ring->
yData();
488 double x0 = *srcXData++;
489 double y0 = *srcYData++;
490 for (
int i = 1; i < numPoints; ++i )
492 const double x1 = *srcXData++;
493 const double y1 = *srcYData++;
502 return min_d != 1e20 ? std::sqrt( min_d ) : 1e20;
507 return QByteArray(
reinterpret_cast<const char *
>( mData.constData() ),
sizeof(
float ) * mData.size() );
512 return QByteArray(
reinterpret_cast<const char *
>( mIndexBuffer.constData() ),
sizeof( uint32_t ) * mIndexBuffer.size() );
515void QgsTessellator::calculateBaseTransform(
const QVector3D &pNormal, QMatrix4x4 *base )
const
517 if ( !mInputZValueIgnored && pNormal != QVector3D( 0, 0, 1 ) )
521 QVector3D pXVector, pYVector;
522 normalVectorToXYVectors( pNormal, pXVector, pYVector );
527 *base = QMatrix4x4( pXVector.x(), pXVector.y(), pXVector.z(), 0, pYVector.x(), pYVector.y(), pYVector.z(), 0, pNormal.x(), pNormal.y(), pNormal.z(), 0, 0, 0, 0, 0 );
531 base->setToIdentity();
535QVector3D QgsTessellator::applyTransformWithExtrusion(
const QVector3D point,
float extrusionHeight, QMatrix4x4 *transformMatrix,
const QgsPoint *originOffset )
537 const float z = mInputZValueIgnored ? 0.0f : point.z();
538 QVector4D pt( point.x(), point.y(), z, 0 );
540 pt = *transformMatrix * pt;
542 const double fx = pt.
x() - mOrigin.x() + originOffset->
x();
543 const double fy = pt.y() - mOrigin.y() + originOffset->
y();
544 const double baseHeight = mInputZValueIgnored ? 0 : pt.z() - mOrigin.z() + originOffset->
z();
545 const double fz = mInputZValueIgnored ? 0.0 : ( baseHeight + extrusionHeight );
547 if ( baseHeight < mZMin )
548 mZMin =
static_cast<float>( baseHeight );
549 if ( baseHeight > mZMax )
550 mZMax =
static_cast<float>( baseHeight );
552 mZMax =
static_cast<float>( fz );
554 return QVector3D(
static_cast<float>( fx ),
static_cast<float>( fy ),
static_cast<float>( fz ) );
562 polyline.reserve( pCount );
564 const double *srcXData = ring->
xData();
565 const double *srcYData = ring->
yData();
566 const double *srcZData = ring->
zData();
569 for (
int i = 0; i < pCount - 1; ++i )
571 const double x = *srcXData++;
572 const double y = *srcYData++;
574 std::array<double, 2> pt = { x, y };
575 polyline.push_back( pt );
578 if ( zValues && srcZData )
580 zValues->insert( zValues->end(), srcZData, srcZData + pCount - 1 );
584std::vector<QVector3D> QgsTessellator::generateConstrainedDelaunayTriangles(
const QgsPolygon *polygonNew )
586 QList<std::vector<p2t::Point *>> polylinesToDelete;
587 QHash<p2t::Point *, float> z;
590 std::vector<p2t::Point *> polyline;
592 polylinesToDelete << polyline;
594 p2t::CDT cdt = p2t::CDT( polyline );
599 std::vector<p2t::Point *> holePolyline;
602 ringToPoly2tri( hole, holePolyline, mInputZValueIgnored ?
nullptr : &z );
604 cdt.AddHole( holePolyline );
605 polylinesToDelete << holePolyline;
609 std::vector<p2t::Triangle *> triangles = cdt.GetTriangles();
611 std::vector<QVector3D> trianglePoints;
612 trianglePoints.reserve( triangles.size() * 3 );
614 for ( p2t::Triangle *t : triangles )
616 trianglePoints.emplace_back( t->GetPoint( 0 )->x / mScale, t->GetPoint( 0 )->y / mScale, z.value( t->GetPoint( 0 ) ) );
617 trianglePoints.emplace_back( t->GetPoint( 1 )->x / mScale, t->GetPoint( 1 )->y / mScale, z.value( t->GetPoint( 1 ) ) );
618 trianglePoints.emplace_back( t->GetPoint( 2 )->x / mScale, t->GetPoint( 2 )->y / mScale, z.value( t->GetPoint( 2 ) ) );
621 for (
int i = 0; i < polylinesToDelete.count(); ++i )
622 qDeleteAll( polylinesToDelete[i] );
624 return trianglePoints;
627std::vector<QVector3D> QgsTessellator::generateEarcutTriangles(
const QgsPolygon *polygonNew )
629 const bool useZValues = !mInputZValueIgnored && polygonNew->
is3D();
630 const int allVerticesCount = polygonNew->
nCoordinates();
631 std::vector<double> zValues;
634 zValues.reserve( allVerticesCount );
636 std::vector<std::vector<std::array<double, 2>>> rings;
640 std::vector<std::array<double, 2>> polyline;
642 rings.push_back( std::move( polyline ) );
647 std::vector<std::array<double, 2>> holePolyline;
649 rings.push_back( std::move( holePolyline ) );
652 std::vector<std::array<double, 2>> points;
653 points.reserve( allVerticesCount );
655 for (
const auto &ring : rings )
657 points.insert( points.end(), ring.begin(), ring.end() );
660 std::vector<uint32_t> indices = mapbox::earcut<uint32_t>( rings );
661 std::vector<QVector3D> trianglePoints;
662 trianglePoints.reserve( indices.size() );
664 for (
size_t i = 0; i < indices.size(); i++ )
666 uint32_t vertexIndex = indices[i];
668 const float x =
static_cast<float>( points[vertexIndex][0] );
669 const float y =
static_cast<float>( points[vertexIndex][1] );
670 const float z =
static_cast<float>( useZValues ? zValues[vertexIndex] : 0.0 );
672 trianglePoints.emplace_back( x / mScale, y / mScale, z );
675 return trianglePoints;
678void QgsTessellator::addVertex(
679 const QVector3D &point,
680 const QVector3D &normal,
681 const QVector4D &tangent,
682 float extrusionHeight,
683 QMatrix4x4 *transformMatrix,
685 QHash<VertexPoint, unsigned int> *vertexBuffer,
686 const size_t &vertexBufferOffset,
690 const QVector3D pt = applyTransformWithExtrusion( point, extrusionHeight, transformMatrix, originOffset );
691 const VertexPoint vertex( pt, normal, tangent );
695 mIndexBuffer << vertexBufferOffset + index;
701 mIndexBuffer << vertexBufferOffset + index;
703 mData << pt.x() << pt.y() << pt.z();
706 mData << normal.x() << normal.y() << normal.z();
710 mData << tangent.x() << tangent.y() << tangent.z() << tangent.w();
712 if ( mAddTextureCoords )
729void QgsTessellator::addVertex(
const QVector3D &point,
const QVector3D &normal,
const QVector4D &tangent,
float extrusionHeight, QMatrix4x4 *transformMatrix,
const QgsPoint *originOffset,
bool isFloor )
731 const QVector3D pt = applyTransformWithExtrusion( point, extrusionHeight, transformMatrix, originOffset );
733 mData << pt.x() << pt.y() << pt.z();
736 mData << normal.x() << normal.y() << normal.z();
740 mData << tangent.x() << tangent.y() << tangent.z() << tangent.w();
742 if ( mAddTextureCoords )
764 const QVector3D pNormal = !mInputZValueIgnored ? calculateNormal( exterior, mOrigin.x(), mOrigin.y(), mOrigin.z(), mInvertNormals, extrusionHeight ) : QVector3D();
766 const QVector4D frontTangent( 1.0f, 0.0f, 0.0f, 1.0f );
767 const QVector4D floorFrontTangent( -1.0f, 0.0f, 0.0f, 1.0f );
769 const QVector4D backTangent( frontTangent.x(), frontTangent.y(), frontTangent.z(), -1.0f );
770 const QVector4D floorBackTangent( floorFrontTangent.x(), floorFrontTangent.y(), floorFrontTangent.z(), -1.0f );
772 const int pCount = exterior->
numPoints();
779 std::unique_ptr<QgsPolygon> polygonNew;
781 if ( !mInputZValueIgnored && !
qgsDoubleNear( pNormal.length(), 1, 0.001 ) )
784 bool buildWalls =
false;
785 bool buildFloor =
false;
786 bool buildRoof =
false;
801 if ( buildFloor || buildRoof )
803 calculateBaseTransform( pNormal, &base );
806 QVector3D normal = pNormal;
808 base = base.transposed();
812 Q_ASSERT( polygonNew->exteriorRing()->numPoints() >= 3 );
815 const QVector3D p1(
static_cast<float>( triangle->
xAt( 0 ) ),
static_cast<float>( triangle->
yAt( 0 ) ),
static_cast<float>( triangle->
zAt( 0 ) ) );
816 const QVector3D p2(
static_cast<float>( triangle->
xAt( 1 ) ),
static_cast<float>( triangle->
yAt( 1 ) ),
static_cast<float>( triangle->
zAt( 1 ) ) );
817 const QVector3D p3(
static_cast<float>( triangle->
xAt( 2 ) ),
static_cast<float>( triangle->
yAt( 2 ) ),
static_cast<float>( triangle->
zAt( 2 ) ) );
818 std::array<QVector3D, 3> points = { p1, p2, p3 };
822 for (
const QVector3D &point : points )
824 addVertex( point, normal, frontTangent, extrusionHeight, &base, &extrusionOrigin );
829 for (
size_t i = points.size(); i-- > 0; )
831 const QVector3D &point = points[i];
832 addVertex( point, -normal, backTangent, extrusionHeight, &base, &extrusionOrigin );
839 for (
const QVector3D &point : points )
841 addVertex( point, normal, floorFrontTangent, 0.0, &base, &extrusionOrigin,
true );
846 for (
size_t i = points.size(); i-- > 0; )
848 const QVector3D &point = points[i];
849 addVertex( point, -normal, floorBackTangent, 0.0, &base, &extrusionOrigin,
true );
863 if ( polygonSimplified.
isNull() )
865 mError = QObject::tr(
"geometry simplification failed - skipping" );
873 mError = QObject::tr(
"geometry's coordinates are too close to each other and simplification failed - skipping" );
878 polygonNew.reset( polygonSimplifiedData->
clone() );
885 std::vector<QVector3D> trianglePoints;
886 switch ( mTriangulationAlgorithm )
889 trianglePoints = generateConstrainedDelaunayTriangles( polygonNew.get() );
892 trianglePoints = generateEarcutTriangles( polygonNew.get() );
896 if ( trianglePoints.empty() )
898 mError = QObject::tr(
"Failed to triangulate polygon." );
902 Q_ASSERT( trianglePoints.size() % 3 == 0 );
904 mData.reserve( mData.size() + trianglePoints.size() * 3 * (
stride() /
sizeof(
float ) ) );
908 for (
size_t i = 0; i < trianglePoints.size(); i += 3 )
910 const std::array<QVector3D, 3> points = { trianglePoints[i + 0], trianglePoints[i + 1], trianglePoints[i + 2] };
915 for (
const QVector3D &point : points )
917 addVertex( point, normal, frontTangent, extrusionHeight, &base, &extrusionOrigin, &
vertexBuffer, vertexBufferSize );
922 for (
size_t i = points.size(); i-- > 0; )
924 const QVector3D &point = points[i];
925 addVertex( point, -normal, backTangent, extrusionHeight, &base, &extrusionOrigin, &
vertexBuffer, vertexBufferSize );
932 for (
const QVector3D &point : points )
934 addVertex( point, normal, floorFrontTangent, 0.0, &base, &extrusionOrigin, &
vertexBuffer, vertexBufferSize,
true );
939 for (
size_t i = points.size(); i-- > 0; )
941 const QVector3D &point = points[i];
942 addVertex( point, -normal, floorBackTangent, 0.0, &base, &extrusionOrigin, &
vertexBuffer, vertexBufferSize,
true );
948 catch ( std::runtime_error &err )
954 mError = QObject::tr(
"An unknown error occurred" );
962 makeWalls( *exterior,
false, extrusionHeight );
970 return mIndexBuffer.size();
975 auto mp = std::make_unique< QgsMultiPolygon >();
976 const size_t nVals = mIndexBuffer.size();
978 Q_ASSERT( nVals % 3 == 0 );
980 mp->reserve( nVals / 3 );
981 const size_t noOfElements =
stride() /
sizeof( float );
983 for (
size_t i = 0; i + 2 < nVals; i += 3 )
985 const uint32_t index1 = mIndexBuffer[i] * noOfElements;
986 const uint32_t index2 = mIndexBuffer[i + 1] * noOfElements;
987 const uint32_t index3 = mIndexBuffer[i + 2] * noOfElements;
989 const QgsPoint p1( mData[index1], mData[index1 + 1], mData[index1 + 2] );
990 const QgsPoint p2( mData[index2], mData[index2 + 1], mData[index2 + 2] );
991 const QgsPoint p3( mData[index3], mData[index3 + 1], mData[index3 + 2] );
1000 const size_t n = mIndexBuffer.size();
1002 return QVector<float>();
1004 QVector<float> tData;
1005 size_t noOfElements =
stride() /
sizeof( float );
1006 tData.reserve( n * noOfElements );
1008 for (
auto &index : mIndexBuffer )
1010 for (
size_t i = 0; i < noOfElements; i++ )
1012 tData << mData[index * noOfElements + i];
1021 if ( mData.size() == 0 )
1024 return mData.size() / (
stride() /
sizeof( float ) );
@ 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.
int nCoordinates() const override
Returns the number of nodes contained in the geometry.
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, QgsFeedback *feedback=nullptr) 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.
Q_DECL_DEPRECATED 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.
Q_DECL_DEPRECATED QVector< float > data() const
Returns array of triangle vertex data.
QByteArray vertexBuffer() const
Returns vertex buffer for the generated points.
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.
int uniqueVertexCount() const
Returns unique vertex count.
QByteArray indexBuffer() const
Returns index buffer for the generated points.
void setInvertNormals(bool invertNormals)
Sets whether normals should be inverted.
void setBackFacesEnabled(bool addBackFaces)
Sets whether back faces should be added to the output data.
Q_DECL_DEPRECATED void setOutputZUp(bool zUp)
Sets whether the "up" direction should be the Z axis on output (true), otherwise the "up" direction w...
void setAddTangents(bool addTangents)
Sets whether tangents should be added to the output data.
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.
void setAddNormals(bool addNormals)
Sets whether normals should be added to the output data.
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)
bool isCounterClockwise(std::array< Direction, 4 > dirs)
Checks whether the 4 directions in dirs make up a counter-clockwise rectangle.
double minimumDistanceBetweenCoordinates(const QgsPolygon &polygon)
void ringToEarcutPoints(const QgsLineString *ring, std::vector< std::array< double, 2 > > &polyline, std::vector< double > *zValues)
void ringToPoly2tri(const QgsLineString *ring, std::vector< p2t::Point * > &polyline, QHash< p2t::Point *, float > *zHash)
QgsPolygon * transformPolygonToNewBase(const QgsPolygon &polygon, const QgsPoint &pt0, const QMatrix4x4 *toNewBase, const float scale)
double roundCoord(double x)
std::size_t operator()(const std::pair< float, float > pair) const