//! Simplifies the geometry (Removing duplicated points) when is applied the specified map2pixel context bool QgsMapToPixelSimplifier::simplifyGeometry( QgsGeometry* geometry, int simplifyFlags, double tolerance ) { size_t targetWkbSize = 0; // Check whether the geometry can be simplified using the map2pixel context QGis::GeometryType geometryType = geometry->type(); if ( !( geometryType == QGis::Line || geometryType == QGis::Polygon ) ) return false; QgsRectangle envelope = geometry->boundingBox(); QGis::WkbType wkbType = geometry->wkbType(); unsigned char* wkb = ( unsigned char* )geometry->asWkb( ); size_t wkbSize = geometry->wkbSize( ); // Simplify the geometry rewriting temporally its WKB-stream for saving calloc's. if ( simplifyWkbGeometry( simplifyFlags, wkbType, wkb, wkbSize, wkb, targetWkbSize, envelope, tolerance ) ) { unsigned char* targetWkb = new unsigned char[targetWkbSize]; memcpy( targetWkb, wkb, targetWkbSize ); geometry->fromWkb( targetWkb, targetWkbSize ); return true; } return false; }
//! Simplifies the geometry (Removing duplicated points) when is applied the specified map2pixel context bool QgsMapToPixelSimplifier::simplifyGeometry( QgsGeometry* geometry, int simplifyFlags, double tolerance ) { size_t finalWkbSize = 0; // Check whether the geometry can be simplified using the map2pixel context QGis::GeometryType geometryType = geometry->type(); if ( !( geometryType == QGis::Line || geometryType == QGis::Polygon ) ) return false; QgsRectangle envelope = geometry->boundingBox(); QGis::WkbType wkbType = geometry->wkbType(); const unsigned char* wkb = geometry->asWkb(); size_t wkbSize = geometry->wkbSize(); unsigned char* targetWkb = new unsigned char[wkbSize]; memcpy( targetWkb, wkb, wkbSize ); if ( simplifyWkbGeometry( simplifyFlags, wkbType, wkb, wkbSize, targetWkb, finalWkbSize, envelope, tolerance ) ) { unsigned char* finalWkb = new unsigned char[finalWkbSize]; memcpy( finalWkb, targetWkb, finalWkbSize ); geometry->fromWkb( finalWkb, finalWkbSize ); delete [] targetWkb; return true; } delete [] targetWkb; return false; }
//! Simplify the WKB-geometry using the specified tolerance bool QgsMapToPixelSimplifier::simplifyWkbGeometry( int simplifyFlags, QGis::WkbType wkbType, unsigned char* sourceWkb, size_t sourceWkbSize, unsigned char* targetWkb, size_t& targetWkbSize, const QgsRectangle& envelope, double map2pixelTol, bool writeHeader, bool isaLinearRing ) { bool isGeneralizable = true; bool hasZValue = QGis::wkbDimensions( wkbType ) == 3; bool result = false; // Save initial WKB settings to use when the simplification creates invalid geometries unsigned char* sourcePrevWkb = sourceWkb; unsigned char* targetPrevWkb = targetWkb; size_t targetWkbPrevSize = targetWkbSize; // Can replace the geometry by its BBOX ? if (( simplifyFlags & QgsMapToPixelSimplifier::SimplifyEnvelope ) && isGeneralizableByMapBoundingBox( envelope, map2pixelTol ) ) { isGeneralizable = generalizeWkbGeometry( wkbType, sourceWkb, sourceWkbSize, targetWkb, targetWkbSize, envelope, writeHeader ); if ( isGeneralizable ) return true; } if ( !( simplifyFlags & QgsMapToPixelSimplifier::SimplifyGeometry ) ) isGeneralizable = false; // Write the main header of the geometry if ( writeHeader ) { targetWkb[0] = sourceWkb[0]; // byteOrder sourceWkb += 1; targetWkb += 1; int geometryType; memcpy( &geometryType, sourceWkb, 4 ); int flatType = QGis::flatType(( QGis::WkbType )geometryType ); memcpy( targetWkb, &flatType, 4 ); // type sourceWkb += 4; targetWkb += 4; targetWkbSize += 5; } unsigned char* wkb1 = sourceWkb; unsigned char* wkb2 = targetWkb; unsigned int flatType = QGis::flatType( wkbType ); // Write the geometry if ( flatType == QGis::WKBLineString || isaLinearRing ) { double x, y, lastX = 0, lastY = 0; QgsRectangle r; r.setMinimal(); int sizeOfDoubleX = sizeof( double ); int sizeOfDoubleY = QGis::wkbDimensions( wkbType ) == 3 /*hasZValue*/ ? 2 * sizeof( double ) : sizeof( double ); int numPoints; memcpy( &numPoints, sourceWkb, 4 ); sourceWkb += 4; if ( numPoints <= ( isaLinearRing ? 5 : 2 ) ) isGeneralizable = false; int numTargetPoints = 0; memcpy( targetWkb, &numTargetPoints, 4 ); targetWkb += 4; targetWkbSize += 4; double* ptr = ( double* )targetWkb; map2pixelTol *= map2pixelTol; //-> Use mappixelTol for 'LengthSquare' calculations. // Check whether the LinearRing is really closed. if ( isaLinearRing ) { double x1, y1, x2, y2; unsigned char* startWkbX = sourceWkb; unsigned char* startWkbY = startWkbX + sizeOfDoubleX; unsigned char* finalWkbX = sourceWkb + ( numPoints - 1 ) * ( sizeOfDoubleX + sizeOfDoubleY ); unsigned char* finalWkbY = finalWkbX + sizeOfDoubleX; memcpy( &x1, startWkbX, sizeof( double ) ); memcpy( &y1, startWkbY, sizeof( double ) ); memcpy( &x2, finalWkbX, sizeof( double ) ); memcpy( &y2, finalWkbY, sizeof( double ) ); isaLinearRing = ( x1 == x2 ) && ( y1 == y2 ); } // Process each vertex... for ( int i = 0; i < numPoints; ++i ) { memcpy( &x, sourceWkb, sizeof( double ) ); sourceWkb += sizeOfDoubleX; memcpy( &y, sourceWkb, sizeof( double ) ); sourceWkb += sizeOfDoubleY; if ( i == 0 || !isGeneralizable || calculateLengthSquared2D( x, y, lastX, lastY ) > map2pixelTol || ( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) ) { memcpy( ptr, &x, sizeof( double ) ); lastX = x; ptr++; memcpy( ptr, &y, sizeof( double ) ); lastY = y; ptr++; numTargetPoints++; } r.combineExtentWith( x, y ); } targetWkb = wkb2 + 4; // Fix the topology of the geometry if ( numTargetPoints <= ( isaLinearRing ? 2 : 1 ) ) { unsigned char* targetTempWkb = targetWkb; int targetWkbTempSize = targetWkbSize; sourceWkb = sourcePrevWkb; targetWkb = targetPrevWkb; targetWkbSize = targetWkbPrevSize; if ( generalizeWkbGeometry( wkbType, sourceWkb, sourceWkbSize, targetWkb, targetWkbSize, r, writeHeader ) ) return true; targetWkb = targetTempWkb; targetWkbSize = targetWkbTempSize; } if ( isaLinearRing ) { memcpy( &x, targetWkb + 0, sizeof( double ) ); memcpy( &y, targetWkb + sizeof( double ), sizeof( double ) ); if ( lastX != x || lastY != y ) { memcpy( ptr, &x, sizeof( double ) ); ptr++; memcpy( ptr, &y, sizeof( double ) ); ptr++; numTargetPoints++; } } targetWkbSize += numTargetPoints * sizeof( double ) * 2; targetWkb = wkb2; memcpy( targetWkb, &numTargetPoints, 4 ); result = numPoints != numTargetPoints; } else if ( flatType == QGis::WKBPolygon ) { int numRings; memcpy( &numRings, sourceWkb, 4 ); sourceWkb += 4; memcpy( targetWkb, &numRings, 4 ); targetWkb += 4; targetWkbSize += 4; for ( int i = 0; i < numRings; ++i ) { int numPoints_i; memcpy( &numPoints_i, sourceWkb, 4 ); QgsRectangle envelope_i = numRings == 1 ? envelope : calculateBoundingBox( wkbType, sourceWkb + 4, numPoints_i ); size_t sourceWkbSize_i = 4 + numPoints_i * ( hasZValue ? 3 : 2 ) * sizeof( double ); size_t targetWkbSize_i = 0; result |= simplifyWkbGeometry( simplifyFlags, wkbType, sourceWkb, sourceWkbSize_i, targetWkb, targetWkbSize_i, envelope_i, map2pixelTol, false, true ); sourceWkb += sourceWkbSize_i; targetWkb += targetWkbSize_i; targetWkbSize += targetWkbSize_i; } } else if ( flatType == QGis::WKBMultiLineString || flatType == QGis::WKBMultiPolygon ) { int numGeoms; memcpy( &numGeoms, sourceWkb, 4 ); sourceWkb += 4; wkb1 += 4; memcpy( targetWkb, &numGeoms, 4 ); targetWkb += 4; targetWkbSize += 4; for ( int i = 0; i < numGeoms; ++i ) { size_t sourceWkbSize_i = 0; size_t targetWkbSize_i = 0; // ... calculate the wkb-size of the current child complex geometry if ( flatType == QGis::WKBMultiLineString ) { int numPoints_i; memcpy( &numPoints_i, wkb1 + 5, 4 ); int wkbSize_i = 4 + numPoints_i * ( hasZValue ? 3 : 2 ) * sizeof( double ); sourceWkbSize_i += 5 + wkbSize_i; wkb1 += 5 + wkbSize_i; } else { int numPrings_i; memcpy( &numPrings_i, wkb1 + 5, 4 ); sourceWkbSize_i = 9; wkb1 += 9; for ( int j = 0; j < numPrings_i; ++j ) { int numPoints_i; memcpy( &numPoints_i, wkb1, 4 ); int wkbSize_i = 4 + numPoints_i * ( hasZValue ? 3 : 2 ) * sizeof( double ); sourceWkbSize_i += wkbSize_i; wkb1 += wkbSize_i; } } result |= simplifyWkbGeometry( simplifyFlags, QGis::singleType( wkbType ), sourceWkb, sourceWkbSize_i, targetWkb, targetWkbSize_i, envelope, map2pixelTol, true, false ); sourceWkb += sourceWkbSize_i; targetWkb += targetWkbSize_i; targetWkbSize += targetWkbSize_i; } } return result; }
//! Simplify the WKB-geometry using the specified tolerance bool QgsMapToPixelSimplifier::simplifyWkbGeometry( int simplifyFlags, QGis::WkbType wkbType, unsigned char* sourceWkb, size_t sourceWkbSize, unsigned char* targetWkb, size_t& targetWkbSize, const QgsRectangle& envelope, double map2pixelTol, bool writeHeader, bool isaLinearRing ) { bool canbeGeneralizable = true; bool hasZValue = QGis::wkbDimensions( wkbType ) == 3; bool result = false; // Can replace the geometry by its BBOX ? if (( simplifyFlags & QgsMapToPixelSimplifier::SimplifyEnvelope ) && ( envelope.xMaximum() - envelope.xMinimum() ) < map2pixelTol && ( envelope.yMaximum() - envelope.yMinimum() ) < map2pixelTol ) { canbeGeneralizable = generalizeWkbGeometry( wkbType, sourceWkb, sourceWkbSize, targetWkb, targetWkbSize, envelope, writeHeader ); if ( canbeGeneralizable ) return true; } if ( !( simplifyFlags & QgsMapToPixelSimplifier::SimplifyGeometry ) ) canbeGeneralizable = false; // Write the main header of the geometry if ( writeHeader ) { memcpy( targetWkb, sourceWkb, 1 ); // byteOrder sourceWkb += 1; targetWkb += 1; int geometryType; memcpy( &geometryType, sourceWkb, 4 ); int flatType = QGis::flatType(( QGis::WkbType )geometryType ); memcpy( targetWkb, &flatType, 4 ); // type sourceWkb += 4; targetWkb += 4; targetWkbSize += 5; } unsigned char* wkb1 = sourceWkb; unsigned char* wkb2 = targetWkb; unsigned int flatType = QGis::flatType( wkbType ); // Write the geometry if ( flatType == QGis::WKBLineString || isaLinearRing ) { double x, y, lastX = 0, lastY = 0; int sizeOfDoubleX = sizeof( double ); int sizeOfDoubleY = QGis::wkbDimensions( wkbType ) == 3 /*hasZValue*/ ? 2 * sizeof( double ) : sizeof( double ); int numPoints; memcpy( &numPoints, sourceWkb, 4 ); sourceWkb += 4; if ( numPoints <= ( isaLinearRing ? 5 : 2 ) ) canbeGeneralizable = false; int numTargetPoints = 0; memcpy( targetWkb, &numTargetPoints, 4 ); targetWkb += 4; targetWkbSize += 4; double* ptr = ( double* )targetWkb; map2pixelTol *= map2pixelTol; //-> Use mappixelTol for 'LengthSquare' calculations. // Process each vertex... for ( int i = 0, numPoints_i = ( isaLinearRing ? numPoints - 1 : numPoints ); i < numPoints_i; ++i ) { memcpy( &x, sourceWkb, sizeof( double ) ); sourceWkb += sizeOfDoubleX; memcpy( &y, sourceWkb, sizeof( double ) ); sourceWkb += sizeOfDoubleY; if ( i == 0 || !canbeGeneralizable || QgsMapToPixelSimplifier::calculateLengthSquared2D( x, y, lastX, lastY ) > map2pixelTol || ( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) ) { memcpy( ptr, &x, sizeof( double ) ); lastX = x; ptr++; memcpy( ptr, &y, sizeof( double ) ); lastY = y; ptr++; numTargetPoints++; } } targetWkb = wkb2 + 4; // Fix the topology of the geometry if ( isaLinearRing ) { memcpy( &x, targetWkb + 0, sizeof( double ) ); memcpy( &y, targetWkb + 8, sizeof( double ) ); memcpy( ptr, &x, sizeof( double ) ); ptr++; memcpy( ptr, &y, sizeof( double ) ); ptr++; numTargetPoints++; } targetWkbSize += numTargetPoints * 16; targetWkb = wkb2; memcpy( targetWkb, &numTargetPoints, 4 ); result = numPoints != numTargetPoints; } else if ( flatType == QGis::WKBPolygon ) { int numRings; memcpy( &numRings, sourceWkb, 4 ); sourceWkb += 4; memcpy( targetWkb, &numRings, 4 ); targetWkb += 4; targetWkbSize += 4; for ( int i = 0; i < numRings; ++i ) { int numPoints_i; memcpy( &numPoints_i, sourceWkb, 4 ); QgsRectangle envelope_i = numRings == 1 ? envelope : calculateBoundingBox( wkbType, sourceWkb + 4, numPoints_i ); size_t sourceWkbSize_i = 4 + numPoints_i * ( hasZValue ? 3 : 2 ) * sizeof( double ); size_t targetWkbSize_i = 0; result |= simplifyWkbGeometry( simplifyFlags, wkbType, sourceWkb, sourceWkbSize_i, targetWkb, targetWkbSize_i, envelope_i, map2pixelTol, false, true ); sourceWkb += sourceWkbSize_i; targetWkb += targetWkbSize_i; targetWkbSize += targetWkbSize_i; } } else if ( flatType == QGis::WKBMultiLineString || flatType == QGis::WKBMultiPolygon ) { int numGeoms; memcpy( &numGeoms, sourceWkb, 4 ); sourceWkb += 4; wkb1 += 4; memcpy( targetWkb, &numGeoms, 4 ); targetWkb += 4; targetWkbSize += 4; for ( int i = 0; i < numGeoms; ++i ) { size_t sourceWkbSize_i = 0; size_t targetWkbSize_i = 0; // ... calculate the wkb-size of the current child complex geometry if ( flatType == QGis::WKBMultiLineString ) { int numPoints_i; memcpy( &numPoints_i, wkb1 + 5, 4 ); int wkbSize_i = 4 + numPoints_i * ( hasZValue ? 3 : 2 ) * sizeof( double ); sourceWkbSize_i += 5 + wkbSize_i; wkb1 += 5 + wkbSize_i; } else { int numPrings_i; memcpy( &numPrings_i, wkb1 + 5, 4 ); sourceWkbSize_i = 9; wkb1 += 9; for ( int j = 0; j < numPrings_i; ++j ) { int numPoints_i; memcpy( &numPoints_i, wkb1, 4 ); int wkbSize_i = 4 + numPoints_i * ( hasZValue ? 3 : 2 ) * sizeof( double ); sourceWkbSize_i += wkbSize_i; wkb1 += wkbSize_i; } } result |= simplifyWkbGeometry( simplifyFlags, QGis::singleType( wkbType ), sourceWkb, sourceWkbSize_i, targetWkb, targetWkbSize_i, envelope, map2pixelTol, true, false ); sourceWkb += sourceWkbSize_i; targetWkb += targetWkbSize_i; targetWkbSize += targetWkbSize_i; } } return result; }
//! Simplify the WKB-geometry using the specified tolerance bool QgsMapToPixelSimplifier::simplifyWkbGeometry( int simplifyFlags, QGis::WkbType wkbType, const unsigned char* sourceWkb, size_t sourceWkbSize, unsigned char* targetWkb, size_t& targetWkbSize, const QgsRectangle& envelope, double map2pixelTol, bool writeHeader, bool isaLinearRing ) { bool isGeneralizable = true; bool hasZValue = QGis::wkbDimensions( wkbType ) == 3; bool result = false; // Save initial WKB settings to use when the simplification creates invalid geometries const unsigned char* sourcePrevWkb = sourceWkb; unsigned char* targetPrevWkb = targetWkb; size_t targetWkbPrevSize = targetWkbSize; // Can replace the geometry by its BBOX ? if (( simplifyFlags & QgsMapToPixelSimplifier::SimplifyEnvelope ) && isGeneralizableByMapBoundingBox( envelope, map2pixelTol ) ) { isGeneralizable = generalizeWkbGeometryByBoundingBox( wkbType, sourceWkb, sourceWkbSize, targetWkb, targetWkbSize, envelope, writeHeader ); if ( isGeneralizable ) return true; } if ( !( simplifyFlags & QgsMapToPixelSimplifier::SimplifyGeometry ) ) isGeneralizable = false; // Write the main header of the geometry if ( writeHeader ) { targetWkb[0] = sourceWkb[0]; // byteOrder sourceWkb += 1; targetWkb += 1; int geometryType; memcpy( &geometryType, sourceWkb, 4 ); int flatType = QGis::flatType(( QGis::WkbType )geometryType ); memcpy( targetWkb, &flatType, 4 ); // type sourceWkb += 4; targetWkb += 4; targetWkbSize += 5; } const unsigned char* wkb1 = sourceWkb; unsigned char* wkb2 = targetWkb; unsigned int flatType = QGis::flatType( wkbType ); // Write the geometry if ( flatType == QGis::WKBLineString || isaLinearRing ) { double x, y, lastX = 0, lastY = 0; QgsRectangle r; r.setMinimal(); int sizeOfDoubleX = sizeof( double ); int sizeOfDoubleY = QGis::wkbDimensions( wkbType ) == 3 /*hasZValue*/ ? 2 * sizeof( double ) : sizeof( double ); int numPoints; memcpy( &numPoints, sourceWkb, 4 ); sourceWkb += 4; if ( numPoints <= ( isaLinearRing ? 5 : 2 ) ) isGeneralizable = false; int numTargetPoints = 0; memcpy( targetWkb, &numTargetPoints, 4 ); targetWkb += 4; targetWkbSize += 4; double* ptr = ( double* )targetWkb; map2pixelTol *= map2pixelTol; //-> Use mappixelTol for 'LengthSquare' calculations. bool isLongSegment; bool hasLongSegments = false; //-> To avoid replace the simplified geometry by its BBOX when there are 'long' segments. // Check whether the LinearRing is really closed. if ( isaLinearRing ) { double x1, y1, x2, y2; const unsigned char* startWkbX = sourceWkb; const unsigned char* startWkbY = startWkbX + sizeOfDoubleX; const unsigned char* finalWkbX = sourceWkb + ( numPoints - 1 ) * ( sizeOfDoubleX + sizeOfDoubleY ); const unsigned char* finalWkbY = finalWkbX + sizeOfDoubleX; memcpy( &x1, startWkbX, sizeof( double ) ); memcpy( &y1, startWkbY, sizeof( double ) ); memcpy( &x2, finalWkbX, sizeof( double ) ); memcpy( &y2, finalWkbY, sizeof( double ) ); isaLinearRing = ( x1 == x2 ) && ( y1 == y2 ); } // Process each vertex... for ( int i = 0; i < numPoints; ++i ) { memcpy( &x, sourceWkb, sizeof( double ) ); sourceWkb += sizeOfDoubleX; memcpy( &y, sourceWkb, sizeof( double ) ); sourceWkb += sizeOfDoubleY; isLongSegment = false; if ( i == 0 || !isGeneralizable || ( isLongSegment = ( calculateLengthSquared2D( x, y, lastX, lastY ) > map2pixelTol ) ) || ( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) ) { memcpy( ptr, &x, sizeof( double ) ); lastX = x; ptr++; memcpy( ptr, &y, sizeof( double ) ); lastY = y; ptr++; numTargetPoints++; hasLongSegments |= isLongSegment; } r.combineExtentWith( x, y ); } targetWkb = wkb2 + 4; if ( numTargetPoints < ( isaLinearRing ? 4 : 2 ) ) { // we simplified the geometry too much! if ( !hasLongSegments ) { // approximate the geometry's shape by its bounding box // (rect for linear ring / one segment for line string) unsigned char* targetTempWkb = targetWkb; size_t targetWkbTempSize = targetWkbSize; sourceWkb = sourcePrevWkb; targetWkb = targetPrevWkb; targetWkbSize = targetWkbPrevSize; if ( generalizeWkbGeometryByBoundingBox( wkbType, sourceWkb, sourceWkbSize, targetWkb, targetWkbSize, r, writeHeader ) ) return true; targetWkb = targetTempWkb; targetWkbSize = targetWkbTempSize; } else { // Bad luck! The simplified geometry is invalid and approximation by bounding box // would create artifacts due to long segments. Worst of all, we may have overwritten // the original coordinates by the simplified ones (source and target WKB ptr can be the same) // so we cannot even undo the changes here. We will return invalid geometry and hope that // other pieces of QGIS will survive that :-/ } } if ( isaLinearRing ) { // make sure we keep the linear ring closed memcpy( &x, targetWkb + 0, sizeof( double ) ); memcpy( &y, targetWkb + sizeof( double ), sizeof( double ) ); if ( lastX != x || lastY != y ) { memcpy( ptr, &x, sizeof( double ) ); ptr++; memcpy( ptr, &y, sizeof( double ) ); ptr++; numTargetPoints++; } } targetWkbSize += numTargetPoints * sizeof( double ) * 2; targetWkb = wkb2; memcpy( targetWkb, &numTargetPoints, 4 ); result = numPoints != numTargetPoints; } else if ( flatType == QGis::WKBPolygon ) { int numRings; memcpy( &numRings, sourceWkb, 4 ); sourceWkb += 4; memcpy( targetWkb, &numRings, 4 ); targetWkb += 4; targetWkbSize += 4; for ( int i = 0; i < numRings; ++i ) { int numPoints_i; memcpy( &numPoints_i, sourceWkb, 4 ); QgsRectangle envelope_i = numRings == 1 ? envelope : calculateBoundingBox( wkbType, sourceWkb + 4, numPoints_i ); size_t sourceWkbSize_i = 4 + numPoints_i * ( hasZValue ? 3 : 2 ) * sizeof( double ); size_t targetWkbSize_i = 0; result |= simplifyWkbGeometry( simplifyFlags, wkbType, sourceWkb, sourceWkbSize_i, targetWkb, targetWkbSize_i, envelope_i, map2pixelTol, false, true ); sourceWkb += sourceWkbSize_i; targetWkb += targetWkbSize_i; targetWkbSize += targetWkbSize_i; } } else if ( flatType == QGis::WKBMultiLineString || flatType == QGis::WKBMultiPolygon ) { int numGeoms; memcpy( &numGeoms, sourceWkb, 4 ); sourceWkb += 4; wkb1 += 4; memcpy( targetWkb, &numGeoms, 4 ); targetWkb += 4; targetWkbSize += 4; for ( int i = 0; i < numGeoms; ++i ) { size_t sourceWkbSize_i = 0; size_t targetWkbSize_i = 0; // ... calculate the wkb-size of the current child complex geometry if ( flatType == QGis::WKBMultiLineString ) { int numPoints_i; memcpy( &numPoints_i, wkb1 + 5, 4 ); int wkbSize_i = 4 + numPoints_i * ( hasZValue ? 3 : 2 ) * sizeof( double ); sourceWkbSize_i += 5 + wkbSize_i; wkb1 += 5 + wkbSize_i; } else { int numPrings_i; memcpy( &numPrings_i, wkb1 + 5, 4 ); sourceWkbSize_i = 9; wkb1 += 9; for ( int j = 0; j < numPrings_i; ++j ) { int numPoints_i; memcpy( &numPoints_i, wkb1, 4 ); int wkbSize_i = 4 + numPoints_i * ( hasZValue ? 3 : 2 ) * sizeof( double ); sourceWkbSize_i += wkbSize_i; wkb1 += wkbSize_i; } } result |= simplifyWkbGeometry( simplifyFlags, QGis::singleType( wkbType ), sourceWkb, sourceWkbSize_i, targetWkb, targetWkbSize_i, envelope, map2pixelTol, true, false ); sourceWkb += sourceWkbSize_i; targetWkb += targetWkbSize_i; targetWkbSize += targetWkbSize_i; } } return result; }