bool QgsCurvePolygon::fromWkb( QgsConstWkbPtr &wkbPtr ) { clear(); if ( !wkbPtr ) { return false; } QgsWkbTypes::Type type = wkbPtr.readHeader(); if ( QgsWkbTypes::flatType( type ) != QgsWkbTypes::CurvePolygon ) { return false; } mWkbType = type; int nRings; wkbPtr >> nRings; std::unique_ptr< QgsCurve > currentCurve; for ( int i = 0; i < nRings; ++i ) { QgsWkbTypes::Type curveType = wkbPtr.readHeader(); wkbPtr -= 1 + sizeof( int ); QgsWkbTypes::Type flatCurveType = QgsWkbTypes::flatType( curveType ); if ( flatCurveType == QgsWkbTypes::LineString ) { currentCurve.reset( new QgsLineString() ); } else if ( flatCurveType == QgsWkbTypes::CircularString ) { currentCurve.reset( new QgsCircularString() ); } else if ( flatCurveType == QgsWkbTypes::CompoundCurve ) { currentCurve.reset( new QgsCompoundCurve() ); } else { return false; } currentCurve->fromWkb( wkbPtr ); // also updates wkbPtr if ( i == 0 ) { mExteriorRing = std::move( currentCurve ); } else { mInteriorRings.append( currentCurve.release() ); } } return true; }
QgsConstWkbPtr QgsClipper::clippedLineWKB( QgsConstWkbPtr wkbPtr, const QgsRectangle& clipExtent, QPolygonF& line ) { QgsWKBTypes::Type wkbType = wkbPtr.readHeader(); int nPoints; wkbPtr >> nPoints; int skipZM = ( QgsWKBTypes::coordDimensions( wkbType ) - 2 ) * sizeof( double ); if ( static_cast<int>( nPoints * ( 2 * sizeof( double ) + skipZM ) ) > wkbPtr.remaining() ) { QgsDebugMsg( QString( "%1 points exceed wkb length (%2>%3)" ).arg( nPoints ).arg( nPoints * ( 2 * sizeof( double ) + skipZM ) ).arg( wkbPtr.remaining() ) ); return QgsConstWkbPtr( nullptr, 0 ); } double p0x, p0y, p1x = 0.0, p1y = 0.0; //original coordinates double p1x_c, p1y_c; //clipped end coordinates double lastClipX = 0.0, lastClipY = 0.0; //last successfully clipped coords line.clear(); line.reserve( nPoints + 1 ); for ( int i = 0; i < nPoints; ++i ) { if ( i == 0 ) { wkbPtr >> p1x >> p1y; wkbPtr += skipZM; continue; } else {
bool QgsPolygonV2::fromWkb( QgsConstWkbPtr wkbPtr ) { clear(); if ( !wkbPtr ) { return false; } QgsWKBTypes::Type type = wkbPtr.readHeader(); if ( QgsWKBTypes::flatType( type ) != QgsWKBTypes::Polygon ) { return false; } mWkbType = type; QgsWKBTypes::Type ringType; switch ( mWkbType ) { case QgsWKBTypes::PolygonZ: ringType = QgsWKBTypes::LineStringZ; break; case QgsWKBTypes::PolygonM: ringType = QgsWKBTypes::LineStringM; break; case QgsWKBTypes::PolygonZM: ringType = QgsWKBTypes::LineStringZM; break; case QgsWKBTypes::Polygon25D: ringType = QgsWKBTypes::LineString25D; break; default: ringType = QgsWKBTypes::LineString; break; } int nRings; wkbPtr >> nRings; for ( int i = 0; i < nRings; ++i ) { QgsLineStringV2* line = new QgsLineStringV2(); line->fromWkbPoints( ringType, wkbPtr ); /*if ( !line->isRing() ) { delete line; continue; }*/ if ( !mExteriorRing ) { mExteriorRing = line; } else { mInteriorRings.append( line ); } } return true; }
bool QgsCompoundCurve::fromWkb( QgsConstWkbPtr &wkbPtr ) { clear(); if ( !wkbPtr ) { return false; } QgsWkbTypes::Type type = wkbPtr.readHeader(); if ( QgsWkbTypes::flatType( type ) != QgsWkbTypes::CompoundCurve ) { return false; } mWkbType = type; int nCurves; wkbPtr >> nCurves; QgsCurve *currentCurve = nullptr; for ( int i = 0; i < nCurves; ++i ) { QgsWkbTypes::Type curveType = wkbPtr.readHeader(); wkbPtr -= 1 + sizeof( int ); if ( QgsWkbTypes::flatType( curveType ) == QgsWkbTypes::LineString ) { currentCurve = new QgsLineString(); } else if ( QgsWkbTypes::flatType( curveType ) == QgsWkbTypes::CircularString ) { currentCurve = new QgsCircularString(); } else { return false; } currentCurve->fromWkb( wkbPtr ); // also updates wkbPtr mCurves.append( currentCurve ); } return true; }
QgsConstWkbPtr QgsSymbolV2::_getLineString( QPolygonF& pts, QgsRenderContext& context, QgsConstWkbPtr wkbPtr, bool clipToExtent ) { QgsWKBTypes::Type wkbType = wkbPtr.readHeader(); unsigned int nPoints; wkbPtr >> nPoints; const QgsCoordinateTransform* ct = context.coordinateTransform(); const QgsMapToPixel& mtp = context.mapToPixel(); //apply clipping for large lines to achieve a better rendering performance if ( clipToExtent && nPoints > 1 ) { const QgsRectangle& e = context.extent(); double cw = e.width() / 10; double ch = e.height() / 10; QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch ); wkbPtr -= 1 + 2 * sizeof( int ); wkbPtr = QgsClipper::clippedLineWKB( wkbPtr, clipRect, pts ); } else { pts.resize( nPoints ); int skipZM = ( QgsWKBTypes::coordDimensions( wkbType ) - 2 ) * sizeof( double ); Q_ASSERT( skipZM >= 0 ); QPointF *ptr = pts.data(); for ( unsigned int i = 0; i < nPoints; ++i, ++ptr ) { wkbPtr >> ptr->rx() >> ptr->ry(); wkbPtr += skipZM; } } //transform the QPolygonF to screen coordinates if ( ct ) { ct->transformPolygon( pts ); } QPointF *ptr = pts.data(); for ( int i = 0; i < pts.size(); ++i, ++ptr ) { mtp.transformInPlace( ptr->rx(), ptr->ry() ); } return wkbPtr; }
bool QgsTriangle::fromWkb( QgsConstWkbPtr &wkbPtr ) { clear(); if ( !wkbPtr ) { return false; } QgsWkbTypes::Type type = wkbPtr.readHeader(); if ( QgsWkbTypes::flatType( type ) != QgsWkbTypes::Triangle ) { return false; } mWkbType = type; QgsWkbTypes::Type ringType; switch ( mWkbType ) { case QgsWkbTypes::TriangleZ: ringType = QgsWkbTypes::LineStringZ; break; case QgsWkbTypes::TriangleM: ringType = QgsWkbTypes::LineStringM; break; case QgsWkbTypes::TriangleZM: ringType = QgsWkbTypes::LineStringZM; break; default: ringType = QgsWkbTypes::LineString; break; } int nRings; wkbPtr >> nRings; if ( nRings > 1 ) { return false; } QgsLineString *line = new QgsLineString(); line->fromWkbPoints( ringType, wkbPtr ); if ( !mExteriorRing ) { mExteriorRing = line; } return true; }
bool QgsLineString::fromWkb( QgsConstWkbPtr &wkbPtr ) { if ( !wkbPtr ) { return false; } QgsWkbTypes::Type type = wkbPtr.readHeader(); if ( QgsWkbTypes::flatType( type ) != QgsWkbTypes::LineString ) { return false; } mWkbType = type; importVerticesFromWkb( wkbPtr ); return true; }
bool QgsCircularString::fromWkb( QgsConstWkbPtr &wkbPtr ) { if ( !wkbPtr ) return false; QgsWkbTypes::Type type = wkbPtr.readHeader(); if ( QgsWkbTypes::flatType( type ) != QgsWkbTypes::CircularString ) { return false; } clearCache(); mWkbType = type; //type bool hasZ = is3D(); bool hasM = isMeasure(); int nVertices = 0; wkbPtr >> nVertices; mX.resize( nVertices ); mY.resize( nVertices ); hasZ ? mZ.resize( nVertices ) : mZ.clear(); hasM ? mM.resize( nVertices ) : mM.clear(); for ( int i = 0; i < nVertices; ++i ) { wkbPtr >> mX[i]; wkbPtr >> mY[i]; if ( hasZ ) { wkbPtr >> mZ[i]; } if ( hasM ) { wkbPtr >> mM[i]; } } return true; }
std::unique_ptr<QgsAbstractGeometry> QgsGeometryFactory::geomFromWkb( QgsConstWkbPtr &wkbPtr ) { if ( !wkbPtr ) return nullptr; //find out type (bytes 2-5) QgsWkbTypes::Type type = QgsWkbTypes::Unknown; try { type = wkbPtr.readHeader(); } catch ( const QgsWkbException &e ) { Q_UNUSED( e ); QgsDebugMsg( "WKB exception while reading header: " + e.what() ); return nullptr; } wkbPtr -= 1 + sizeof( int ); std::unique_ptr< QgsAbstractGeometry > geom = geomFromWkbType( type ); if ( geom ) { try { geom->fromWkb( wkbPtr ); // also updates wkbPtr } catch ( const QgsWkbException &e ) { Q_UNUSED( e ); QgsDebugMsg( "WKB exception: " + e.what() ); geom.reset(); } } return geom; }
bool QgsGeometryCollection::fromWkb( QgsConstWkbPtr &wkbPtr ) { if ( !wkbPtr ) { return false; } QgsWkbTypes::Type wkbType = wkbPtr.readHeader(); if ( QgsWkbTypes::flatType( wkbType ) != QgsWkbTypes::flatType( mWkbType ) ) return false; mWkbType = wkbType; int nGeometries = 0; wkbPtr >> nGeometries; QVector<QgsAbstractGeometry *> geometryListBackup = mGeometries; mGeometries.clear(); for ( int i = 0; i < nGeometries; ++i ) { std::unique_ptr< QgsAbstractGeometry > geom( QgsGeometryFactory::geomFromWkb( wkbPtr ) ); // also updates wkbPtr if ( geom ) { if ( !addGeometry( geom.release() ) ) { qDeleteAll( mGeometries ); mGeometries = geometryListBackup; return false; } } } qDeleteAll( geometryListBackup ); clearCache(); //set bounding box invalid return true; }
QgsConstWkbPtr QgsSymbolV2::_getPolygon( QPolygonF &pts, QList<QPolygonF> &holes, QgsRenderContext &context, QgsConstWkbPtr wkbPtr, bool clipToExtent ) { QgsWKBTypes::Type wkbType = wkbPtr.readHeader(); QgsDebugMsg( QString( "wkbType=%1" ).arg( wkbType ) ); unsigned int numRings; wkbPtr >> numRings; if ( numRings == 0 ) // sanity check for zero rings in polygon return wkbPtr; holes.clear(); const QgsCoordinateTransform* ct = context.coordinateTransform(); const QgsMapToPixel& mtp = context.mapToPixel(); const QgsRectangle& e = context.extent(); double cw = e.width() / 10; double ch = e.height() / 10; QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch ); int skipZM = ( QgsWKBTypes::coordDimensions( wkbType ) - 2 ) * sizeof( double ); Q_ASSERT( skipZM >= 0 ); for ( unsigned int idx = 0; idx < numRings; idx++ ) { unsigned int nPoints; wkbPtr >> nPoints; QPolygonF poly( nPoints ); QPointF *ptr = poly.data(); for ( unsigned int jdx = 0; jdx < nPoints; ++jdx, ++ptr ) { wkbPtr >> ptr->rx() >> ptr->ry(); wkbPtr += skipZM; } if ( nPoints < 1 ) continue; //clip close to view extent, if needed QRectF ptsRect = poly.boundingRect(); if ( clipToExtent && !context.extent().contains( ptsRect ) ) { QgsClipper::trimPolygon( poly, clipRect ); } //transform the QPolygonF to screen coordinates if ( ct ) { ct->transformPolygon( poly ); } ptr = poly.data(); for ( int i = 0; i < poly.size(); ++i, ++ptr ) { mtp.transformInPlace( ptr->rx(), ptr->ry() ); } if ( idx == 0 ) pts = poly; else holes.append( poly ); } return wkbPtr; }
//! Simplify the WKB-geometry using the specified tolerance bool QgsMapToPixelSimplifier::simplifyWkbGeometry( int simplifyFlags, SimplifyAlgorithm simplifyAlgorithm, QGis::WkbType wkbType, QgsConstWkbPtr sourceWkbPtr, QgsWkbPtr targetWkbPtr, int &targetWkbSize, const QgsRectangle &envelope, double map2pixelTol, bool writeHeader, bool isaLinearRing ) { bool isGeneralizable = true; bool result = false; // Save initial WKB settings to use when the simplification creates invalid geometries QgsConstWkbPtr sourcePrevWkbPtr( sourceWkbPtr ); QgsWkbPtr targetPrevWkbPtr( targetWkbPtr ); int targetWkbPrevSize = targetWkbSize; // Can replace the geometry by its BBOX ? if (( simplifyFlags & QgsMapToPixelSimplifier::SimplifyEnvelope ) && isGeneralizableByMapBoundingBox( envelope, map2pixelTol ) ) { isGeneralizable = generalizeWkbGeometryByBoundingBox( wkbType, sourceWkbPtr, targetWkbPtr, targetWkbSize, envelope, writeHeader ); if ( isGeneralizable ) return true; } if ( !( simplifyFlags & QgsMapToPixelSimplifier::SimplifyGeometry ) ) isGeneralizable = false; // Write the main header of the geometry if ( writeHeader ) { QgsWKBTypes::Type geometryType = sourceWkbPtr.readHeader(); targetWkbPtr << ( char ) QgsApplication::endian() << QgsWKBTypes::flatType( geometryType ); targetWkbSize += targetWkbPtr - targetPrevWkbPtr; } unsigned int flatType = QGis::flatType( wkbType ); // Write the geometry if ( flatType == QGis::WKBLineString || isaLinearRing ) { QgsWkbPtr savedTargetWkbPtr( targetWkbPtr ); double x = 0.0, y = 0.0, lastX = 0, lastY = 0; QgsRectangle r; r.setMinimal(); int skipZM = ( QGis::wkbDimensions( wkbType ) - 2 ) * sizeof( double ); Q_ASSERT( skipZM >= 0 ); int numPoints; sourceWkbPtr >> numPoints; if ( numPoints <= ( isaLinearRing ? 5 : 2 ) ) isGeneralizable = false; QgsWkbPtr numPtr( targetWkbPtr ); int numTargetPoints = 0; targetWkbPtr << numTargetPoints; targetWkbSize += 4; bool isLongSegment; bool hasLongSegments = false; //-> To avoid replace the simplified geometry by its BBOX when there are 'long' segments. bool badLuck = false; // Check whether the LinearRing is really closed. if ( isaLinearRing ) { QgsConstWkbPtr checkPtr( sourceWkbPtr ); double x1, y1, x2, y2; checkPtr >> x1 >> y1; checkPtr += skipZM + ( numPoints - 2 ) * ( 2 * sizeof( double ) + skipZM ); checkPtr >> x2 >> y2; isaLinearRing = qgsDoubleNear( x1, x2 ) && qgsDoubleNear( y1, y2 ); } // Process each vertex... if ( simplifyAlgorithm == SnapToGrid ) { double gridOriginX = envelope.xMinimum(); double gridOriginY = envelope.yMinimum(); // Use a factor for the maximum displacement distance for simplification, similar as GeoServer does float gridInverseSizeXY = map2pixelTol != 0 ? ( float )( 1.0f / ( 0.8 * map2pixelTol ) ) : 0.0f; for ( int i = 0; i < numPoints; ++i ) { sourceWkbPtr >> x >> y; sourceWkbPtr += skipZM; if ( i == 0 || !isGeneralizable || !equalSnapToGrid( x, y, lastX, lastY, gridOriginX, gridOriginY, gridInverseSizeXY ) || ( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) ) { targetWkbPtr << x << y; lastX = x; lastY = y; numTargetPoints++; } r.combineExtentWith( x, y ); } }
QgsConstWkbPtr QgsClipper::clippedLineWKB( QgsConstWkbPtr& wkbPtr, const QgsRectangle& clipExtent, QPolygonF& line ) { QgsWKBTypes::Type wkbType = wkbPtr.readHeader(); int nPoints; wkbPtr >> nPoints; int skipZM = ( QgsWKBTypes::coordDimensions( wkbType ) - 2 ) * sizeof( double ); if ( static_cast<int>( nPoints * ( 2 * sizeof( double ) + skipZM ) ) > wkbPtr.remaining() ) { QgsDebugMsg( QString( "%1 points exceed wkb length (%2>%3)" ).arg( nPoints ).arg( nPoints * ( 2 * sizeof( double ) + skipZM ) ).arg( wkbPtr.remaining() ) ); return QgsConstWkbPtr( nullptr, 0 ); } double p0x, p0y, p1x = 0.0, p1y = 0.0; //original coordinates double p1x_c, p1y_c; //clipped end coordinates double lastClipX = 0.0, lastClipY = 0.0; //last successfully clipped coords QPolygonF pts; wkbPtr -= sizeof( unsigned int ); wkbPtr >> pts; nPoints = pts.size(); line.clear(); line.reserve( nPoints + 1 ); QPointF *ptr = pts.data(); for ( int i = 0; i < nPoints; ++i, ++ptr ) { if ( i == 0 ) { p1x = ptr->rx(); p1y = ptr->ry(); continue; } else { p0x = p1x; p0y = p1y; p1x = ptr->rx(); p1y = ptr->ry(); p1x_c = p1x; p1y_c = p1y; if ( clipLineSegment( clipExtent.xMinimum(), clipExtent.xMaximum(), clipExtent.yMinimum(), clipExtent.yMaximum(), p0x, p0y, p1x_c, p1y_c ) ) { bool newLine = !line.isEmpty() && ( !qgsDoubleNear( p0x, lastClipX ) || !qgsDoubleNear( p0y, lastClipY ) ); if ( newLine ) { //add edge points to connect old and new line connectSeparatedLines( lastClipX, lastClipY, p0x, p0y, clipExtent, line ); } if ( line.size() < 1 || newLine ) { //add first point line << QPointF( p0x, p0y ); } //add second point lastClipX = p1x_c; lastClipY = p1y_c; line << QPointF( p1x_c, p1y_c ); } } } return wkbPtr; }
QgsConstWkbPtr QgsDistanceArea::measurePolygon( QgsConstWkbPtr wkbPtr, double* area, double* perimeter, bool hasZptr ) const { if ( !wkbPtr ) { QgsDebugMsg( "no feature to measure" ); return wkbPtr; } wkbPtr.readHeader(); // get number of rings in the polygon int numRings; wkbPtr >> numRings; if ( numRings == 0 ) { QgsDebugMsg( "no rings to measure" ); return QgsConstWkbPtr( nullptr, 0 ); } // Set pointer to the first ring QList<QgsPoint> points; QgsPoint pnt; double x, y; if ( area ) *area = 0; if ( perimeter ) *perimeter = 0; try { for ( int idx = 0; idx < numRings; idx++ ) { int nPoints; wkbPtr >> nPoints; // Extract the points from the WKB and store in a pair of // vectors. for ( int jdx = 0; jdx < nPoints; jdx++ ) { wkbPtr >> x >> y; if ( hasZptr ) { // totally ignore Z value wkbPtr += sizeof( double ); } pnt = QgsPoint( x, y ); if ( mEllipsoidalMode && ( mEllipsoid != GEO_NONE ) ) { pnt = mCoordTransform.transform( pnt ); } points.append( pnt ); } if ( points.size() > 2 ) { if ( area ) { double areaTmp = computePolygonArea( points ); if ( idx == 0 ) { // exterior ring *area += areaTmp; } else { *area -= areaTmp; // interior rings } } if ( perimeter ) { if ( idx == 0 ) { // exterior ring *perimeter += computeDistance( points ); } } } points.clear(); } } catch ( QgsCsException &cse ) { Q_UNUSED( cse ); QgsMessageLog::logMessage( QObject::tr( "Caught a coordinate system exception while trying to transform a point. Unable to calculate polygon area or perimeter." ) ); } return wkbPtr; }