void TestQgsCoordinateTransform::isShortCircuited() { QgsCoordinateTransform tr; //invalid transform shortcircuits QVERIFY( tr.isShortCircuited() ); QgsCoordinateReferenceSystem srs1; srs1.createFromSrid( 3994 ); QgsCoordinateReferenceSystem srs2; srs2.createFromSrid( 4326 ); // valid source, invalid destination QgsCoordinateTransform tr2( srs1, QgsCoordinateReferenceSystem() ); QVERIFY( tr2.isShortCircuited() ); // invalid source, valid destination QgsCoordinateTransform tr3( QgsCoordinateReferenceSystem(), srs2 ); QVERIFY( tr3.isShortCircuited() ); // equal, valid source and destination QgsCoordinateTransform tr4( srs1, srs1 ); QVERIFY( tr4.isShortCircuited() ); // valid but different source and destination QgsCoordinateTransform tr5( srs1, srs2 ); QVERIFY( !tr5.isShortCircuited() ); // try to short circuit by changing dest tr5.setDestinationCrs( srs1 ); QVERIFY( tr5.isShortCircuited() ); }
QgsCoordinateTransform QgsCoordinateTransformCache::transform( const QString& srcAuthId, const QString& destAuthId, int srcDatumTransform, int destDatumTransform ) { QList< QgsCoordinateTransform > values = mTransforms.values( qMakePair( srcAuthId, destAuthId ) ); QList< QgsCoordinateTransform >::const_iterator valIt = values.constBegin(); for ( ; valIt != values.constEnd(); ++valIt ) { if (( *valIt ).isValid() && ( *valIt ).sourceDatumTransform() == srcDatumTransform && ( *valIt ).destinationDatumTransform() == destDatumTransform ) { return *valIt; } } //not found, insert new value QgsCoordinateReferenceSystem srcCrs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( srcAuthId ); QgsCoordinateReferenceSystem destCrs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( destAuthId ); QgsCoordinateTransform ct = QgsCoordinateTransform( srcCrs, destCrs ); ct.setSourceDatumTransform( srcDatumTransform ); ct.setDestinationDatumTransform( destDatumTransform ); ct.initialise(); mTransforms.insertMulti( qMakePair( srcAuthId, destAuthId ), ct ); return ct; }
void TestQgsCoordinateTransform::assignment() { QgsCoordinateTransform uninitialized; QgsCoordinateTransform uninitializedCopy; uninitializedCopy = uninitialized; QVERIFY( !uninitializedCopy.isValid() ); QgsCoordinateReferenceSystem source; source.createFromId( 3111, QgsCoordinateReferenceSystem::EpsgCrsId ); QgsCoordinateReferenceSystem destination; destination.createFromId( 4326, QgsCoordinateReferenceSystem::EpsgCrsId ); QgsCoordinateTransform original( source, destination ); QVERIFY( original.isValid() ); QgsCoordinateTransform copy; copy = original; QVERIFY( copy.isValid() ); QCOMPARE( copy.sourceCrs().authid(), original.sourceCrs().authid() ); QCOMPARE( copy.destinationCrs().authid(), original.destinationCrs().authid() ); // force detachement of copy QgsCoordinateReferenceSystem newDest; newDest.createFromId( 3857, QgsCoordinateReferenceSystem::EpsgCrsId ); copy.setDestinationCrs( newDest ); QVERIFY( copy.isValid() ); QCOMPARE( copy.destinationCrs().authid(), QString( "EPSG:3857" ) ); QCOMPARE( original.destinationCrs().authid(), QString( "EPSG:4326" ) ); // test assigning back to invalid copy = uninitialized; QVERIFY( !copy.isValid() ); QVERIFY( original.isValid() ); }
void TestQgsCoordinateTransform::isValid() { QgsCoordinateTransform tr; QVERIFY( !tr.isValid() ); QgsCoordinateReferenceSystem srs1; srs1.createFromSrid( 3994 ); QgsCoordinateReferenceSystem srs2; srs2.createFromSrid( 4326 ); // valid source, invalid destination QgsCoordinateTransform tr2( srs1, QgsCoordinateReferenceSystem() ); QVERIFY( !tr2.isValid() ); // invalid source, valid destination QgsCoordinateTransform tr3( QgsCoordinateReferenceSystem(), srs2 ); QVERIFY( !tr3.isValid() ); // valid source, valid destination QgsCoordinateTransform tr4( srs1, srs2 ); QVERIFY( tr4.isValid() ); // try to invalidate by setting source as invalid tr4.setSourceCrs( QgsCoordinateReferenceSystem() ); QVERIFY( !tr4.isValid() ); QgsCoordinateTransform tr5( srs1, srs2 ); // try to invalidate by setting destination as invalid tr5.setDestinationCrs( QgsCoordinateReferenceSystem() ); QVERIFY( !tr5.isValid() ); }
QgsCoordinateTransform* QgsCoordinateTransform::clone() const { QgsCoordinateTransform* tr = new QgsCoordinateTransform( sourceCrs(), destCRS() ); tr->setSourceDatumTransform( sourceDatumTransform() ); tr->setDestinationDatumTransform( destinationDatumTransform() ); tr->initialise(); return tr; }
void QgsSpatialQueryDialog::zoomFeature( QgsVectorLayer* lyr, QgsFeatureId fid ) { static QgsVectorLayer* lyrCheck = NULL; static bool hasMsg = false; if ( ! lyrCheck || lyrCheck != lyr ) { lyrCheck = lyr; hasMsg = true; } else { hasMsg = false; } QgsFeature feat; if ( !lyr->getFeatures( QgsFeatureRequest().setFilterFid( fid ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( feat ) ) { return; } if ( !feat.geometry() ) { return; } // Set system reference QgsCoordinateReferenceSystem srsSource = lyr->dataProvider()->crs(); QgsCoordinateReferenceSystem srcMapcanvas = mIface->mapCanvas()->mapSettings().destinationCrs(); if ( ! srsSource.isValid() ) { if ( hasMsg ) { QString crsMapcanvas = srcMapcanvas.authid(); bool isFly = mIface->mapCanvas()->mapSettings().hasCrsTransformEnabled(); QString msgFly = tr( "Map \"%1\" \"on the fly\" transformation." ).arg( isFly ? tr( "enable" ) : tr( "disable" ) ); QString msg = tr( "Coordinate reference system(CRS) of\n\"%1\" is invalid(see CRS of provider)." ).arg( lyr->name() ); msg.append( tr( "\n\nCRS of map is %1.\n%2." ).arg( crsMapcanvas ).arg( msgFly ) ); msg.append( "\n\nUsing CRS of map for all features!" ); QMessageBox::warning( this, tr( "Zoom to feature" ), msg, QMessageBox::Ok ); } mIface->mapCanvas()->setExtent( feat.geometry()->boundingBox() ); } else if ( srsSource == srcMapcanvas ) { mIface->mapCanvas()->setExtent( feat.geometry()->boundingBox() ); } else { QgsCoordinateTransform * coordTransform = new QgsCoordinateTransform( srsSource, srcMapcanvas ); QgsRectangle rectExtent = coordTransform->transform( feat.geometry()->boundingBox() ); delete coordTransform; mIface->mapCanvas()->setExtent( rectExtent ); } mIface->mapCanvas()->refresh(); } // void QgsSpatialQueryDialog::zoomFeatureTarget(QgsVectorLayer* lyr, int fid)
void QgsGrassRegionEdit::calcSrcRegion() { mSrcRectangle.set( mStartPoint, mEndPoint ); if ( mCanvas->hasCrsTransformEnabled() && mCrs.isValid() && mCanvas->mapSettings().destinationCrs().isValid() ) { QgsCoordinateTransform coordinateTransform; coordinateTransform.setSourceCrs( mCanvas->mapSettings().destinationCrs() ); coordinateTransform.setDestinationCrs( mCrs ); mSrcRectangle = coordinateTransform.transformBoundingBox( mSrcRectangle ); } }
QgsPointXY QgsMapSettings::layerToMapCoordinates( const QgsMapLayer *layer, QgsPointXY point ) const { try { QgsCoordinateTransform ct = layerTransform( layer ); if ( ct.isValid() ) point = ct.transform( point, QgsCoordinateTransform::ForwardTransform ); } catch ( QgsCsException &cse ) { QgsMessageLog::logMessage( QObject::tr( "Transform error caught: %1" ).arg( cse.what() ), QObject::tr( "CRS" ) ); } return point; }
QgsRectangle QgsMapSettings::mapToLayerCoordinates( const QgsMapLayer *layer, QgsRectangle rect ) const { try { QgsCoordinateTransform ct = layerTransform( layer ); if ( ct.isValid() ) rect = ct.transform( rect, QgsCoordinateTransform::ReverseTransform ); } catch ( QgsCsException &cse ) { QgsMessageLog::logMessage( QObject::tr( "Transform error caught: %1" ).arg( cse.what() ), QObject::tr( "CRS" ) ); } return rect; }
void QgsGrassRegionEdit::drawRegion( QgsMapCanvas *canvas, QgsRubberBand* rubberBand, const QgsRectangle &rect, const QgsCoordinateTransform& coordinateTransform, bool isPolygon ) { QVector<QgsPoint> points; points.append( QgsPoint( rect.xMinimum(), rect.yMinimum() ) ); points.append( QgsPoint( rect.xMaximum(), rect.yMinimum() ) ); points.append( QgsPoint( rect.xMaximum(), rect.yMaximum() ) ); points.append( QgsPoint( rect.xMinimum(), rect.yMaximum() ) ); if ( !isPolygon ) { points.append( QgsPoint( rect.xMinimum(), rect.yMinimum() ) ); } if ( coordinateTransform.isValid() ) { transform( canvas, points, coordinateTransform ); } rubberBand->reset( isPolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry ); for ( int i = 0; i < points.size(); i++ ) { bool update = false; // true to update canvas if ( i == points.size() - 1 ) update = true; rubberBand->addPoint( points[i], update ); } rubberBand->show(); }
QgsRectangle QgsAbstractFeatureIterator::filterRectToSourceCrs( const QgsCoordinateTransform &transform ) const { if ( mRequest.filterRect().isNull() ) return QgsRectangle(); return transform.transformBoundingBox( mRequest.filterRect(), QgsCoordinateTransform::ReverseTransform ); }
int QgsMapToolCapture::addCurve( QgsCurve *c ) { if ( !c ) { return 1; } if ( !mRubberBand ) { mRubberBand = createRubberBand( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry ); } QgsLineString *lineString = c->curveToLine(); QgsPointSequence linePoints; lineString->points( linePoints ); delete lineString; QgsPointSequence::const_iterator ptIt = linePoints.constBegin(); for ( ; ptIt != linePoints.constEnd(); ++ptIt ) { mRubberBand->addPoint( QgsPointXY( ptIt->x(), ptIt->y() ) ); } if ( !mTempRubberBand ) { mTempRubberBand = createRubberBand( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, true ); } else { mTempRubberBand->reset(); } QgsPoint endPt = c->endPoint(); mTempRubberBand->addPoint( QgsPointXY( endPt.x(), endPt.y() ) ); //add last point of c //transform back to layer CRS in case map CRS and layer CRS are different QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() ); QgsCoordinateTransform ct = mCanvas->mapSettings().layerTransform( vlayer ); if ( ct.isValid() ) { c->transform( ct, QgsCoordinateTransform::ReverseTransform ); } mCaptureCurve.addCurve( c ); for ( int i = 0; i < c->length(); ++i ) mSnappingMatches.append( QgsPointLocator::Match() ); return 0; }
bool ProjectorData::checkRows( const QgsCoordinateTransform &ct ) { if ( !ct.isValid() ) { return false; } for ( int r = 0; r < mCPRows; r++ ) { for ( int c = 1; c < mCPCols - 1; c += 2 ) { double myDestX, myDestY; destPointOnCPMatrix( r, c, &myDestX, &myDestY ); QgsPointXY myDestPoint( myDestX, myDestY ); QgsPointXY mySrcPoint1 = mCPMatrix[r][c - 1]; QgsPointXY mySrcPoint2 = mCPMatrix[r][c]; QgsPointXY mySrcPoint3 = mCPMatrix[r][c + 1]; QgsPointXY mySrcApprox( ( mySrcPoint1.x() + mySrcPoint3.x() ) / 2, ( mySrcPoint1.y() + mySrcPoint3.y() ) / 2 ); if ( !mCPLegalMatrix[r][c - 1] || !mCPLegalMatrix[r][c] || !mCPLegalMatrix[r][c + 1] ) { // There was an error earlier in transform, just abort return false; } try { QgsPointXY myDestApprox = ct.transform( mySrcApprox, QgsCoordinateTransform::ReverseTransform ); double mySqrDist = myDestApprox.sqrDist( myDestPoint ); if ( mySqrDist > mSqrTolerance ) { return false; } } catch ( QgsCsException &e ) { Q_UNUSED( e ); // Caught an error in transform return false; } } } return true; }
bool QgsRasterProjector::extentSize( const QgsCoordinateTransform &ct, const QgsRectangle &srcExtent, int srcXSize, int srcYSize, QgsRectangle &destExtent, int &destXSize, int &destYSize ) { if ( srcExtent.isEmpty() || srcXSize <= 0 || srcYSize <= 0 ) { return false; } destExtent = ct.transformBoundingBox( srcExtent ); // We reproject pixel rectangle from 9 points matrix of source extent, of course, it gives // bigger xRes,yRes than reprojected edges (envelope) double srcXStep = srcExtent.width() / 3; double srcYStep = srcExtent.height() / 3; double srcXRes = srcExtent.width() / srcXSize; double srcYRes = srcExtent.height() / srcYSize; double destXRes = std::numeric_limits<double>::max(); double destYRes = std::numeric_limits<double>::max(); for ( int i = 0; i < 3; i++ ) { double x = srcExtent.xMinimum() + i * srcXStep; for ( int j = 0; j < 3; j++ ) { double y = srcExtent.yMinimum() + j * srcYStep; QgsRectangle srcRectangle( x - srcXRes / 2, y - srcYRes / 2, x + srcXRes / 2, y + srcYRes / 2 ); QgsRectangle destRectangle = ct.transformBoundingBox( srcRectangle ); if ( destRectangle.width() > 0 ) { destXRes = std::min( destXRes, destRectangle.width() ); } if ( destRectangle.height() > 0 ) { destYRes = std::min( destYRes, destRectangle.height() ); } } } destXSize = std::max( 1, static_cast< int >( destExtent.width() / destYRes ) ); destYSize = std::max( 1, static_cast< int >( destExtent.height() / destYRes ) ); return true; }
void GlobePlugin::syncExtent() { QgsMapCanvas* mapCanvas = mQGisIface->mapCanvas(); const QgsMapSettings &mapSettings = mapCanvas->mapSettings(); QgsRectangle extent = mapCanvas->extent(); long epsgGlobe = 4326; QgsCoordinateReferenceSystem globeCrs; globeCrs.createFromOgcWmsCrs( QString( "EPSG:%1" ).arg( epsgGlobe ) ); // transform extent to WGS84 if ( mapSettings.destinationCrs().authid().compare( QString( "EPSG:%1" ).arg( epsgGlobe ), Qt::CaseInsensitive ) != 0 ) { QgsCoordinateReferenceSystem srcCRS( mapSettings.destinationCrs() ); QgsCoordinateTransform* coordTransform = new QgsCoordinateTransform( srcCRS, globeCrs ); extent = coordTransform->transformBoundingBox( extent ); delete coordTransform; } osgEarth::Util::EarthManipulator* manip = dynamic_cast<osgEarth::Util::EarthManipulator*>( mOsgViewer->getCameraManipulator() ); //rotate earth to north and perpendicular to camera manip->setRotation( osg::Quat() ); QgsDistanceArea dist; dist.setSourceCrs( globeCrs ); dist.setEllipsoidalMode( true ); dist.setEllipsoid( "WGS84" ); QgsPoint ll = QgsPoint( extent.xMinimum(), extent.yMinimum() ); QgsPoint ul = QgsPoint( extent.xMinimum(), extent.yMaximum() ); double height = dist.measureLine( ll, ul ); //camera viewing angle double viewAngle = 30; //camera distance double distance = height / tan( viewAngle * osg::PI / 180 ); //c = b*cotan(B(rad)) OE_NOTICE << "map extent: " << height << " camera distance: " << distance << std::endl; osgEarth::Util::Viewpoint viewpoint( osg::Vec3d( extent.center().x(), extent.center().y(), 0.0 ), 0.0, -90.0, distance ); manip->setViewpoint( viewpoint, 4.0 ); }
void QgsMapRendererJob::drawOldLabeling( const QgsMapSettings& settings, QgsRenderContext& renderContext ) { // render all labels for vector layers in the stack, starting at the base QListIterator<QString> li( settings.layers() ); li.toBack(); while ( li.hasPrevious() ) { if ( renderContext.renderingStopped() ) { break; } QString layerId = li.previous(); QgsMapLayer *ml = QgsMapLayerRegistry::instance()->mapLayer( layerId ); if ( !ml || ( ml->type() != QgsMapLayer::VectorLayer ) ) continue; // only make labels if the layer is visible // after scale dep viewing settings are checked if ( !ml->isInScaleRange( settings.scale() ) ) continue; QgsRectangle r1 = settings.visibleExtent(), r2; QgsCoordinateTransform ct = settings.layerTransform( ml ); if ( settings.hasCrsTransformEnabled() ) { if ( ct.isValid() ) reprojectToLayerExtent( ml, ct, r1, r2 ); } renderContext.setCoordinateTransform( ct ); renderContext.setExtent( r1 ); ml->drawLabels( renderContext ); } }
QgsRectangle QgsMapSettings::outputExtentToLayerExtent( const QgsMapLayer *layer, QgsRectangle extent ) const { try { QgsCoordinateTransform ct = layerTransform( layer ); if ( ct.isValid() ) { QgsDebugMsgLevel( QStringLiteral( "sourceCrs = %1" ).arg( ct.sourceCrs().authid() ), 3 ); QgsDebugMsgLevel( QStringLiteral( "destCRS = %1" ).arg( ct.destinationCrs().authid() ), 3 ); QgsDebugMsgLevel( QStringLiteral( "extent = %1" ).arg( extent.toString() ), 3 ); extent = ct.transformBoundingBox( extent, QgsCoordinateTransform::ReverseTransform ); } } catch ( QgsCsException &cse ) { QgsMessageLog::logMessage( QObject::tr( "Transform error caught: %1" ).arg( cse.what() ), QObject::tr( "CRS" ) ); } QgsDebugMsgLevel( QStringLiteral( "proj extent = %1" ).arg( extent.toString() ), 3 ); return extent; }
void ProjectorData::calcCP( int row, int col, const QgsCoordinateTransform &ct ) { double myDestX, myDestY; destPointOnCPMatrix( row, col, &myDestX, &myDestY ); QgsPointXY myDestPoint( myDestX, myDestY ); try { if ( ct.isValid() ) { mCPMatrix[row][col] = ct.transform( myDestPoint ); mCPLegalMatrix[row][col] = true; } else { mCPLegalMatrix[row][col] = false; } } catch ( QgsCsException &e ) { Q_UNUSED( e ); // Caught an error in transform mCPLegalMatrix[row][col] = false; } }
void QgsGrassRegionEdit::transform( QgsMapCanvas *, QVector<QgsPointXY> &points, const QgsCoordinateTransform &coordinateTransform, QgsCoordinateTransform::TransformDirection direction ) { //! Coordinate transform //QgsDebugMsg ( "srcCrs = " + coordinateTransform->sourceCrs().toWkt() ); //QgsDebugMsg ( "destCrs = " + coordinateTransform->destCRS().toWkt() ); try { for ( int i = 0; i < points.size(); i++ ) { points[i] = coordinateTransform.transform( points[i], direction ); } } catch ( QgsCsException &cse ) { Q_UNUSED( cse ); QgsDebugMsg( QString( "transformation failed: %1" ).arg( cse.what() ) ); } }
void QgsLineStringV2::transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d ) { double* zArray = mZ.data(); bool hasZ = is3D(); int nPoints = numPoints(); if ( !hasZ ) { zArray = new double[nPoints]; for ( int i = 0; i < nPoints; ++i ) { zArray[i] = 0; } } ct.transformCoords( nPoints, mX.data(), mY.data(), zArray, d ); if ( !hasZ ) { delete[] zArray; } mBoundingBox = QgsRectangle(); }
void QgsLineString::transform( const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d, bool transformZ ) { double *zArray = nullptr; bool hasZ = is3D(); int nPoints = numPoints(); // it's possible that transformCoords will throw an exception - so we need to use // a smart pointer for the dummy z values in order to ensure that they always get cleaned up std::unique_ptr< double[] > dummyZ; if ( !hasZ || !transformZ ) { dummyZ.reset( new double[nPoints]() ); zArray = dummyZ.get(); } else { zArray = mZ.data(); } ct.transformCoords( nPoints, mX.data(), mY.data(), zArray, d ); clearCache(); }
void QgsAbstractFeatureIterator::geometryToDestinationCrs( QgsFeature &feature, const QgsCoordinateTransform &transform ) const { if ( transform.isValid() && feature.hasGeometry() ) { try { QgsGeometry g = feature.geometry(); g.transform( transform ); feature.setGeometry( g ); } catch ( QgsCsException & ) { // transform error if ( mRequest.transformErrorCallback() ) { mRequest.transformErrorCallback()( feature ); } // remove geometry - we can't reproject so better not return a geometry in a different crs feature.clearGeometry(); } } }
void QgsCircularStringV2::transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d ) { clearCache(); double* zArray = mZ.data(); bool hasZ = is3D(); int nPoints = numPoints(); if ( !hasZ ) { zArray = new double[nPoints]; for ( int i = 0; i < nPoints; ++i ) { zArray[i] = 0; } } ct.transformCoords( nPoints, mX.data(), mY.data(), zArray, d ); if ( !hasZ ) { delete[] zArray; } }
void QgsLineString::transform( const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d, bool transformZ ) { double *zArray = mZ.data(); bool hasZ = is3D(); int nPoints = numPoints(); bool useDummyZ = !hasZ || !transformZ; if ( useDummyZ ) { zArray = new double[nPoints]; for ( int i = 0; i < nPoints; ++i ) { zArray[i] = 0; } } ct.transformCoords( nPoints, mX.data(), mY.data(), zArray, d ); if ( useDummyZ ) { delete[] zArray; } clearCache(); }
bool QgsHeatmapRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker ) { Q_UNUSED( layer ); Q_UNUSED( selected ); Q_UNUSED( drawVertexMarker ); if ( !context.painter() ) { return false; } if ( !feature.hasGeometry() || feature.geometry().type() != QgsWkbTypes::PointGeometry ) { //can only render point type return false; } double weight = 1.0; if ( !mWeightExpressionString.isEmpty() ) { QVariant value; if ( mWeightAttrNum == -1 ) { Q_ASSERT( mWeightExpression.data() ); value = mWeightExpression->evaluate( &context.expressionContext() ); } else { QgsAttributes attrs = feature.attributes(); value = attrs.value( mWeightAttrNum ); } bool ok = false; double evalWeight = value.toDouble( &ok ); if ( ok ) { weight = evalWeight; } } int width = context.painter()->device()->width() / mRenderQuality; int height = context.painter()->device()->height() / mRenderQuality; //transform geometry if required QgsGeometry geom = feature.geometry(); QgsCoordinateTransform xform = context.coordinateTransform(); if ( xform.isValid() ) { geom.transform( xform ); } //convert point to multipoint QgsMultiPoint multiPoint = convertToMultipoint( &geom ); //loop through all points in multipoint for ( QgsMultiPoint::const_iterator pointIt = multiPoint.constBegin(); pointIt != multiPoint.constEnd(); ++pointIt ) { QgsPoint pixel = context.mapToPixel().transform( *pointIt ); int pointX = pixel.x() / mRenderQuality; int pointY = pixel.y() / mRenderQuality; for ( int x = qMax( pointX - mRadiusPixels, 0 ); x < qMin( pointX + mRadiusPixels, width ); ++x ) { for ( int y = qMax( pointY - mRadiusPixels, 0 ); y < qMin( pointY + mRadiusPixels, height ); ++y ) { int index = y * width + x; if ( index >= mValues.count() ) { continue; } double distanceSquared = pow( pointX - x, 2.0 ) + pow( pointY - y, 2.0 ); if ( distanceSquared > mRadiusSquared ) { continue; } double score = weight * quarticKernel( sqrt( distanceSquared ), mRadiusPixels ); double value = mValues.at( index ) + score; if ( value > mCalculatedMaxValue ) { mCalculatedMaxValue = value; } mValues[ index ] = value; } } } mFeaturesRendered++; #if 0 //TODO - enable progressive rendering if ( mFeaturesRendered % 200 == 0 ) { renderImage( context ); } #endif return true; }
QgsLabelFeature *QgsVectorLayerDiagramProvider::registerDiagram( QgsFeature &feat, QgsRenderContext &context, const QgsGeometry &obstacleGeometry ) { const QgsMapSettings &mapSettings = mEngine->mapSettings(); const QgsDiagramRenderer *dr = mSettings.renderer(); if ( dr ) { QList<QgsDiagramSettings> settingList = dr->diagramSettings(); if ( !settingList.isEmpty() && settingList.at( 0 ).scaleBasedVisibility ) { double maxScale = settingList.at( 0 ).maximumScale; if ( maxScale > 0 && context.rendererScale() < maxScale ) { return nullptr; } double minScale = settingList.at( 0 ).minimumScale; if ( minScale > 0 && context.rendererScale() > minScale ) { return nullptr; } } } // data defined show diagram? check this before doing any other processing if ( !mSettings.dataDefinedProperties().valueAsBool( QgsDiagramLayerSettings::Show, context.expressionContext(), true ) ) return nullptr; // data defined obstacle? bool isObstacle = mSettings.dataDefinedProperties().valueAsBool( QgsDiagramLayerSettings::IsObstacle, context.expressionContext(), mSettings.isObstacle() ); //convert geom to geos QgsGeometry geom = feat.geometry(); QgsGeometry extentGeom = QgsGeometry::fromRect( mapSettings.visibleExtent() ); if ( !qgsDoubleNear( mapSettings.rotation(), 0.0 ) ) { //PAL features are prerotated, so extent also needs to be unrotated extentGeom.rotate( -mapSettings.rotation(), mapSettings.visibleExtent().center() ); } geos::unique_ptr geomCopy; std::unique_ptr<QgsGeometry> scopedPreparedGeom; if ( QgsPalLabeling::geometryRequiresPreparation( geom, context, mSettings.coordinateTransform(), extentGeom ) ) { scopedPreparedGeom.reset( new QgsGeometry( QgsPalLabeling::prepareGeometry( geom, context, mSettings.coordinateTransform(), extentGeom ) ) ); QgsGeometry *preparedGeom = scopedPreparedGeom.get(); if ( preparedGeom->isNull() ) return nullptr; geomCopy = QgsGeos::asGeos( *preparedGeom ); } else { geomCopy = QgsGeos::asGeos( geom ); } if ( !geomCopy ) return nullptr; // invalid geometry geos::unique_ptr geosObstacleGeomClone; std::unique_ptr<QgsGeometry> scopedObstacleGeom; if ( isObstacle && obstacleGeometry && QgsPalLabeling::geometryRequiresPreparation( obstacleGeometry, context, mSettings.coordinateTransform(), extentGeom ) ) { QgsGeometry preparedObstacleGeom = QgsPalLabeling::prepareGeometry( obstacleGeometry, context, mSettings.coordinateTransform(), extentGeom ); geosObstacleGeomClone = QgsGeos::asGeos( preparedObstacleGeom ); } else if ( mSettings.isObstacle() && !obstacleGeometry.isNull() ) { geosObstacleGeomClone = QgsGeos::asGeos( obstacleGeometry ); } double diagramWidth = 0; double diagramHeight = 0; if ( dr ) { QSizeF diagSize = dr->sizeMapUnits( feat, context ); if ( diagSize.isValid() ) { diagramWidth = diagSize.width(); diagramHeight = diagSize.height(); } } // feature to the layer bool alwaysShow = mSettings.showAllDiagrams(); context.expressionContext().setOriginalValueVariable( alwaysShow ); alwaysShow = mSettings.dataDefinedProperties().valueAsBool( QgsDiagramLayerSettings::AlwaysShow, context.expressionContext(), alwaysShow ); // new style data defined position bool ddPos = false; double ddPosX = 0.0; double ddPosY = 0.0; if ( mSettings.dataDefinedProperties().hasProperty( QgsDiagramLayerSettings::PositionX ) && mSettings.dataDefinedProperties().property( QgsDiagramLayerSettings::PositionX ).isActive() && mSettings.dataDefinedProperties().hasProperty( QgsDiagramLayerSettings::PositionY ) && mSettings.dataDefinedProperties().property( QgsDiagramLayerSettings::PositionY ).isActive() ) { ddPosX = mSettings.dataDefinedProperties().valueAsDouble( QgsDiagramLayerSettings::PositionX, context.expressionContext(), std::numeric_limits<double>::quiet_NaN() ); ddPosY = mSettings.dataDefinedProperties().valueAsDouble( QgsDiagramLayerSettings::PositionY, context.expressionContext(), std::numeric_limits<double>::quiet_NaN() ); ddPos = !std::isnan( ddPosX ) && !std::isnan( ddPosY ); if ( ddPos ) { QgsCoordinateTransform ct = mSettings.coordinateTransform(); if ( ct.isValid() && !ct.isShortCircuited() ) { double z = 0; ct.transformInPlace( ddPosX, ddPosY, z ); } //data defined diagram position is always centered ddPosX -= diagramWidth / 2.0; ddPosY -= diagramHeight / 2.0; } } QgsDiagramLabelFeature *lf = new QgsDiagramLabelFeature( feat.id(), std::move( geomCopy ), QSizeF( diagramWidth, diagramHeight ) ); lf->setHasFixedPosition( ddPos ); lf->setFixedPosition( QgsPointXY( ddPosX, ddPosY ) ); lf->setHasFixedAngle( true ); lf->setFixedAngle( 0 ); lf->setAlwaysShow( alwaysShow ); lf->setIsObstacle( isObstacle ); if ( geosObstacleGeomClone ) { lf->setObstacleGeometry( std::move( geosObstacleGeomClone ) ); } if ( dr ) { //append the diagram attributes to lbl lf->setAttributes( feat.attributes() ); } // data defined priority? if ( mSettings.dataDefinedProperties().hasProperty( QgsDiagramLayerSettings::Priority ) && mSettings.dataDefinedProperties().property( QgsDiagramLayerSettings::Priority ).isActive() ) { context.expressionContext().setOriginalValueVariable( mSettings.priority() ); double priorityD = mSettings.dataDefinedProperties().valueAsDouble( QgsDiagramLayerSettings::Priority, context.expressionContext(), mSettings.priority() ); priorityD = qBound( 0.0, priorityD, 10.0 ); priorityD = 1 - priorityD / 10.0; // convert 0..10 --> 1..0 lf->setPriority( priorityD ); } // z-Index double zIndex = mSettings.zIndex(); if ( mSettings.dataDefinedProperties().hasProperty( QgsDiagramLayerSettings::ZIndex ) && mSettings.dataDefinedProperties().property( QgsDiagramLayerSettings::ZIndex ).isActive() ) { context.expressionContext().setOriginalValueVariable( zIndex ); zIndex = mSettings.dataDefinedProperties().valueAsDouble( QgsDiagramLayerSettings::ZIndex, context.expressionContext(), zIndex ); } lf->setZIndex( zIndex ); // label distance QgsPointXY ptZero = mapSettings.mapToPixel().toMapCoordinates( 0, 0 ); QgsPointXY ptOne = mapSettings.mapToPixel().toMapCoordinates( 1, 0 ); double dist = mSettings.distance(); if ( mSettings.dataDefinedProperties().hasProperty( QgsDiagramLayerSettings::Distance ) && mSettings.dataDefinedProperties().property( QgsDiagramLayerSettings::Distance ).isActive() ) { context.expressionContext().setOriginalValueVariable( dist ); dist = mSettings.dataDefinedProperties().valueAsDouble( QgsDiagramLayerSettings::Distance, context.expressionContext(), dist ); } dist *= ptOne.distance( ptZero ); lf->setDistLabel( dist ); return lf; }
void QgsLineVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, const QVector< QgsPoint >& additionalPoints, QVector< QgsPoint >& tiedPoint ) const { QgsVectorLayer *vl = mVectorLayer; if ( vl == NULL ) return; int featureCount = ( int ) vl->featureCount() * 2; int step = 0; QgsCoordinateTransform ct; ct.setSourceCrs( vl->crs() ); if ( builder->coordinateTransformationEnabled() ) { ct.setDestCRS( builder->destinationCrs() ); } else { ct.setDestCRS( vl->crs() ); } tiedPoint = QVector< QgsPoint >( additionalPoints.size(), QgsPoint( 0.0, 0.0 ) ); TiePointInfo tmpInfo; tmpInfo.mLength = std::numeric_limits<double>::infinity(); QVector< TiePointInfo > pointLengthMap( additionalPoints.size(), tmpInfo ); QVector< TiePointInfo >::iterator pointLengthIt; //Graph's points; QVector< QgsPoint > points; QgsFeatureIterator fit = vl->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) ); // begin: tie points to the graph QgsAttributeList la; QgsFeature feature; while ( fit.nextFeature( feature ) ) { QgsMultiPolyline mpl; if ( feature.constGeometry()->wkbType() == QGis::WKBMultiLineString ) mpl = feature.constGeometry()->asMultiPolyline(); else if ( feature.constGeometry()->wkbType() == QGis::WKBLineString ) mpl.push_back( feature.constGeometry()->asPolyline() ); QgsMultiPolyline::iterator mplIt; for ( mplIt = mpl.begin(); mplIt != mpl.end(); ++mplIt ) { QgsPoint pt1, pt2; bool isFirstPoint = true; QgsPolyline::iterator pointIt; for ( pointIt = mplIt->begin(); pointIt != mplIt->end(); ++pointIt ) { pt2 = ct.transform( *pointIt ); points.push_back( pt2 ); if ( !isFirstPoint ) { int i = 0; for ( i = 0; i != additionalPoints.size(); ++i ) { TiePointInfo info; if ( pt1 == pt2 ) { info.mLength = additionalPoints[ i ].sqrDist( pt1 ); info.mTiedPoint = pt1; } else { info.mLength = additionalPoints[ i ].sqrDistToSegment( pt1.x(), pt1.y(), pt2.x(), pt2.y(), info.mTiedPoint ); } if ( pointLengthMap[ i ].mLength > info.mLength ) { Q_UNUSED( info.mTiedPoint ); info.mFirstPoint = pt1; info.mLastPoint = pt2; pointLengthMap[ i ] = info; tiedPoint[ i ] = info.mTiedPoint; } } } pt1 = pt2; isFirstPoint = false; } } emit buildProgress( ++step, featureCount ); } // end: tie points to graph // add tied point to graph int i = 0; for ( i = 0; i < tiedPoint.size(); ++i ) { if ( tiedPoint[ i ] != QgsPoint( 0.0, 0.0 ) ) { points.push_back( tiedPoint [ i ] ); } } QgsPointCompare pointCompare( builder->topologyTolerance() ); qSort( points.begin(), points.end(), pointCompare ); QVector< QgsPoint >::iterator tmp = std::unique( points.begin(), points.end() ); points.resize( tmp - points.begin() ); for ( i = 0;i < points.size();++i ) builder->addVertex( i, points[ i ] ); for ( i = 0; i < tiedPoint.size() ; ++i ) tiedPoint[ i ] = *( my_binary_search( points.begin(), points.end(), tiedPoint[ i ], pointCompare ) ); qSort( pointLengthMap.begin(), pointLengthMap.end(), TiePointInfoCompare ); { // fill attribute list 'la' QgsAttributeList tmpAttr; if ( mDirectionFieldId != -1 ) { tmpAttr.push_back( mDirectionFieldId ); } QList< QgsArcProperter* >::const_iterator it; QgsAttributeList::const_iterator it2; for ( it = mProperterList.begin(); it != mProperterList.end(); ++it ) { QgsAttributeList tmp = ( *it )->requiredAttributes(); for ( it2 = tmp.begin(); it2 != tmp.end(); ++it2 ) { tmpAttr.push_back( *it2 ); } } qSort( tmpAttr.begin(), tmpAttr.end() ); int lastAttrId = -1; for ( it2 = tmpAttr.begin(); it2 != tmpAttr.end(); ++it2 ) { if ( *it2 == lastAttrId ) { continue; } la.push_back( *it2 ); lastAttrId = *it2; } } // end fill attribute list 'la' // begin graph construction fit = vl->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( la ) ); while ( fit.nextFeature( feature ) ) { int directionType = mDefaultDirection; // What direction have feature? QString str = feature.attribute( mDirectionFieldId ).toString(); if ( str == mBothDirectionValue ) { directionType = 3; } else if ( str == mDirectDirectionValue ) { directionType = 1; } else if ( str == mReverseDirectionValue ) { directionType = 2; } // begin features segments and add arc to the Graph; QgsMultiPolyline mpl; if ( feature.constGeometry()->wkbType() == QGis::WKBMultiLineString ) mpl = feature.constGeometry()->asMultiPolyline(); else if ( feature.constGeometry()->wkbType() == QGis::WKBLineString ) mpl.push_back( feature.constGeometry()->asPolyline() ); QgsMultiPolyline::iterator mplIt; for ( mplIt = mpl.begin(); mplIt != mpl.end(); ++mplIt ) { QgsPoint pt1, pt2; bool isFirstPoint = true; QgsPolyline::iterator pointIt; for ( pointIt = mplIt->begin(); pointIt != mplIt->end(); ++pointIt ) { pt2 = ct.transform( *pointIt ); if ( !isFirstPoint ) { std::map< double, QgsPoint > pointsOnArc; pointsOnArc[ 0.0 ] = pt1; pointsOnArc[ pt1.sqrDist( pt2 )] = pt2; TiePointInfo t; t.mFirstPoint = pt1; t.mLastPoint = pt2; pointLengthIt = my_binary_search( pointLengthMap.begin(), pointLengthMap.end(), t, TiePointInfoCompare ); if ( pointLengthIt != pointLengthMap.end() ) { QVector< TiePointInfo >::iterator it; for ( it = pointLengthIt; it - pointLengthMap.begin() >= 0; --it ) { if ( it->mFirstPoint == pt1 && it->mLastPoint == pt2 ) { pointsOnArc[ pt1.sqrDist( it->mTiedPoint )] = it->mTiedPoint; } } for ( it = pointLengthIt + 1; it != pointLengthMap.end(); ++it ) { if ( it->mFirstPoint == pt1 && it->mLastPoint == pt2 ) { pointsOnArc[ pt1.sqrDist( it->mTiedPoint )] = it->mTiedPoint; } } } std::map< double, QgsPoint >::iterator pointsIt; QgsPoint pt1; QgsPoint pt2; int pt1idx = -1, pt2idx = -1; bool isFirstPoint = true; for ( pointsIt = pointsOnArc.begin(); pointsIt != pointsOnArc.end(); ++pointsIt ) { pt2 = pointsIt->second; tmp = my_binary_search( points.begin(), points.end(), pt2, pointCompare ); pt2 = *tmp; pt2idx = tmp - points.begin(); if ( !isFirstPoint && pt1 != pt2 ) { double distance = builder->distanceArea()->measureLine( pt1, pt2 ); QVector< QVariant > prop; QList< QgsArcProperter* >::const_iterator it; for ( it = mProperterList.begin(); it != mProperterList.end(); ++it ) { prop.push_back(( *it )->property( distance, feature ) ); } if ( directionType == 1 || directionType == 3 ) { builder->addArc( pt1idx, pt1, pt2idx, pt2, prop ); } if ( directionType == 2 || directionType == 3 ) { builder->addArc( pt2idx, pt2, pt1idx, pt1, prop ); } } pt1idx = pt2idx; pt1 = pt2; isFirstPoint = false; } } // if ( !isFirstPoint ) pt1 = pt2; isFirstPoint = false; } // for (it = pl.begin(); it != pl.end(); ++it) } emit buildProgress( ++step, featureCount ); } // while( vl->nextFeature(feature) ) } // makeGraph( QgsGraphBuilderInterface *builder, const QVector< QgsPoint >& additionalPoints, QVector< QgsPoint >& tiedPoint )
QgsLabelFeature* QgsVectorLayerDiagramProvider::registerDiagram( QgsFeature& feat, QgsRenderContext &context, QgsGeometry* obstacleGeometry ) { const QgsMapSettings& mapSettings = mEngine->mapSettings(); const QgsDiagramRenderer* dr = mSettings.getRenderer(); if ( dr ) { QList<QgsDiagramSettings> settingList = dr->diagramSettings(); if ( !settingList.isEmpty() && settingList.at( 0 ).scaleBasedVisibility ) { double minScale = settingList.at( 0 ).minScaleDenominator; if ( minScale > 0 && context.rendererScale() < minScale ) { return nullptr; } double maxScale = settingList.at( 0 ).maxScaleDenominator; if ( maxScale > 0 && context.rendererScale() > maxScale ) { return nullptr; } } } //convert geom to geos QgsGeometry geom = feat.geometry(); QgsGeometry extentGeom = QgsGeometry::fromRect( mapSettings.visibleExtent() ); if ( !qgsDoubleNear( mapSettings.rotation(), 0.0 ) ) { //PAL features are prerotated, so extent also needs to be unrotated extentGeom.rotate( -mapSettings.rotation(), mapSettings.visibleExtent().center() ); } const GEOSGeometry* geos_geom = nullptr; QScopedPointer<QgsGeometry> scopedPreparedGeom; if ( QgsPalLabeling::geometryRequiresPreparation( geom, context, mSettings.coordinateTransform(), &extentGeom ) ) { scopedPreparedGeom.reset( new QgsGeometry( QgsPalLabeling::prepareGeometry( geom, context, mSettings.coordinateTransform(), &extentGeom ) ) ); QgsGeometry* preparedGeom = scopedPreparedGeom.data(); if ( preparedGeom->isEmpty() ) return nullptr; geos_geom = preparedGeom->asGeos(); } else { geos_geom = geom.asGeos(); } if ( !geos_geom ) return nullptr; // invalid geometry GEOSGeometry* geomCopy = GEOSGeom_clone_r( QgsGeometry::getGEOSHandler(), geos_geom ); const GEOSGeometry* geosObstacleGeom = nullptr; QScopedPointer<QgsGeometry> scopedObstacleGeom; if ( mSettings.isObstacle() && obstacleGeometry && QgsPalLabeling::geometryRequiresPreparation( *obstacleGeometry, context, mSettings.coordinateTransform(), &extentGeom ) ) { QgsGeometry preparedObstacleGeom = QgsPalLabeling::prepareGeometry( *obstacleGeometry, context, mSettings.coordinateTransform(), &extentGeom ); geosObstacleGeom = preparedObstacleGeom.asGeos(); } else if ( mSettings.isObstacle() && obstacleGeometry ) { geosObstacleGeom = obstacleGeometry->asGeos(); } GEOSGeometry* geosObstacleGeomClone = nullptr; if ( geosObstacleGeom ) { geosObstacleGeomClone = GEOSGeom_clone_r( QgsGeometry::getGEOSHandler(), geosObstacleGeom ); } double diagramWidth = 0; double diagramHeight = 0; if ( dr ) { QSizeF diagSize = dr->sizeMapUnits( feat, context ); if ( diagSize.isValid() ) { diagramWidth = diagSize.width(); diagramHeight = diagSize.height(); } } // feature to the layer bool alwaysShow = mSettings.showAllDiagrams(); int ddColX = mSettings.xPosColumn; int ddColY = mSettings.yPosColumn; double ddPosX = 0.0; double ddPosY = 0.0; bool ddPos = ( ddColX >= 0 && ddColY >= 0 ); if ( ddPos && ! feat.attribute( ddColX ).isNull() && ! feat.attribute( ddColY ).isNull() ) { bool posXOk, posYOk; ddPosX = feat.attribute( ddColX ).toDouble( &posXOk ); ddPosY = feat.attribute( ddColY ).toDouble( &posYOk ); if ( !posXOk || !posYOk ) { ddPos = false; } else { QgsCoordinateTransform ct = mSettings.coordinateTransform(); if ( ct.isValid() && !ct.isShortCircuited() ) { double z = 0; ct.transformInPlace( ddPosX, ddPosY, z ); } //data defined diagram position is always centered ddPosX -= diagramWidth / 2.0; ddPosY -= diagramHeight / 2.0; } } else ddPos = false; int ddColShow = mSettings.showColumn; if ( ddColShow >= 0 && ! feat.attribute( ddColShow ).isNull() ) { bool showOk; bool ddShow = feat.attribute( ddColShow ).toDouble( &showOk ); if ( showOk && ! ddShow ) return nullptr; } QgsDiagramLabelFeature* lf = new QgsDiagramLabelFeature( feat.id(), geomCopy, QSizeF( diagramWidth, diagramHeight ) ); lf->setHasFixedPosition( ddPos ); lf->setFixedPosition( QgsPoint( ddPosX, ddPosY ) ); lf->setHasFixedAngle( true ); lf->setFixedAngle( 0 ); lf->setAlwaysShow( alwaysShow ); lf->setIsObstacle( mSettings.isObstacle() ); lf->setZIndex( mSettings.getZIndex() ); if ( geosObstacleGeomClone ) { lf->setObstacleGeometry( geosObstacleGeomClone ); } if ( dr ) { //append the diagram attributes to lbl lf->setAttributes( feat.attributes() ); } QgsPoint ptZero = mapSettings.mapToPixel().toMapCoordinates( 0, 0 ); QgsPoint ptOne = mapSettings.mapToPixel().toMapCoordinates( 1, 0 ); lf->setDistLabel( ptOne.distance( ptZero ) * mSettings.distance() ); return lf; }
bool QgsVectorLayerRenderer::render() { if ( mGeometryType == QgsWkbTypes::NullGeometry || mGeometryType == QgsWkbTypes::UnknownGeometry ) return true; if ( !mRenderer ) { mErrors.append( QObject::tr( "No renderer for drawing." ) ); return false; } bool usingEffect = false; if ( mRenderer->paintEffect() && mRenderer->paintEffect()->enabled() ) { usingEffect = true; mRenderer->paintEffect()->begin( mContext ); } // Per feature blending mode if ( mContext.useAdvancedEffects() && mFeatureBlendMode != QPainter::CompositionMode_SourceOver ) { // set the painter to the feature blend mode, so that features drawn // on this layer will interact and blend with each other mContext.painter()->setCompositionMode( mFeatureBlendMode ); } mRenderer->startRender( mContext, mFields ); QString rendererFilter = mRenderer->filter( mFields ); QgsRectangle requestExtent = mContext.extent(); mRenderer->modifyRequestExtent( requestExtent, mContext ); QgsFeatureRequest featureRequest = QgsFeatureRequest() .setFilterRect( requestExtent ) .setSubsetOfAttributes( mAttrNames, mFields ) .setExpressionContext( mContext.expressionContext() ); if ( mRenderer->orderByEnabled() ) { featureRequest.setOrderBy( mRenderer->orderBy() ); } const QgsFeatureFilterProvider *featureFilterProvider = mContext.featureFilterProvider(); if ( featureFilterProvider ) { featureFilterProvider->filterFeatures( mLayer, featureRequest ); } if ( !rendererFilter.isEmpty() && rendererFilter != QLatin1String( "TRUE" ) ) { featureRequest.combineFilterExpression( rendererFilter ); } // enable the simplification of the geometries (Using the current map2pixel context) before send it to renderer engine. if ( mSimplifyGeometry ) { double map2pixelTol = mSimplifyMethod.threshold(); bool validTransform = true; const QgsMapToPixel &mtp = mContext.mapToPixel(); map2pixelTol *= mtp.mapUnitsPerPixel(); QgsCoordinateTransform ct = mContext.coordinateTransform(); // resize the tolerance using the change of size of an 1-BBOX from the source CoordinateSystem to the target CoordinateSystem if ( ct.isValid() && !ct.isShortCircuited() ) { try { QgsPointXY center = mContext.extent().center(); double rectSize = ct.sourceCrs().isGeographic() ? 0.0008983 /* ~100/(40075014/360=111319.4833) */ : 100; QgsRectangle sourceRect = QgsRectangle( center.x(), center.y(), center.x() + rectSize, center.y() + rectSize ); QgsRectangle targetRect = ct.transform( sourceRect ); QgsDebugMsgLevel( QStringLiteral( "Simplify - SourceTransformRect=%1" ).arg( sourceRect.toString( 16 ) ), 4 ); QgsDebugMsgLevel( QStringLiteral( "Simplify - TargetTransformRect=%1" ).arg( targetRect.toString( 16 ) ), 4 ); if ( !sourceRect.isEmpty() && sourceRect.isFinite() && !targetRect.isEmpty() && targetRect.isFinite() ) { QgsPointXY minimumSrcPoint( sourceRect.xMinimum(), sourceRect.yMinimum() ); QgsPointXY maximumSrcPoint( sourceRect.xMaximum(), sourceRect.yMaximum() ); QgsPointXY minimumDstPoint( targetRect.xMinimum(), targetRect.yMinimum() ); QgsPointXY maximumDstPoint( targetRect.xMaximum(), targetRect.yMaximum() ); double sourceHypothenuse = std::sqrt( minimumSrcPoint.sqrDist( maximumSrcPoint ) ); double targetHypothenuse = std::sqrt( minimumDstPoint.sqrDist( maximumDstPoint ) ); QgsDebugMsgLevel( QStringLiteral( "Simplify - SourceHypothenuse=%1" ).arg( sourceHypothenuse ), 4 ); QgsDebugMsgLevel( QStringLiteral( "Simplify - TargetHypothenuse=%1" ).arg( targetHypothenuse ), 4 ); if ( !qgsDoubleNear( targetHypothenuse, 0.0 ) ) map2pixelTol *= ( sourceHypothenuse / targetHypothenuse ); } } catch ( QgsCsException &cse ) { QgsMessageLog::logMessage( QObject::tr( "Simplify transform error caught: %1" ).arg( cse.what() ), QObject::tr( "CRS" ) ); validTransform = false; } } if ( validTransform ) { QgsSimplifyMethod simplifyMethod; simplifyMethod.setMethodType( QgsSimplifyMethod::OptimizeForRendering ); simplifyMethod.setTolerance( map2pixelTol ); simplifyMethod.setThreshold( mSimplifyMethod.threshold() ); simplifyMethod.setForceLocalOptimization( mSimplifyMethod.forceLocalOptimization() ); featureRequest.setSimplifyMethod( simplifyMethod ); QgsVectorSimplifyMethod vectorMethod = mSimplifyMethod; vectorMethod.setTolerance( map2pixelTol ); mContext.setVectorSimplifyMethod( vectorMethod ); } else { QgsVectorSimplifyMethod vectorMethod; vectorMethod.setSimplifyHints( QgsVectorSimplifyMethod::NoSimplification ); mContext.setVectorSimplifyMethod( vectorMethod ); } } else { QgsVectorSimplifyMethod vectorMethod; vectorMethod.setSimplifyHints( QgsVectorSimplifyMethod::NoSimplification ); mContext.setVectorSimplifyMethod( vectorMethod ); } QgsFeatureIterator fit = mSource->getFeatures( featureRequest ); // Attach an interruption checker so that iterators that have potentially // slow fetchFeature() implementations, such as in the WFS provider, can // check it, instead of relying on just the mContext.renderingStopped() check // in drawRenderer() fit.setInterruptionChecker( mInterruptionChecker.get() ); if ( ( mRenderer->capabilities() & QgsFeatureRenderer::SymbolLevels ) && mRenderer->usingSymbolLevels() ) drawRendererLevels( fit ); else drawRenderer( fit ); if ( !fit.isValid() ) { mErrors.append( QStringLiteral( "Data source invalid" ) ); } if ( usingEffect ) { mRenderer->paintEffect()->end( mContext ); } return true; }
bool QgsPointDistanceRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker ) { Q_UNUSED( drawVertexMarker ); Q_UNUSED( context ); Q_UNUSED( layer ); //check if there is already a point at that position if ( !feature.hasGeometry() ) return false; QgsMarkerSymbol* symbol = firstSymbolForFeature( feature, context ); //if the feature has no symbol (eg, no matching rule in a rule-based renderer), skip it if ( !symbol ) return false; //point position in screen coords QgsGeometry geom = feature.geometry(); QgsWkbTypes::Type geomType = geom.wkbType(); if ( QgsWkbTypes::flatType( geomType ) != QgsWkbTypes::Point ) { //can only render point type return false; } QString label; if ( mDrawLabels ) { label = getLabel( feature ); } QgsCoordinateTransform xform = context.coordinateTransform(); QgsFeature transformedFeature = feature; if ( xform.isValid() ) { geom.transform( xform ); transformedFeature.setGeometry( geom ); } double searchDistance = mTolerance * QgsSymbolLayerUtils::mapUnitScaleFactor( context, mToleranceUnit, mToleranceMapUnitScale ); QgsPoint point = transformedFeature.geometry().asPoint(); QList<QgsFeatureId> intersectList = mSpatialIndex->intersects( searchRect( point, searchDistance ) ); if ( intersectList.empty() ) { mSpatialIndex->insertFeature( transformedFeature ); // create new group ClusteredGroup newGroup; newGroup << GroupedFeature( transformedFeature, symbol, selected, label ); mClusteredGroups.push_back( newGroup ); // add to group index mGroupIndex.insert( transformedFeature.id(), mClusteredGroups.count() - 1 ); mGroupLocations.insert( transformedFeature.id(), point ); } else { // find group with closest location to this point (may be more than one within search tolerance) QgsFeatureId minDistFeatureId = intersectList.at( 0 ); double minDist = mGroupLocations.value( minDistFeatureId ).distance( point ); for ( int i = 1; i < intersectList.count(); ++i ) { QgsFeatureId candidateId = intersectList.at( i ); double newDist = mGroupLocations.value( candidateId ).distance( point ); if ( newDist < minDist ) { minDist = newDist; minDistFeatureId = candidateId; } } int groupIdx = mGroupIndex[ minDistFeatureId ]; ClusteredGroup& group = mClusteredGroups[groupIdx]; // calculate new centroid of group QgsPoint oldCenter = mGroupLocations.value( minDistFeatureId ); mGroupLocations[ minDistFeatureId ] = QgsPoint(( oldCenter.x() * group.size() + point.x() ) / ( group.size() + 1.0 ), ( oldCenter.y() * group.size() + point.y() ) / ( group.size() + 1.0 ) ); // add to a group group << GroupedFeature( transformedFeature, symbol, selected, label ); // add to group index mGroupIndex.insert( transformedFeature.id(), groupIdx ); } return true; }