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  bool sceneOk = 
false;
 
  327  const std::size_t sceneIndex = QgsGltfUtils::sourceSceneForModel( model, sceneOk );
 
  333  const tinygltf::Scene &scene = model.scenes[sceneIndex];
 
  334  feedback->
pushDebugInfo( QObject::tr( 
"Found %1 nodes in default scene [%2]" ).arg( scene.nodes.size() ).arg( sceneIndex ) );
 
  336  QSet< int > warnedPrimitiveTypes;
 
  338  const QgsVector3D tileTranslationEcef = QgsGltfUtils::extractTileTranslation( model );
 
  339  std::function< void( 
int nodeIndex, 
const QMatrix4x4 &transform ) > traverseNode;
 
  340  traverseNode = [&model, feedback, &polygonSink, &lineSink, &warnedPrimitiveTypes, &ecefTransform, &tileTranslationEcef, &traverseNode]( 
int nodeIndex, 
const QMatrix4x4 & parentTransform )
 
  342    const tinygltf::Node &gltfNode = model.nodes[nodeIndex];
 
  343    std::unique_ptr< QMatrix4x4 > gltfLocalTransform = QgsGltfUtils::parseNodeTransform( gltfNode );
 
  344    if ( !parentTransform.isIdentity() )
 
  346      if ( gltfLocalTransform )
 
  347        *gltfLocalTransform = parentTransform * *gltfLocalTransform;
 
  350        gltfLocalTransform.reset( 
new QMatrix4x4( parentTransform ) );
 
  354    if ( gltfNode.mesh >= 0 )
 
  356      const tinygltf::Mesh &mesh = model.meshes[gltfNode.mesh];
 
  357      feedback->pushDebugInfo( QObject::tr( 
"Found %1 primitives in node [%2]" ).arg( mesh.primitives.size() ).arg( nodeIndex ) );
 
  359      for ( 
const tinygltf::Primitive &primitive : mesh.primitives )
 
  361        switch ( primitive.mode )
 
  363          case TINYGLTF_MODE_TRIANGLES:
 
  367              std::unique_ptr< QgsAbstractGeometry > geometry = extractTriangles( model, primitive, ecefTransform, tileTranslationEcef, gltfLocalTransform.get(), feedback );
 
  378          case TINYGLTF_MODE_LINE:
 
  382              std::unique_ptr< QgsAbstractGeometry > geometry = extractLines( model, primitive, ecefTransform, tileTranslationEcef, gltfLocalTransform.get(), feedback );
 
  393          case TINYGLTF_MODE_POINTS:
 
  394            if ( !warnedPrimitiveTypes.contains( TINYGLTF_MODE_POINTS ) )
 
  396              feedback->reportError( QObject::tr( 
"Point objects are not supported" ) );
 
  397              warnedPrimitiveTypes.insert( TINYGLTF_MODE_POINTS );
 
  401          case TINYGLTF_MODE_LINE_LOOP:
 
  402            if ( !warnedPrimitiveTypes.contains( TINYGLTF_MODE_LINE_LOOP ) )
 
  404              feedback->reportError( QObject::tr( 
"Line loops in are not supported" ) );
 
  405              warnedPrimitiveTypes.insert( TINYGLTF_MODE_LINE_LOOP );
 
  409          case TINYGLTF_MODE_LINE_STRIP:
 
  410            if ( !warnedPrimitiveTypes.contains( TINYGLTF_MODE_LINE_STRIP ) )
 
  412              feedback->reportError( QObject::tr( 
"Line strips in are not supported" ) );
 
  413              warnedPrimitiveTypes.insert( TINYGLTF_MODE_LINE_STRIP );
 
  417          case TINYGLTF_MODE_TRIANGLE_STRIP:
 
  418            if ( !warnedPrimitiveTypes.contains( TINYGLTF_MODE_TRIANGLE_STRIP ) )
 
  420              feedback->reportError( QObject::tr( 
"Triangular strips are not supported" ) );
 
  421              warnedPrimitiveTypes.insert( TINYGLTF_MODE_TRIANGLE_STRIP );
 
  425          case TINYGLTF_MODE_TRIANGLE_FAN:
 
  426            if ( !warnedPrimitiveTypes.contains( TINYGLTF_MODE_TRIANGLE_FAN ) )
 
  428              feedback->reportError( QObject::tr( 
"Triangular fans are not supported" ) );
 
  429              warnedPrimitiveTypes.insert( TINYGLTF_MODE_TRIANGLE_FAN );
 
  434            if ( !warnedPrimitiveTypes.contains( primitive.mode ) )
 
  436              feedback->reportError( QObject::tr( 
"Primitive type %1 are not supported" ).arg( primitive.mode ) );
 
  437              warnedPrimitiveTypes.insert( primitive.mode );
 
  444    for ( 
int childNode : gltfNode.children )
 
  446      traverseNode( childNode, gltfLocalTransform ? *gltfLocalTransform : QMatrix4x4() );
 
  451  if ( !scene.nodes.empty() )
 
  453    for ( 
const int nodeIndex : scene.nodes )
 
  455      traverseNode( nodeIndex, QMatrix4x4() );
 
  461    outputs.insert( QStringLiteral( 
"OUTPUT_POLYGONS" ), polygonDest );
 
  463    outputs.insert( QStringLiteral( 
"OUTPUT_LINES" ), lineDest );
 
@ VectorPolygon
Vector polygon layers.
 
@ VectorLine
Vector line layers.
 
@ File
Parameter is a single file.
 
@ 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.
 
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...