QByteArray QgsCurvePolygon::asWkb() const
{
  int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
  QVector<QByteArray> wkbForRings;
  wkbForRings.reserve( 1 + mInteriorRings.size() );
  if ( mExteriorRing )
  {
    QByteArray wkb( mExteriorRing->asWkb() );
    binarySize += wkb.length();
    wkbForRings << wkb;
  }
  for ( const QgsCurve *curve : mInteriorRings )
  {
    QByteArray wkb( curve->asWkb() );
    binarySize += wkb.length();
    wkbForRings << wkb;
  }

  QByteArray wkbArray;
  wkbArray.resize( binarySize );
  QgsWkbPtr wkbPtr( wkbArray );
  wkbPtr << static_cast<char>( QgsApplication::endian() );
  wkbPtr << static_cast<quint32>( wkbType() );
  wkbPtr << static_cast<quint32>( wkbForRings.count() );
  for ( const QByteArray &wkb : qgis::as_const( wkbForRings ) )
  {
    wkbPtr << wkb;
  }
  return wkbArray;
}
QByteArray QgsGeometryCollection::asWkb() const
{
  int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
  QVector<QByteArray> wkbForGeometries;
  for ( const QgsAbstractGeometry *geom : mGeometries )
  {
    if ( geom )
    {
      QByteArray wkb( geom->asWkb() );
      binarySize += wkb.length();
      wkbForGeometries << wkb;
    }
  }

  QByteArray wkbArray;
  wkbArray.resize( binarySize );
  QgsWkbPtr wkb( wkbArray );
  wkb << static_cast<char>( QgsApplication::endian() );
  wkb << static_cast<quint32>( wkbType() );
  wkb << static_cast<quint32>( wkbForGeometries.count() );
  for ( const QByteArray &wkbForGeometry : qgis::as_const( wkbForGeometries ) )
  {
    wkb << wkbForGeometry;
  }
  return wkbArray;
}
 void object::test<1>()
 {
     // POINT(1.234 5.678)
     std::string wkt("POINT (1.234 5.678)");
     std::string wkb("01010000005839B4C876BEF33F83C0CAA145B61640");
     test_wkb(wkb, wkt);
 }
示例#4
0
文件: Polygon.cpp 项目: kirkjens/PDAL
Polygon::Polygon(OGRGeometryH g, const SpatialReference& srs,
    geos::ErrorHandler& err) : m_srs(srs) , m_ctx(err.ctx)
{
    OGRwkbGeometryType t = OGR_G_GetGeometryType(g);

    if (!(t == wkbPolygon ||
        t == wkbMultiPolygon ||
        t == wkbPolygon25D ||
        t == wkbMultiPolygon25D))
    {
        std::ostringstream oss;
        oss << "pdal::Polygon cannot construct geometry because "
            "OGR geometry is not Polygon or MultiPolygon!";
        throw pdal::pdal_error(oss.str());
    }

    OGRGeometry *ogr_g = (OGRGeometry*)g;
    //
    // Convert the the GDAL geom to WKB in order to avoid the version
    // context issues with exporting directoly to GEOS.
    OGRwkbByteOrder bo =
        GEOS_getWKBByteOrder() == GEOS_WKB_XDR ? wkbXDR : wkbNDR;
    int wkbSize = ogr_g->WkbSize();
    std::vector<unsigned char> wkb(wkbSize);

    ogr_g->exportToWkb(bo, wkb.data());
    m_geom = GEOSGeomFromWKB_buf_r(m_ctx, wkb.data(), wkbSize);
    prepare();

}
int QgsInterpolator::addVerticesToCache( const QgsGeometry& geom, bool zCoord, double attributeValue )
{
  if ( geom.isEmpty() )
    return 1;

  bool hasZValue = false;
  QByteArray wkb( geom.exportToWkb() );
  QgsConstWkbPtr currentWkbPtr( wkb );
  currentWkbPtr.readHeader();
  vertexData theVertex; //the current vertex

  QgsWkbTypes::Type wkbType = geom.wkbType();
  switch ( wkbType )
  {
    case QgsWkbTypes::Point25D:
      hasZValue = true;
      //intentional fall-through
      FALLTHROUGH;
    case QgsWkbTypes::Point:
    {
      currentWkbPtr >> theVertex.x >> theVertex.y;
      if ( zCoord && hasZValue )
      {
        currentWkbPtr >> theVertex.z;
      }
      else
      {
        theVertex.z = attributeValue;
      }
      mCachedBaseData.push_back( theVertex );
      break;
    }
示例#6
0
QByteArray QgsPolygonV2::asWkb() const
{
  int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );

  // Endianness and WkbType is not stored for LinearRings
  if ( mExteriorRing )
  {
    binarySize += sizeof( quint32 ) + mExteriorRing->numPoints() * ( 2 + mExteriorRing->is3D() + mExteriorRing->isMeasure() ) * sizeof( double );
  }
  for ( const QgsCurve *curve : mInteriorRings )
  {
    binarySize += sizeof( quint32 ) + curve->numPoints() * ( 2 + curve->is3D() + curve->isMeasure() ) * sizeof( double );
  }

  QByteArray wkbArray;
  wkbArray.resize( binarySize );
  QgsWkbPtr wkb( wkbArray );
  wkb << static_cast<char>( QgsApplication::endian() );
  wkb << static_cast<quint32>( wkbType() );
  wkb << static_cast<quint32>( ( nullptr != mExteriorRing ) + mInteriorRings.size() );
  if ( mExteriorRing )
  {
    QgsPointSequence pts;
    mExteriorRing->points( pts );
    QgsGeometryUtils::pointsToWKB( wkb, pts, mExteriorRing->is3D(), mExteriorRing->isMeasure() );
  }
  for ( const QgsCurve *curve : mInteriorRings )
  {
    QgsPointSequence pts;
    curve->points( pts );
    QgsGeometryUtils::pointsToWKB( wkb, pts, curve->is3D(), curve->isMeasure() );
  }

  return wkbArray;
}
QgsGeometry QgsGeometryAnalyzer::locateBetweenMeasures( double fromMeasure, double toMeasure, const QgsGeometry& lineGeom )
{
  if ( lineGeom.isEmpty() )
  {
    return QgsGeometry();
  }

  QgsMultiPolyline resultGeom;

  //need to go with WKB and z coordinate until QgsGeometry supports M values
  QByteArray wkb( lineGeom.exportToWkb() );
  QgsConstWkbPtr wkbPtr( wkb );
  wkbPtr.readHeader();

  QgsWkbTypes::Type wkbType = lineGeom.wkbType();
  if ( wkbType != QgsWkbTypes::LineString25D && wkbType != QgsWkbTypes::MultiLineString25D )
  {
    return QgsGeometry();
  }

  if ( wkbType == QgsWkbTypes::LineString25D )
  {
    locateBetweenWkbString( wkbPtr, resultGeom, fromMeasure, toMeasure );
  }
  else if ( wkbType == QgsWkbTypes::MultiLineString25D )
  {
    int nLines;
    wkbPtr >> nLines;
    for ( int i = 0; i < nLines; ++i )
    {
      wkbPtr.readHeader();
      wkbPtr = locateBetweenWkbString( wkbPtr, resultGeom, fromMeasure, toMeasure );
    }
  }
示例#8
0
unsigned char* QgsLineStringV2::asWkb( int& binarySize ) const
{
  binarySize = wkbSize();
  unsigned char* geomPtr = new unsigned char[binarySize];
  QgsWkbPtr wkb( geomPtr );
  wkb << static_cast<char>( QgsApplication::endian() );
  wkb << static_cast<quint32>( wkbType() );
  QList<QgsPointV2> pts;
  points( pts );
  QgsGeometryUtils::pointsToWKB( wkb, pts, is3D(), isMeasure() );
  return geomPtr;
}
示例#9
0
wkb_buffer_ptr to_polygon_wkb( GeometryType const& g, wkbByteOrder byte_order)
{
    unsigned num_points = g.size();
    assert(num_points > 1);

    typedef std::pair<double,double> point_type;
    typedef std::vector<point_type> linear_ring;
    boost::ptr_vector<linear_ring> rings;

    double x = 0;
    double y = 0;
    std::size_t size = 1 + 4 + 4 ; // byteOrder + wkbType + numRings
    for (unsigned i=0; i< num_points; ++i)
    {
        unsigned command = g.vertex(i,&x,&y);
        if (command == SEG_MOVETO)
        {
            rings.push_back(new linear_ring); // start new loop
            rings.back().push_back(std::make_pair(x,y));
            size += 4; // num_points
            size += 2 * 8; // point
        }
        else if (command == SEG_LINETO)
        {
            rings.back().push_back(std::make_pair(x,y));
            size += 2 * 8; // point
        }
    }
    unsigned num_rings = rings.size();
    wkb_buffer_ptr wkb(new wkb_buffer(size));
    wkb_stream ss(wkb->buffer(), wkb->size());
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::geometry_type::types::Polygon);
    write(ss,type,4,byte_order);
    write(ss,num_rings,4,byte_order);

    for ( linear_ring const& ring : rings)
    {
        unsigned num_ring_points = ring.size();
        write(ss,num_ring_points,4,byte_order);
        for ( point_type const& pt : ring)
        {
            write(ss,pt.first,8,byte_order);
            write(ss,pt.second,8,byte_order);
        }
    }

    assert(ss.good());
    return std::move(wkb);
}
示例#10
0
QByteArray QgsCircularString::asWkb() const
{
  int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
  binarySize += numPoints() * ( 2 + is3D() + isMeasure() ) * sizeof( double );

  QByteArray wkbArray;
  wkbArray.resize( binarySize );
  QgsWkbPtr wkb( wkbArray );
  wkb << static_cast<char>( QgsApplication::endian() );
  wkb << static_cast<quint32>( wkbType() );
  QgsPointSequence pts;
  points( pts );
  QgsGeometryUtils::pointsToWKB( wkb, pts, is3D(), isMeasure() );
  return wkbArray;
}
示例#11
0
wkb_buffer_ptr to_point_wkb( GeometryType const& g, wkbByteOrder byte_order)
{
    assert(g.size() == 1);
    std::size_t size = 1 + 4 + 8*2 ; // byteOrder + wkbType + Point
    wkb_buffer_ptr wkb(new wkb_buffer(size));
    wkb_stream ss(wkb->buffer(), wkb->size());
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::geometry_type::types::Point);
    write(ss,type,4,byte_order);
    double x = 0;
    double y = 0;
    g.vertex(0,&x,&y);
    write(ss,x,8,byte_order);
    write(ss,y,8,byte_order);
    assert(ss.good());
    return std::move(wkb);
}
示例#12
0
unsigned char* QgsGeometryCollectionV2::asWkb( int& binarySize ) const
{
  binarySize = wkbSize();
  unsigned char* geomPtr = new unsigned char[binarySize];
  QgsWkbPtr wkb( geomPtr );
  wkb << static_cast<char>( QgsApplication::endian() );
  wkb << static_cast<quint32>( wkbType() );
  wkb << static_cast<quint32>( mGeometries.size() );
  Q_FOREACH ( const QgsAbstractGeometryV2 *geom, mGeometries )
  {
    int geomWkbLen = 0;
    if ( geom )
    {
      unsigned char* geomWkb = geom->asWkb( geomWkbLen );
      memcpy( wkb, geomWkb, geomWkbLen );
      wkb += geomWkbLen;
      delete[] geomWkb;
    }
  }
示例#13
0
wkb_buffer_ptr to_line_string_wkb( GeometryType const& g, wkbByteOrder byte_order)
{
    unsigned num_points = g.size();
    assert(num_points > 1);
    std::size_t size = 1 + 4 + 4 + 8*2*num_points ; // byteOrder + wkbType + numPoints + Point*numPoints
    wkb_buffer_ptr wkb(new wkb_buffer(size));
    wkb_stream ss(wkb->buffer(), wkb->size());
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::geometry_type::types::LineString);
    write(ss,type,4,byte_order);
    write(ss,num_points,4,byte_order);
    double x = 0;
    double y = 0;
    for (unsigned i=0; i< num_points; ++i)
    {
        g.vertex(i,&x,&y);
        write(ss,x,8,byte_order);
        write(ss,y,8,byte_order);
    }
    assert(ss.good());
    return std::move(wkb);
}
示例#14
0
//
// Convert a QgsGeometry into a SpatiaLite geometry BLOB
void qgsGeometryToSpatialiteBlob( const QgsGeometry &geom, int32_t srid, char *&blob, int &size )
{
  const int header_len = SpatialiteBlobHeader::LENGTH;

  QByteArray wkb( geom.exportToWkb() );

  const int wkb_size = wkb.length();
  size = header_len + wkb_size;
  blob = new char[size];

  char *p = blob;

  // write the header
  SpatialiteBlobHeader pHeader;
  QgsRectangle bbox = const_cast<QgsGeometry &>( geom ).boundingBox(); // boundingBox should be const
  pHeader.srid = srid;
  pHeader.mbrMinX = bbox.xMinimum();
  pHeader.mbrMinY = bbox.yMinimum();
  pHeader.mbrMaxX = bbox.xMaximum();
  pHeader.mbrMaxY = bbox.yMaximum();
  pHeader.writeTo( blob );

  p += header_len;

  // wkb of the geometry is
  // name         size    value
  // endianness     1      01
  // type           4      int

  // blob geometry = header + wkb[1:] + 'end'

  // copy wkb
  memcpy( p, wkb.constData() + 1, wkb_size - 1 );
  p += wkb_size - 1;

  // end marker
  *p = '\xFE';
}
示例#15
0
QByteArray QgsCompoundCurve::asWkb() const
{
  int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
  QVector<QByteArray> wkbForCurves;
  for ( const QgsCurve *curve : mCurves )
  {
    QByteArray wkbForCurve = curve->asWkb();
    binarySize += wkbForCurve.length();
    wkbForCurves << wkbForCurve;
  }

  QByteArray wkbArray;
  wkbArray.resize( binarySize );
  QgsWkbPtr wkb( wkbArray );
  wkb << static_cast<char>( QgsApplication::endian() );
  wkb << static_cast<quint32>( wkbType() );
  wkb << static_cast<quint32>( mCurves.size() );
  for ( const QByteArray &wkbForCurve : qgis::as_const( wkbForCurves ) )
  {
    wkb << wkbForCurve;
  }
  return wkbArray;
}
示例#16
0
bool QgsGPXProvider::addFeature( QgsFeature &f )
{
  QByteArray wkb( f.geometry().exportToWkb() );
  const char *geo = wkb.constData();
  QgsWkbTypes::Type wkbType = f.geometry().wkbType();
  bool success = false;
  QgsGPSObject *obj = nullptr;
  QgsAttributes attrs = f.attributes();
  QgsAttributeMap::const_iterator it;

  // is it a waypoint?
  if ( mFeatureType == WaypointType && geo && wkbType == QgsWkbTypes::Point )
  {

    // add geometry
    QgsWaypoint wpt;
    std::memcpy( &wpt.lon, geo + 5, sizeof( double ) );
    std::memcpy( &wpt.lat, geo + 13, sizeof( double ) );

    // add waypoint-specific attributes
    for ( int i = 0; i < attrs.count(); ++i )
    {
      if ( indexToAttr.at( i ) == EleAttr )
      {
        bool eleIsOK;
        double ele = attrs.at( i ).toDouble( &eleIsOK );
        if ( eleIsOK )
          wpt.ele = ele;
      }
      else if ( indexToAttr.at( i ) == SymAttr )
      {
        wpt.sym = attrs.at( i ).toString();
      }
    }

    QgsGPSData::WaypointIterator iter = data->addWaypoint( wpt );
    success = true;
    obj = &( *iter );
  }

  // is it a route?
  if ( mFeatureType == RouteType && geo && wkbType == QgsWkbTypes::LineString )
  {

    QgsRoute rte;

    // reset bounds
    rte.xMin = std::numeric_limits<double>::max();
    rte.xMax = -std::numeric_limits<double>::max();
    rte.yMin = std::numeric_limits<double>::max();
    rte.yMax = -std::numeric_limits<double>::max();

    // add geometry
    int nPoints;
    std::memcpy( &nPoints, geo + 5, 4 );
    for ( int i = 0; i < nPoints; ++i )
    {
      double lat, lon;
      std::memcpy( &lon, geo + 9 + 16 * i, sizeof( double ) );
      std::memcpy( &lat, geo + 9 + 16 * i + 8, sizeof( double ) );
      QgsRoutepoint rtept;
      rtept.lat = lat;
      rtept.lon = lon;
      rte.points.push_back( rtept );
      rte.xMin = rte.xMin < lon ? rte.xMin : lon;
      rte.xMax = rte.xMax > lon ? rte.xMax : lon;
      rte.yMin = rte.yMin < lat ? rte.yMin : lat;
      rte.yMax = rte.yMax > lat ? rte.yMax : lat;
    }

    // add route-specific attributes
    for ( int i = 0; i < attrs.count(); ++i )
    {
      if ( indexToAttr.at( i ) == NumAttr )
      {
        bool numIsOK;
        long num = attrs.at( i ).toInt( &numIsOK );
        if ( numIsOK )
          rte.number = num;
      }
    }

    QgsGPSData::RouteIterator iter = data->addRoute( rte );
    success = true;
    obj = &( *iter );
  }

  // is it a track?
  if ( mFeatureType == TrackType && geo && wkbType == QgsWkbTypes::LineString )
  {

    QgsTrack trk;
    QgsTrackSegment trkseg;

    // reset bounds
    trk.xMin = std::numeric_limits<double>::max();
    trk.xMax = -std::numeric_limits<double>::max();
    trk.yMin = std::numeric_limits<double>::max();
    trk.yMax = -std::numeric_limits<double>::max();

    // add geometry
    int nPoints;
    std::memcpy( &nPoints, geo + 5, 4 );
    for ( int i = 0; i < nPoints; ++i )
    {
      double lat, lon;
      std::memcpy( &lon, geo + 9 + 16 * i, sizeof( double ) );
      std::memcpy( &lat, geo + 9 + 16 * i + 8, sizeof( double ) );
      QgsTrackpoint trkpt;
      trkpt.lat = lat;
      trkpt.lon = lon;
      trkseg.points.push_back( trkpt );
      trk.xMin = trk.xMin < lon ? trk.xMin : lon;
      trk.xMax = trk.xMax > lon ? trk.xMax : lon;
      trk.yMin = trk.yMin < lat ? trk.yMin : lat;
      trk.yMax = trk.yMax > lat ? trk.yMax : lat;
    }

    // add track-specific attributes
    for ( int i = 0; i < attrs.count(); ++i )
    {
      if ( indexToAttr.at( i ) == NumAttr )
      {
        bool numIsOK;
        long num = attrs.at( i ).toInt( &numIsOK );
        if ( numIsOK )
          trk.number = num;
      }
    }

    trk.segments.push_back( trkseg );
    QgsGPSData::TrackIterator iter = data->addTrack( trk );
    success = true;
    obj = &( *iter );
  }


  // add common attributes
  if ( obj )
  {
    for ( int i = 0; i < attrs.count(); ++i )
    {
      switch ( indexToAttr.at( i ) )
      {
        case NameAttr:
          obj->name    = attrs.at( i ).toString();
          break;
        case CmtAttr:
          obj->cmt     = attrs.at( i ).toString();
          break;
        case DscAttr:
          obj->desc    = attrs.at( i ).toString();
          break;
        case SrcAttr:
          obj->src     = attrs.at( i ).toString();
          break;
        case URLAttr:
          obj->url     = attrs.at( i ).toString();
          break;
        case URLNameAttr:
          obj->urlname = attrs.at( i ).toString();
          break;
      }
    }
  }

  return success;
}
示例#17
0
void QgsOSMDatabase::exportSpatiaLiteNodes( const QString &tableName, const QStringList &tagKeys, const QStringList &notNullTagKeys )
{
  QString sqlInsertPoint = QStringLiteral( "INSERT INTO %1 VALUES (?" ).arg( quotedIdentifier( tableName ) );
  for ( int i = 0; i < tagKeys.count(); ++i )
    sqlInsertPoint += QStringLiteral( ",?" );
  sqlInsertPoint += QLatin1String( ", GeomFromWKB(?, 4326))" );
  sqlite3_stmt *stmtInsert = nullptr;
  if ( sqlite3_prepare_v2( mDatabase, sqlInsertPoint.toUtf8().constData(), -1, &stmtInsert, nullptr ) != SQLITE_OK )
  {
    mError = QStringLiteral( "Prepare SELECT FROM nodes failed." );
    return;
  }

  QgsOSMNodeIterator nodes = listNodes();
  QgsOSMNode n;
  while ( ( n = nodes.next() ).isValid() )
  {
    QgsOSMTags t = tags( false, n.id() );

    // skip untagged nodes: probably they form a part of ways
    if ( t.count() == 0 )
      continue;

    //check not null tags
    bool skipNull = false;
    for ( int i = 0; i < notNullTagKeys.count() && !skipNull; ++i )
      if ( !t.contains( notNullTagKeys[i] ) )
        skipNull = true;

    if ( skipNull )
      continue;

    QgsGeometry geom = QgsGeometry::fromPoint( n.point() );
    int col = 0;
    sqlite3_bind_int64( stmtInsert, ++col, n.id() );

    // tags
    for ( int i = 0; i < tagKeys.count(); ++i )
    {
      if ( t.contains( tagKeys[i] ) )
        sqlite3_bind_text( stmtInsert, ++col, t.value( tagKeys[i] ).toUtf8().constData(), -1, SQLITE_TRANSIENT );
      else
        sqlite3_bind_null( stmtInsert, ++col );
    }

    QByteArray wkb( geom.exportToWkb() );
    sqlite3_bind_blob( stmtInsert, ++col, wkb.constData(), wkb.length(), SQLITE_STATIC );

    int insertRes = sqlite3_step( stmtInsert );
    if ( insertRes != SQLITE_DONE )
    {
      mError = QStringLiteral( "Error inserting node %1 [%2]" ).arg( n.id() ).arg( insertRes );
      break;
    }

    sqlite3_reset( stmtInsert );
    sqlite3_clear_bindings( stmtInsert );
  }

  sqlite3_finalize( stmtInsert );
}
示例#18
0
int QgsTINInterpolator::insertData( QgsFeature* f, bool zCoord, int attr, InputType type )
{
  if ( !f )
  {
    return 1;
  }

  QgsGeometry g = f->geometry();
  {
    if ( g.isNull() )
    {
      return 2;
    }
  }

  //check attribute value
  double attributeValue = 0;
  bool attributeConversionOk = false;
  if ( !zCoord )
  {
    QVariant attributeVariant = f->attribute( attr );
    if ( !attributeVariant.isValid() ) //attribute not found, something must be wrong (e.g. NULL value)
    {
      return 3;
    }
    attributeValue = attributeVariant.toDouble( &attributeConversionOk );
    if ( !attributeConversionOk || qIsNaN( attributeValue ) ) //don't consider vertices with attributes like 'nan' for the interpolation
    {
      return 4;
    }
  }

  //parse WKB. It is ugly, but we cannot use the methods with QgsPoint because they don't contain z-values for 25D types
  bool hasZValue = false;
  double x, y, z;
  QByteArray wkb( g.exportToWkb() );
  QgsConstWkbPtr currentWkbPtr( wkb );
  currentWkbPtr.readHeader();
  //maybe a structure or break line
  Line3D* line = nullptr;

  QgsWkbTypes::Type wkbType = g.wkbType();
  switch ( wkbType )
  {
    case QgsWkbTypes::Point25D:
      hasZValue = true;
      FALLTHROUGH;
    case QgsWkbTypes::Point:
    {
      currentWkbPtr >> x >> y;
      if ( zCoord && hasZValue )
      {
        currentWkbPtr >> z;
      }
      else
      {
        z = attributeValue;
      }
      Point3D* thePoint = new Point3D( x, y, z );
      if ( mTriangulation->addPoint( thePoint ) == -100 )
      {
        return -1;
      }
      break;
    }
示例#19
0
void QgsOSMDatabase::exportSpatiaLiteWays( bool closed, const QString &tableName,
    const QStringList &tagKeys,
    const QStringList &notNullTagKeys )
{
  Q_UNUSED( tagKeys );

  QString sqlInsertLine = QStringLiteral( "INSERT INTO %1 VALUES (?" ).arg( quotedIdentifier( tableName ) );
  for ( int i = 0; i < tagKeys.count(); ++i )
    sqlInsertLine += QStringLiteral( ",?" );
  sqlInsertLine += QLatin1String( ", GeomFromWKB(?, 4326))" );
  sqlite3_stmt *stmtInsert = nullptr;
  if ( sqlite3_prepare_v2( mDatabase, sqlInsertLine.toUtf8().constData(), -1, &stmtInsert, nullptr ) != SQLITE_OK )
  {
    mError = QStringLiteral( "Prepare SELECT FROM ways failed." );
    return;
  }

  QgsOSMWayIterator ways = listWays();
  QgsOSMWay w;
  while ( ( w = ways.next() ).isValid() )
  {
    QgsOSMTags t = tags( true, w.id() );

    QgsPolyline polyline = wayPoints( w.id() );

    if ( polyline.count() < 2 )
      continue; // invalid way

    bool isArea = ( polyline.first() == polyline.last() ); // closed way?
    // filter out closed way that are not areas through tags
    if ( isArea && ( t.contains( QStringLiteral( "highway" ) ) || t.contains( QStringLiteral( "barrier" ) ) ) )
    {
      // make sure tags that indicate areas are taken into consideration when deciding on a closed way is or isn't an area
      // and allow for a closed way to be exported both as a polygon and a line in case both area and non-area tags are present
      if ( ( t.value( QStringLiteral( "area" ) ) != QLatin1String( "yes" ) && !t.contains( QStringLiteral( "amenity" ) ) && !t.contains( QStringLiteral( "landuse" ) ) && !t.contains( QStringLiteral( "building" ) ) && !t.contains( QStringLiteral( "natural" ) ) && !t.contains( QStringLiteral( "leisure" ) ) && !t.contains( QStringLiteral( "aeroway" ) ) ) || !closed )
        isArea = false;
    }

    if ( closed != isArea )
      continue; // skip if it's not what we're looking for

    //check not null tags
    bool skipNull = false;
    for ( int i = 0; i < notNullTagKeys.count() && !skipNull; ++i )
      if ( !t.contains( notNullTagKeys[i] ) )
        skipNull = true;

    if ( skipNull )
      continue;

    QgsGeometry geom = closed ? QgsGeometry::fromPolygon( QgsPolygon() << polyline ) : QgsGeometry::fromPolyline( polyline );
    int col = 0;
    sqlite3_bind_int64( stmtInsert, ++col, w.id() );

    // tags
    for ( int i = 0; i < tagKeys.count(); ++i )
    {
      if ( t.contains( tagKeys[i] ) )
        sqlite3_bind_text( stmtInsert, ++col, t.value( tagKeys[i] ).toUtf8().constData(), -1, SQLITE_TRANSIENT );
      else
        sqlite3_bind_null( stmtInsert, ++col );
    }

    if ( !geom.isNull() )
    {
      QByteArray wkb( geom.exportToWkb() );
      sqlite3_bind_blob( stmtInsert, ++col, wkb.constData(), wkb.length(), SQLITE_STATIC );
    }
    else
      sqlite3_bind_null( stmtInsert, ++col );

    int insertRes = sqlite3_step( stmtInsert );
    if ( insertRes != SQLITE_DONE )
    {
      mError = QStringLiteral( "Error inserting way %1 [%2]" ).arg( w.id() ).arg( insertRes );
      break;
    }

    sqlite3_reset( stmtInsert );
    sqlite3_clear_bindings( stmtInsert );
  }

  sqlite3_finalize( stmtInsert );
}