29#define TINYGLTF_NO_STB_IMAGE
30#define TINYGLTF_NO_STB_IMAGE_WRITE
36QString QgsGltfToVectorFeaturesAlgorithm::name()
const
38 return QStringLiteral(
"gltftovector" );
41QString QgsGltfToVectorFeaturesAlgorithm::displayName()
const
43 return QObject::tr(
"Convert GLTF to vector features" );
46QStringList QgsGltfToVectorFeaturesAlgorithm::tags()
const
48 return QObject::tr(
"3d,tiles,cesium" ).split(
',' );
51QString QgsGltfToVectorFeaturesAlgorithm::group()
const
53 return QObject::tr(
"3D Tiles" );
56QString QgsGltfToVectorFeaturesAlgorithm::groupId()
const
58 return QStringLiteral(
"3dtiles" );
61QString QgsGltfToVectorFeaturesAlgorithm::shortHelpString()
const
63 return QObject::tr(
"Converts GLTF content to standard vector layer formats." );
66QgsGltfToVectorFeaturesAlgorithm *QgsGltfToVectorFeaturesAlgorithm::createInstance()
const
68 return new QgsGltfToVectorFeaturesAlgorithm();
71void QgsGltfToVectorFeaturesAlgorithm::initAlgorithm(
const QVariantMap & )
74 QStringLiteral(
"gltf" ), QVariant(),
false, QStringLiteral(
"GLTF (*.gltf *.GLTF);;GLB (*.glb *.GLB)" ) ) );
80std::unique_ptr< QgsAbstractGeometry > extractTriangles(
81 const tinygltf::Model &model,
82 const tinygltf::Primitive &primitive,
85 const QMatrix4x4 *gltfLocalTransform,
88 auto posIt = primitive.attributes.find(
"POSITION" );
89 if ( posIt == primitive.attributes.end() )
91 feedback->
reportError( QObject::tr(
"Could not find POSITION attribute for primitive" ) );
94 int positionAccessorIndex = posIt->second;
99 QgsGltfUtils::accessorToMapCoordinates(
108 std::unique_ptr< QgsMultiPolygon > mp = std::make_unique< QgsMultiPolygon >();
110 if ( primitive.indices == -1 )
112 Q_ASSERT( x.size() % 3 == 0 );
114 mp->reserve( x.size() );
115 for (
int i = 0; i < x.size(); i += 3 )
117 mp->addGeometry(
new QgsPolygon(
new QgsLineString( QVector<QgsPoint> {
QgsPoint( x[i], y[i], z[i] ),
QgsPoint( x[i + 1], y[i + 1], z[i + 1] ),
QgsPoint( x[i + 2], y[i + 2 ], z[i + 2] ),
QgsPoint( x[i], y[i], z[i] ) } ) ) );
122 const tinygltf::Accessor &primitiveAccessor = model.accessors[primitive.indices];
123 const tinygltf::BufferView &bvPrimitive = model.bufferViews[primitiveAccessor.bufferView];
124 const tinygltf::Buffer &bPrimitive = model.buffers[bvPrimitive.buffer];
126 Q_ASSERT( ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT
127 || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
128 || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
129 && primitiveAccessor.type == TINYGLTF_TYPE_SCALAR );
131 const char *primitivePtr =
reinterpret_cast< const char *
>( bPrimitive.data.data() ) + bvPrimitive.byteOffset + primitiveAccessor.byteOffset;
133 mp->reserve( primitiveAccessor.count / 3 );
134 for ( std::size_t i = 0; i < primitiveAccessor.count / 3; i++ )
136 unsigned int index1 = 0;
137 unsigned int index2 = 0;
138 unsigned int index3 = 0;
140 if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT )
142 const unsigned short *usPtrPrimitive =
reinterpret_cast< const unsigned short *
>( primitivePtr );
143 if ( bvPrimitive.byteStride )
144 primitivePtr += bvPrimitive.byteStride;
146 primitivePtr += 3 *
sizeof(
unsigned short );
148 index1 = usPtrPrimitive[0];
149 index2 = usPtrPrimitive[1];
150 index3 = usPtrPrimitive[2];
152 else if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
154 const unsigned char *usPtrPrimitive =
reinterpret_cast< const unsigned char *
>( primitivePtr );
155 if ( bvPrimitive.byteStride )
156 primitivePtr += bvPrimitive.byteStride;
158 primitivePtr += 3 *
sizeof(
unsigned char );
160 index1 = usPtrPrimitive[0];
161 index2 = usPtrPrimitive[1];
162 index3 = usPtrPrimitive[2];
166 const unsigned int *uintPtrPrimitive =
reinterpret_cast< const unsigned int *
>( primitivePtr );
167 if ( bvPrimitive.byteStride )
168 primitivePtr += bvPrimitive.byteStride;
170 primitivePtr += 3 *
sizeof(
unsigned int );
172 index1 = uintPtrPrimitive[0];
173 index2 = uintPtrPrimitive[1];
174 index3 = uintPtrPrimitive[2];
177 mp->addGeometry(
new QgsPolygon(
new QgsLineString( QVector<QgsPoint> {
QgsPoint( x[index1], y[index1], z[index1] ),
QgsPoint( x[index2], y[index2], z[index2] ),
QgsPoint( x[index3], y[index3], z[index3] ),
QgsPoint( x[index1], y[index1], z[index1] ) } ) ) );
183std::unique_ptr< QgsAbstractGeometry > extractLines(
184 const tinygltf::Model &model,
185 const tinygltf::Primitive &primitive,
188 const QMatrix4x4 *gltfLocalTransform,
191 auto posIt = primitive.attributes.find(
"POSITION" );
192 if ( posIt == primitive.attributes.end() )
194 feedback->
reportError( QObject::tr(
"Could not find POSITION attribute for primitive" ) );
197 int positionAccessorIndex = posIt->second;
202 QgsGltfUtils::accessorToMapCoordinates(
211 std::unique_ptr< QgsMultiLineString > ml = std::make_unique< QgsMultiLineString >();
213 if ( primitive.indices == -1 )
215 Q_ASSERT( x.size() % 2 == 0 );
217 ml->reserve( x.size() );
218 for (
int i = 0; i < x.size(); i += 2 )
225 const tinygltf::Accessor &primitiveAccessor = model.accessors[primitive.indices];
226 const tinygltf::BufferView &bvPrimitive = model.bufferViews[primitiveAccessor.bufferView];
227 const tinygltf::Buffer &bPrimitive = model.buffers[bvPrimitive.buffer];
229 Q_ASSERT( ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT
230 || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
231 || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
232 && primitiveAccessor.type == TINYGLTF_TYPE_SCALAR );
234 const char *primitivePtr =
reinterpret_cast< const char *
>( bPrimitive.data.data() ) + bvPrimitive.byteOffset + primitiveAccessor.byteOffset;
236 ml->reserve( primitiveAccessor.count / 2 );
237 for ( std::size_t i = 0; i < primitiveAccessor.count / 2; i++ )
239 unsigned int index1 = 0;
240 unsigned int index2 = 0;
242 if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT )
244 const unsigned short *usPtrPrimitive =
reinterpret_cast< const unsigned short *
>( primitivePtr );
245 if ( bvPrimitive.byteStride )
246 primitivePtr += bvPrimitive.byteStride;
248 primitivePtr += 2 *
sizeof(
unsigned short );
250 index1 = usPtrPrimitive[0];
251 index2 = usPtrPrimitive[1];
253 else if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
255 const unsigned char *usPtrPrimitive =
reinterpret_cast< const unsigned char *
>( primitivePtr );
256 if ( bvPrimitive.byteStride )
257 primitivePtr += bvPrimitive.byteStride;
259 primitivePtr += 2 *
sizeof(
unsigned char );
261 index1 = usPtrPrimitive[0];
262 index2 = usPtrPrimitive[1];
266 const unsigned int *uintPtrPrimitive =
reinterpret_cast< const unsigned int *
>( primitivePtr );
267 if ( bvPrimitive.byteStride )
268 primitivePtr += bvPrimitive.byteStride;
270 primitivePtr += 2 *
sizeof(
unsigned int );
272 index1 = uintPtrPrimitive[0];
273 index2 = uintPtrPrimitive[1];
276 ml->addGeometry(
new QgsLineString( QVector<QgsPoint> {
QgsPoint( x[index1], y[index1], z[index1] ),
QgsPoint( x[index2], y[index2], z[index2] ) } ) );
284 const QString path = parameterAsFile( parameters, QStringLiteral(
"INPUT" ), context );
290 std::unique_ptr< QgsFeatureSink > polygonSink( parameterAsSink( parameters, QStringLiteral(
"OUTPUT_POLYGONS" ), context, polygonDest, fields,
292 if ( !polygonSink && parameters.value( QStringLiteral(
"OUTPUT_POLYGONS" ) ).isValid() )
295 std::unique_ptr< QgsFeatureSink > lineSink( parameterAsSink( parameters, QStringLiteral(
"OUTPUT_LINES" ), context, lineDest, fields,
297 if ( !lineSink && parameters.value( QStringLiteral(
"OUTPUT_LINES" ) ).isValid() )
301 QByteArray fileContent;
302 if ( f.open( QIODevice::ReadOnly ) )
304 fileContent = f.readAll();
313 tinygltf::Model model;
316 if ( !QgsGltfUtils::loadGltfModel( fileContent, model, &errors, &warnings ) )
320 if ( !warnings.isEmpty() )
324 feedback->
pushDebugInfo( QObject::tr(
"Found %1 scenes" ).arg( model.scenes.size() ) );
326 const tinygltf::Scene &scene = model.scenes[model.defaultScene];
327 feedback->
pushDebugInfo( QObject::tr(
"Found %1 nodes in default scene [%2]" ).arg( scene.nodes.size() ).arg( model.defaultScene ) );
329 QSet< int > warnedPrimitiveTypes;
330 if ( !scene.nodes.empty() )
332 for (
const int nodeIndex : scene.nodes )
334 const tinygltf::Node &gltfNode = model.nodes[nodeIndex];
335 const QgsVector3D tileTranslationEcef = QgsGltfUtils::extractTileTranslation( model );
336 const std::unique_ptr< QMatrix4x4 > gltfLocalTransform = QgsGltfUtils::parseNodeTransform( gltfNode );
338 if ( gltfNode.mesh >= 0 )
340 const tinygltf::Mesh &mesh = model.meshes[gltfNode.mesh];
341 feedback->
pushDebugInfo( QObject::tr(
"Found %1 primitives in default scene node [%2]" ).arg( mesh.primitives.size() ).arg( nodeIndex ) );
343 for (
const tinygltf::Primitive &primitive : mesh.primitives )
345 switch ( primitive.mode )
347 case TINYGLTF_MODE_TRIANGLES:
351 std::unique_ptr< QgsAbstractGeometry > geometry = extractTriangles( model, primitive, ecefTransform, tileTranslationEcef, gltfLocalTransform.get(), feedback );
362 case TINYGLTF_MODE_LINE:
366 std::unique_ptr< QgsAbstractGeometry > geometry = extractLines( model, primitive, ecefTransform, tileTranslationEcef, gltfLocalTransform.get(), feedback );
377 case TINYGLTF_MODE_POINTS:
378 if ( !warnedPrimitiveTypes.contains( TINYGLTF_MODE_POINTS ) )
380 feedback->
reportError( QObject::tr(
"Point objects are not supported" ) );
381 warnedPrimitiveTypes.insert( TINYGLTF_MODE_POINTS );
385 case TINYGLTF_MODE_LINE_LOOP:
386 if ( !warnedPrimitiveTypes.contains( TINYGLTF_MODE_LINE_LOOP ) )
388 feedback->
reportError( QObject::tr(
"Line loops in are not supported" ) );
389 warnedPrimitiveTypes.insert( TINYGLTF_MODE_LINE_LOOP );
393 case TINYGLTF_MODE_LINE_STRIP:
394 if ( !warnedPrimitiveTypes.contains( TINYGLTF_MODE_LINE_STRIP ) )
396 feedback->
reportError( QObject::tr(
"Line strips in are not supported" ) );
397 warnedPrimitiveTypes.insert( TINYGLTF_MODE_LINE_STRIP );
401 case TINYGLTF_MODE_TRIANGLE_STRIP:
402 if ( !warnedPrimitiveTypes.contains( TINYGLTF_MODE_TRIANGLE_STRIP ) )
404 feedback->
reportError( QObject::tr(
"Triangular strips are not supported" ) );
405 warnedPrimitiveTypes.insert( TINYGLTF_MODE_TRIANGLE_STRIP );
409 case TINYGLTF_MODE_TRIANGLE_FAN:
410 if ( !warnedPrimitiveTypes.contains( TINYGLTF_MODE_TRIANGLE_FAN ) )
412 feedback->
reportError( QObject::tr(
"Triangular fans are not supported" ) );
413 warnedPrimitiveTypes.insert( TINYGLTF_MODE_TRIANGLE_FAN );
418 if ( !warnedPrimitiveTypes.contains( primitive.mode ) )
420 feedback->
reportError( QObject::tr(
"Primitive type %1 are not supported" ).arg( primitive.mode ) );
421 warnedPrimitiveTypes.insert( primitive.mode );
432 outputs.insert( QStringLiteral(
"OUTPUT_POLYGONS" ), polygonDest );
434 outputs.insert( QStringLiteral(
"OUTPUT_LINES" ), lineDest );
@ MultiLineStringZ
MultiLineStringZ.
@ MultiPolygonZ
MultiPolygonZ.
This class represents a coordinate reference system (CRS).
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Container of fields for a vector layer.
Line string geometry type, with support for z-dimension and m-values.
A simple 4x4 matrix implementation useful for transformation in 3D space.
Point geometry type, with support for z-dimension and m-values.
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void pushWarning(const QString &warning)
Pushes a warning informational message from the algorithm.
virtual void pushDebugInfo(const QString &info)
Pushes an informational message containing debugging helpers from the algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
A feature sink output for processing algorithms.
An input file or folder parameter for processing algorithms.
@ File
Parameter is a single file.
@ TypeVectorLine
Vector line layers.
@ TypeVectorPolygon
Vector polygon layers.
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...