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 ) );
558void QgsTessellator::ringToEarcutPoints(
const QgsLineString *ring, std::vector<std::array<double, 2>> &polyline, QHash<std::array<double, 2> *,
float> *zHash )
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 float x =
static_cast<float>( *srcXData++ );
572 const float y =
static_cast<float>( *srcYData++ );
574 std::array<double, 2> pt = { x, y };
575 polyline.push_back( pt );
577 if ( zHash && srcZData )
579 ( *zHash )[&pt] = *srcZData++;
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 QHash<std::array<double, 2> *,
float> z;
630 std::vector<std::vector<std::array<double, 2>>> rings;
631 std::vector<std::array<double, 2>> polyline;
634 rings.push_back( polyline );
638 std::vector<std::array<double, 2>> holePolyline;
640 rings.push_back( holePolyline );
643 std::vector<std::array<double, 2>> points;
644 for (
const auto &ring : rings )
646 points.insert( points.end(), ring.begin(), ring.end() );
649 std::vector<uint32_t> indices = mapbox::earcut<uint32_t>( rings );
650 std::vector<QVector3D> trianglePoints;
651 trianglePoints.reserve( points.size() );
653 for (
size_t i = 0; i < indices.size(); i++ )
655 uint32_t vertexIndex = indices[i];
656 std::array<double, 2> vertex = points[vertexIndex];
658 double x = vertex[0];
659 double y = vertex[1];
661 float zValue = z.value( &vertex, 0.0f );
663 trianglePoints.emplace_back( x / mScale, y / mScale, zValue );
666 return trianglePoints;
669void QgsTessellator::addVertex(
670 const QVector3D &point,
671 const QVector3D &normal,
672 const QVector4D &tangent,
673 float extrusionHeight,
674 QMatrix4x4 *transformMatrix,
676 QHash<VertexPoint, unsigned int> *vertexBuffer,
677 const size_t &vertexBufferOffset,
681 const QVector3D pt = applyTransformWithExtrusion( point, extrusionHeight, transformMatrix, originOffset );
682 const VertexPoint vertex( pt, normal, tangent );
686 mIndexBuffer << vertexBufferOffset + index;
692 mIndexBuffer << vertexBufferOffset + index;
694 mData << pt.x() << pt.y() << pt.z();
697 mData << normal.x() << normal.y() << normal.z();
701 mData << tangent.x() << tangent.y() << tangent.z() << tangent.w();
703 if ( mAddTextureCoords )
720void QgsTessellator::addVertex(
const QVector3D &point,
const QVector3D &normal,
const QVector4D &tangent,
float extrusionHeight, QMatrix4x4 *transformMatrix,
const QgsPoint *originOffset,
bool isFloor )
722 const QVector3D pt = applyTransformWithExtrusion( point, extrusionHeight, transformMatrix, originOffset );
724 mData << pt.x() << pt.y() << pt.z();
727 mData << normal.x() << normal.y() << normal.z();
731 mData << tangent.x() << tangent.y() << tangent.z() << tangent.w();
733 if ( mAddTextureCoords )
755 const QVector3D pNormal = !mInputZValueIgnored ? calculateNormal( exterior, mOrigin.x(), mOrigin.y(), mOrigin.z(), mInvertNormals, extrusionHeight ) : QVector3D();
757 const QVector4D frontTangent( 1.0f, 0.0f, 0.0f, 1.0f );
758 const QVector4D floorFrontTangent( -1.0f, 0.0f, 0.0f, 1.0f );
760 const QVector4D backTangent( frontTangent.x(), frontTangent.y(), frontTangent.z(), -1.0f );
761 const QVector4D floorBackTangent( floorFrontTangent.x(), floorFrontTangent.y(), floorFrontTangent.z(), -1.0f );
763 const int pCount = exterior->
numPoints();
770 std::unique_ptr<QgsPolygon> polygonNew;
772 if ( !mInputZValueIgnored && !
qgsDoubleNear( pNormal.length(), 1, 0.001 ) )
779 if ( buildFloor || buildRoof )
781 calculateBaseTransform( pNormal, &base );
784 QVector3D normal = pNormal;
786 base = base.transposed();
790 Q_ASSERT( polygonNew->exteriorRing()->numPoints() >= 3 );
793 const QVector3D p1(
static_cast<float>( triangle->
xAt( 0 ) ),
static_cast<float>( triangle->
yAt( 0 ) ),
static_cast<float>( triangle->
zAt( 0 ) ) );
794 const QVector3D p2(
static_cast<float>( triangle->
xAt( 1 ) ),
static_cast<float>( triangle->
yAt( 1 ) ),
static_cast<float>( triangle->
zAt( 1 ) ) );
795 const QVector3D p3(
static_cast<float>( triangle->
xAt( 2 ) ),
static_cast<float>( triangle->
yAt( 2 ) ),
static_cast<float>( triangle->
zAt( 2 ) ) );
796 std::array<QVector3D, 3> points = { p1, p2, p3 };
798 for (
const QVector3D &point : points )
800 addVertex( point, normal, frontTangent, extrusionHeight, &base, &extrusionOrigin );
805 for (
size_t i = points.size(); i-- > 0; )
807 const QVector3D &point = points[i];
808 addVertex( point, -normal, backTangent, extrusionHeight, &base, &extrusionOrigin );
812 if ( extrusionHeight != 0 && buildFloor )
814 for (
const QVector3D &point : points )
816 addVertex( point, normal, floorFrontTangent, 0.0, &base, &extrusionOrigin,
true );
821 for (
size_t i = points.size(); i-- > 0; )
823 const QVector3D &point = points[i];
824 addVertex( point, -normal, floorBackTangent, 0.0, &base, &extrusionOrigin,
true );
838 if ( polygonSimplified.
isNull() )
840 mError = QObject::tr(
"geometry simplification failed - skipping" );
848 mError = QObject::tr(
"geometry's coordinates are too close to each other and simplification failed - skipping" );
853 polygonNew.reset( polygonSimplifiedData->
clone() );
860 std::vector<QVector3D> trianglePoints;
861 switch ( mTriangulationAlgorithm )
864 trianglePoints = generateConstrainedDelaunayTriangles( polygonNew.get() );
867 trianglePoints = generateEarcutTriangles( polygonNew.get() );
871 if ( trianglePoints.empty() )
873 mError = QObject::tr(
"Failed to triangulate polygon." );
877 Q_ASSERT( trianglePoints.size() % 3 == 0 );
879 mData.reserve( mData.size() + trianglePoints.size() * 3 * (
stride() /
sizeof(
float ) ) );
883 for (
size_t i = 0; i < trianglePoints.size(); i += 3 )
885 const std::array<QVector3D, 3> points = { trianglePoints[i + 0], trianglePoints[i + 1], trianglePoints[i + 2] };
888 for (
const QVector3D &point : points )
890 addVertex( point, normal, frontTangent, extrusionHeight, &base, &extrusionOrigin, &
vertexBuffer, vertexBufferSize );
895 for (
size_t i = points.size(); i-- > 0; )
897 const QVector3D &point = points[i];
898 addVertex( point, -normal, backTangent, extrusionHeight, &base, &extrusionOrigin, &
vertexBuffer, vertexBufferSize );
902 if ( extrusionHeight != 0 && buildFloor )
904 for (
const QVector3D &point : points )
906 addVertex( point, normal, floorFrontTangent, 0.0, &base, &extrusionOrigin, &
vertexBuffer, vertexBufferSize,
true );
911 for (
size_t i = points.size(); i-- > 0; )
913 const QVector3D &point = points[i];
914 addVertex( point, -normal, floorBackTangent, 0.0, &base, &extrusionOrigin, &
vertexBuffer, vertexBufferSize,
true );
920 catch ( std::runtime_error &err )
926 mError = QObject::tr(
"An unknown error occurred" );
932 if ( extrusionHeight != 0 && buildWalls )
934 makeWalls( *exterior,
false, extrusionHeight );
942 return mIndexBuffer.size();
947 auto mp = std::make_unique< QgsMultiPolygon >();
948 const size_t nVals = mIndexBuffer.size();
950 Q_ASSERT( nVals % 3 == 0 );
952 mp->reserve( nVals / 3 );
953 const size_t noOfElements =
stride() /
sizeof( float );
955 for (
size_t i = 0; i + 2 < nVals; i += 3 )
957 const uint32_t index1 = mIndexBuffer[i] * noOfElements;
958 const uint32_t index2 = mIndexBuffer[i + 1] * noOfElements;
959 const uint32_t index3 = mIndexBuffer[i + 2] * noOfElements;
961 const QgsPoint p1( mData[index1], mData[index1 + 1], mData[index1 + 2] );
962 const QgsPoint p2( mData[index2], mData[index2 + 1], mData[index2 + 2] );
963 const QgsPoint p3( mData[index3], mData[index3 + 1], mData[index3 + 2] );
972 const size_t n = mIndexBuffer.size();
974 return QVector<float>();
976 QVector<float> tData;
977 size_t noOfElements =
stride() /
sizeof( float );
978 tData.reserve( n * noOfElements );
980 for (
auto &index : mIndexBuffer )
982 for (
size_t i = 0; i < noOfElements; i++ )
984 tData << mData[index * noOfElements + i];
993 if ( mData.size() == 0 )
996 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.
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 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