bool QgsMapToolIdentify::identifyRasterLayer( QList<IdentifyResult> *results, QgsRasterLayer *layer, QgsPoint point, QgsRectangle viewExtent, double mapUnitsPerPixel ) { QgsDebugMsg( "point = " + point.toString() ); if ( !layer ) return false; QgsRasterDataProvider *dprovider = layer->dataProvider(); int capabilities = dprovider->capabilities(); if ( !dprovider || !( capabilities & QgsRasterDataProvider::Identify ) ) { return false; } try { point = toLayerCoordinates( layer, point ); } catch ( QgsCsException &cse ) { Q_UNUSED( cse ); QgsDebugMsg( QString( "coordinate not reprojectable: %1" ).arg( cse.what() ) ); return false; } QgsDebugMsg( QString( "point = %1 %2" ).arg( point.x() ).arg( point.y() ) ); if ( !layer->extent().contains( point ) ) return false; QMap< QString, QString > attributes, derivedAttributes; QMap<int, QVariant> values; QgsRasterDataProvider::IdentifyFormat format = QgsRasterDataProvider::identifyFormatFromName( layer->customProperty( "identify/format" ).toString() ); // check if the format is really supported otherwise use first supported format if ( !( QgsRasterDataProvider::identifyFormatToCapability( format ) & capabilities ) ) { if ( capabilities & QgsRasterInterface::IdentifyFeature ) format = QgsRasterDataProvider::IdentifyFormatFeature; else if ( capabilities & QgsRasterInterface::IdentifyValue ) format = QgsRasterDataProvider::IdentifyFormatValue; else if ( capabilities & QgsRasterInterface::IdentifyHtml ) format = QgsRasterDataProvider::IdentifyFormatHtml; else if ( capabilities & QgsRasterInterface::IdentifyText ) format = QgsRasterDataProvider::IdentifyFormatText; else return false; } // We can only use context (extent, width, heigh) if layer is not reprojected, // otherwise we don't know source resolution (size). if ( mCanvas->hasCrsTransformEnabled() && dprovider->crs() != mCanvas->mapRenderer()->destinationCrs() ) { viewExtent = toLayerCoordinates( layer, viewExtent ); values = dprovider->identify( point, format ); } else { // It would be nice to use the same extent and size which was used for drawing, // so that WCS can use cache from last draw, unfortunately QgsRasterLayer::draw() // is doing some tricks with extent and size to allign raster to output which // would be difficult to replicate here. // Note: cutting the extent may result in slightly different x and y resolutions // and thus shifted point calculated back in QGIS WMS (using average resolution) //viewExtent = dprovider->extent().intersect( &viewExtent ); // Width and height are calculated from not projected extent and we hope that // are similar to source width and height used to reproject layer for drawing. // TODO: may be very dangerous, because it may result in different resolutions // in source CRS, and WMS server (QGIS server) calcs wrong coor using average resolution. int width = qRound( viewExtent.width() / mapUnitsPerPixel ); int height = qRound( viewExtent.height() / mapUnitsPerPixel ); QgsDebugMsg( QString( "viewExtent.width = %1 viewExtent.height = %2" ).arg( viewExtent.width() ).arg( viewExtent.height() ) ); QgsDebugMsg( QString( "width = %1 height = %2" ).arg( width ).arg( height ) ); QgsDebugMsg( QString( "xRes = %1 yRes = %2 mapUnitsPerPixel = %3" ).arg( viewExtent.width() / width ).arg( viewExtent.height() / height ).arg( mapUnitsPerPixel ) ); values = dprovider->identify( point, format, viewExtent, width, height ); } derivedAttributes.insert( tr( "(clicked coordinate)" ), point.toString() ); //QString type = tr( "Raster" ); QgsGeometry geometry; if ( format == QgsRasterDataProvider::IdentifyFormatValue ) { foreach ( int bandNo, values.keys() ) { double value = values.value( bandNo ).toDouble(); QString valueString; if ( dprovider->isNoDataValue( bandNo, value ) ) { valueString = tr( "no data" ); } else { valueString = QgsRasterBlock::printValue( value ); } attributes.insert( dprovider->generateBandName( bandNo ), valueString ); } QString label = layer->name(); results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) ); }
QPointF QgsMapCanvasItem::toCanvasCoordinates( const QgsPoint& point ) { double x = point.x(), y = point.y(); mMapCanvas->getCoordinateTransform()->transformInPlace( x, y ); return QPointF( x, y ) + mPanningOffset; }
QVariantMap QgsJoinWithLinesAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { if ( parameters.value( QStringLiteral( "SPOKES" ) ) == parameters.value( QStringLiteral( "HUBS" ) ) ) throw QgsProcessingException( QObject::tr( "Same layer given for both hubs and spokes" ) ); std::unique_ptr< QgsFeatureSource > hubSource( parameterAsSource( parameters, QStringLiteral( "HUBS" ), context ) ); std::unique_ptr< QgsFeatureSource > spokeSource( parameterAsSource( parameters, QStringLiteral( "SPOKES" ), context ) ); if ( !hubSource || !spokeSource ) return QVariantMap(); QString fieldHubName = parameterAsString( parameters, QStringLiteral( "HUB_FIELD" ), context ); int fieldHubIndex = hubSource->fields().lookupField( fieldHubName ); const QStringList hubFieldsToCopy = parameterAsFields( parameters, QStringLiteral( "HUB_FIELDS" ), context ); QString fieldSpokeName = parameterAsString( parameters, QStringLiteral( "SPOKE_FIELD" ), context ); int fieldSpokeIndex = spokeSource->fields().lookupField( fieldSpokeName ); const QStringList spokeFieldsToCopy = parameterAsFields( parameters, QStringLiteral( "SPOKE_FIELDS" ), context ); if ( fieldHubIndex < 0 || fieldSpokeIndex < 0 ) throw QgsProcessingException( QObject::tr( "Invalid ID field" ) ); QgsFields hubOutFields; QgsAttributeList hubFieldIndices; if ( hubFieldsToCopy.empty() ) { hubOutFields = hubSource->fields(); for ( int i = 0; i < hubOutFields.count(); ++i ) { hubFieldIndices << i; } } else { for ( const QString &field : hubFieldsToCopy ) { int index = hubSource->fields().lookupField( field ); if ( index >= 0 ) { hubFieldIndices << index; hubOutFields.append( hubSource->fields().at( index ) ); } } } QgsAttributeList hubFields2Fetch = hubFieldIndices; hubFields2Fetch << fieldHubIndex; QgsFields spokeOutFields; QgsAttributeList spokeFieldIndices; if ( spokeFieldsToCopy.empty() ) { spokeOutFields = spokeSource->fields(); for ( int i = 0; i < spokeOutFields.count(); ++i ) { spokeFieldIndices << i; } } else { for ( const QString &field : spokeFieldsToCopy ) { int index = spokeSource->fields().lookupField( field ); if ( index >= 0 ) { spokeFieldIndices << index; spokeOutFields.append( spokeSource->fields().at( index ) ); } } } QgsAttributeList spokeFields2Fetch = spokeFieldIndices; spokeFields2Fetch << fieldSpokeIndex; QgsFields fields = QgsProcessingUtils::combineFields( hubOutFields, spokeOutFields ); QgsWkbTypes::Type outType = QgsWkbTypes::LineString; bool hasZ = false; if ( QgsWkbTypes::hasZ( hubSource->wkbType() ) || QgsWkbTypes::hasZ( spokeSource->wkbType() ) ) { outType = QgsWkbTypes::addZ( outType ); hasZ = true; } bool hasM = false; if ( QgsWkbTypes::hasM( hubSource->wkbType() ) || QgsWkbTypes::hasM( spokeSource->wkbType() ) ) { outType = QgsWkbTypes::addM( outType ); hasM = true; } QString dest; std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, outType, hubSource->sourceCrs() ) ); if ( !sink ) return QVariantMap(); auto getPointFromFeature = [hasZ, hasM]( const QgsFeature & feature )->QgsPoint { QgsPoint p; if ( feature.geometry().type() == QgsWkbTypes::PointGeometry && !feature.geometry().isMultipart() ) p = *static_cast< const QgsPoint *>( feature.geometry().constGet() ); else p = *static_cast< const QgsPoint *>( feature.geometry().pointOnSurface().constGet() ); if ( hasZ && !p.is3D() ) p.addZValue( 0 ); if ( hasM && !p.isMeasure() ) p.addMValue( 0 ); return p; }; QgsFeatureIterator hubFeatures = hubSource->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( hubFields2Fetch ) ); double step = hubSource->featureCount() > 0 ? 100.0 / hubSource->featureCount() : 1; int i = 0; QgsFeature hubFeature; while ( hubFeatures.nextFeature( hubFeature ) ) { i++; if ( feedback->isCanceled() ) { break; } feedback->setProgress( i * step ); if ( !hubFeature.hasGeometry() ) continue; QgsPoint hubPoint = getPointFromFeature( hubFeature ); // only keep selected attributes QgsAttributes hubAttributes; for ( int j = 0; j < hubFeature.attributes().count(); ++j ) { if ( !hubFieldIndices.contains( j ) ) continue; hubAttributes << hubFeature.attribute( j ); } QgsFeatureRequest spokeRequest = QgsFeatureRequest().setDestinationCrs( hubSource->sourceCrs(), context.transformContext() ); spokeRequest.setSubsetOfAttributes( spokeFields2Fetch ); spokeRequest.setFilterExpression( QgsExpression::createFieldEqualityExpression( fieldSpokeName, hubFeature.attribute( fieldHubIndex ) ) ); QgsFeatureIterator spokeFeatures = spokeSource->getFeatures( spokeRequest ); QgsFeature spokeFeature; while ( spokeFeatures.nextFeature( spokeFeature ) ) { if ( feedback->isCanceled() ) { break; } if ( !spokeFeature.hasGeometry() ) continue; QgsPoint spokePoint = getPointFromFeature( spokeFeature ); QgsGeometry line( new QgsLineString( QVector< QgsPoint >() << hubPoint << spokePoint ) ); QgsFeature outFeature; QgsAttributes outAttributes = hubAttributes; // only keep selected attributes QgsAttributes spokeAttributes; for ( int j = 0; j < spokeFeature.attributes().count(); ++j ) { if ( !spokeFieldIndices.contains( j ) ) continue; spokeAttributes << spokeFeature.attribute( j ); } outAttributes.append( spokeAttributes ); outFeature.setAttributes( outAttributes ); outFeature.setGeometry( line ); sink->addFeature( outFeature, QgsFeatureSink::FastInsert ); } } QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), dest ); return outputs; }
// Default implementation for values QgsRasterIdentifyResult QgsRasterDataProvider::identify( const QgsPoint & thePoint, QgsRaster::IdentifyFormat theFormat, const QgsRectangle &theExtent, int theWidth, int theHeight ) { QgsDebugMsg( "Entered" ); QMap<int, QVariant> results; if ( theFormat != QgsRaster::IdentifyFormatValue || !( capabilities() & IdentifyValue ) ) { QgsDebugMsg( "Format not supported" ); return QgsRasterIdentifyResult( ERR( tr( "Format not supported" ) ) ); } if ( !extent().contains( thePoint ) ) { // Outside the raster for ( int bandNo = 1; bandNo <= bandCount(); bandNo++ ) { results.insert( bandNo, QVariant() ); } return QgsRasterIdentifyResult( QgsRaster::IdentifyFormatValue, results ); } QgsRectangle myExtent = theExtent; if ( myExtent.isEmpty() ) myExtent = extent(); if ( theWidth == 0 ) { theWidth = capabilities() & Size ? xSize() : 1000; } if ( theHeight == 0 ) { theHeight = capabilities() & Size ? ySize() : 1000; } // Calculate the row / column where the point falls double xres = ( myExtent.width() ) / theWidth; double yres = ( myExtent.height() ) / theHeight; int col = ( int ) floor(( thePoint.x() - myExtent.xMinimum() ) / xres ); int row = ( int ) floor(( myExtent.yMaximum() - thePoint.y() ) / yres ); double xMin = myExtent.xMinimum() + col * xres; double xMax = xMin + xres; double yMax = myExtent.yMaximum() - row * yres; double yMin = yMax - yres; QgsRectangle pixelExtent( xMin, yMin, xMax, yMax ); for ( int i = 1; i <= bandCount(); i++ ) { QgsRasterBlock * myBlock = block( i, pixelExtent, 1, 1 ); if ( myBlock ) { double value = myBlock->value( 0 ); results.insert( i, value ); delete myBlock; } else { results.insert( i, QVariant() ); } } return QgsRasterIdentifyResult( QgsRaster::IdentifyFormatValue, results ); }
void QgsMapMouseEvent::setPoint( const QgsPoint& point ) { mMapPoint.set( point.x(), point.y() ); }
void QgsMapToolMoveFeature::canvasPressEvent( QMouseEvent * e ) { delete mRubberBand; mRubberBand = 0; QgsVectorLayer* vlayer = currentVectorLayer(); if ( !vlayer ) { notifyNotVectorLayer(); return; } if ( !vlayer->isEditable() ) { notifyNotEditableLayer(); return; } //find first geometry under mouse cursor and store iterator to it QgsPoint layerCoords = toLayerCoordinates( vlayer, e->pos() ); QSettings settings; double searchRadius = QgsTolerance::vertexSearchRadius( mCanvas->currentLayer(), mCanvas->mapRenderer() ); QgsRectangle selectRect( layerCoords.x() - searchRadius, layerCoords.y() - searchRadius, layerCoords.x() + searchRadius, layerCoords.y() + searchRadius ); if ( vlayer->selectedFeatureCount() == 0 ) { QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectRect ).setSubsetOfAttributes( QgsAttributeList() ) ); //find the closest feature QgsGeometry* pointGeometry = QgsGeometry::fromPoint( layerCoords ); if ( !pointGeometry ) { return; } double minDistance = std::numeric_limits<double>::max(); QgsFeature cf; QgsFeature f; while ( fit.nextFeature( f ) ) { if ( f.geometry() ) { double currentDistance = pointGeometry->distance( *f.geometry() ); if ( currentDistance < minDistance ) { minDistance = currentDistance; cf = f; } } } delete pointGeometry; if ( minDistance == std::numeric_limits<double>::max() ) { return; } mMovedFeatures.clear(); mMovedFeatures << cf.id(); //todo: take the closest feature, not the first one... mRubberBand = createRubberBand( vlayer->geometryType() ); mRubberBand->setToGeometry( cf.geometry(), vlayer ); } else { mMovedFeatures = vlayer->selectedFeaturesIds(); mRubberBand = createRubberBand( vlayer->geometryType() ); for ( int i = 0; i < vlayer->selectedFeatureCount(); i++ ) { mRubberBand->addGeometry( vlayer->selectedFeatures()[i].geometry(), vlayer ); } } mStartPointMapCoords = toMapCoordinates( e->pos() ); mRubberBand->setColor( QColor( 255, 0, 0, 65 ) ); mRubberBand->setWidth( 2 ); mRubberBand->show(); }
bool QgsMapToolIdentify::identifyRasterLayer( QgsRasterLayer *layer, int x, int y ) { bool res = true; if ( !layer ) return false; QgsRasterDataProvider *dprovider = layer->dataProvider(); if ( dprovider && ( dprovider->capabilities() & QgsRasterDataProvider::Identify ) == 0 ) return false; QMap< QString, QString > attributes, derivedAttributes; QgsPoint idPoint = mCanvas->getCoordinateTransform()->toMapCoordinates( x, y ); try { idPoint = toLayerCoordinates( layer, idPoint ); } catch ( QgsCsException &cse ) { Q_UNUSED( cse ); QgsDebugMsg( QString( "coordinate not reprojectable: %1" ).arg( cse.what() ) ); return false; } QString type; if ( layer->providerType() == "wms" ) { type = tr( "WMS layer" ); //if WMS layer does not cover the view origin, //we need to map the view pixel coordinates //to WMS layer pixel coordinates QgsRectangle viewExtent = toLayerCoordinates( layer, mCanvas->extent() ); QgsRectangle layerExtent = layer->extent(); double mapUnitsPerPixel = mCanvas->mapUnitsPerPixel(); if ( mapUnitsPerPixel > 0 && viewExtent.intersects( layerExtent ) ) { double xMinView = viewExtent.xMinimum(); double yMaxView = viewExtent.yMaximum(); double xMinLayer = layerExtent.xMinimum(); double yMaxLayer = layerExtent.yMaximum(); idPoint.set( xMinView < xMinLayer ? floor( x - ( xMinLayer - xMinView ) / mapUnitsPerPixel ) : x, yMaxView > yMaxLayer ? floor( y - ( yMaxView - yMaxLayer ) / mapUnitsPerPixel ) : y ); attributes.insert( tr( "Feature info" ), layer->identifyAsHtml( idPoint ) ); } else { res = false; } } else { type = tr( "Raster" ); res = layer->extent().contains( idPoint ) && layer->identify( idPoint, attributes ); } if ( res ) { derivedAttributes.insert( tr( "(clicked coordinate)" ), idPoint.toString() ); results()->addFeature( layer, type, attributes, derivedAttributes ); } return res; }
double QgsPoint::sqrDist( const QgsPoint& other ) const { return sqrDist( other.x(), other.y() ); }
double QgsPoint::azimuth( const QgsPoint& other ) { double dx = other.x() - m_x; double dy = other.y() - m_y; return ( atan2( dx, dy ) * 180.0 / M_PI ); }
bool QgsTransectSample::closestSegmentPoints( QgsGeometry& g1, QgsGeometry& g2, double& dist, QgsPoint& pt1, QgsPoint& pt2 ) { QGis::WkbType t1 = g1.wkbType(); if ( t1 != QGis::WKBLineString && t1 != QGis::WKBLineString25D ) { return false; } QGis::WkbType t2 = g2.wkbType(); if ( t2 != QGis::WKBLineString && t2 != QGis::WKBLineString25D ) { return false; } QgsPolyline pl1 = g1.asPolyline(); QgsPolyline pl2 = g2.asPolyline(); if ( pl1.size() < 2 || pl2.size() < 2 ) { return false; } QgsPoint p11 = pl1.at( 0 ); QgsPoint p12 = pl1.at( 1 ); QgsPoint p21 = pl2.at( 0 ); QgsPoint p22 = pl2.at( 1 ); double p1x = p11.x(); double p1y = p11.y(); double v1x = p12.x() - p11.x(); double v1y = p12.y() - p11.y(); double p2x = p21.x(); double p2y = p21.y(); double v2x = p22.x() - p21.x(); double v2y = p22.y() - p21.y(); double denominatorU = v2x * v1y - v2y * v1x; double denominatorT = v1x * v2y - v1y * v2x; if ( qgsDoubleNear( denominatorU, 0 ) || qgsDoubleNear( denominatorT, 0 ) ) { //lines are parallel //project all points on the other segment and take the one with the smallest distance QgsPoint minDistPoint1; double d1 = p11.sqrDistToSegment( p21.x(), p21.y(), p22.x(), p22.y(), minDistPoint1 ); QgsPoint minDistPoint2; double d2 = p12.sqrDistToSegment( p21.x(), p21.y(), p22.x(), p22.y(), minDistPoint2 ); QgsPoint minDistPoint3; double d3 = p21.sqrDistToSegment( p11.x(), p11.y(), p12.x(), p12.y(), minDistPoint3 ); QgsPoint minDistPoint4; double d4 = p22.sqrDistToSegment( p11.x(), p11.y(), p12.x(), p12.y(), minDistPoint4 ); if ( d1 <= d2 && d1 <= d3 && d1 <= d4 ) { dist = sqrt( d1 ); pt1 = p11; pt2 = minDistPoint1; return true; } else if ( d2 <= d1 && d2 <= d3 && d2 <= d4 ) { dist = sqrt( d2 ); pt1 = p12; pt2 = minDistPoint2; return true; } else if ( d3 <= d1 && d3 <= d2 && d3 <= d4 ) { dist = sqrt( d3 ); pt1 = p21; pt2 = minDistPoint3; return true; } else { dist = sqrt( d4 ); pt1 = p21; pt2 = minDistPoint4; return true; } } double u = ( p1x * v1y - p1y * v1x - p2x * v1y + p2y * v1x ) / denominatorU; double t = ( p2x * v2y - p2y * v2x - p1x * v2y + p1y * v2x ) / denominatorT; if ( u >= 0 && u <= 1.0 && t >= 0 && t <= 1.0 ) { dist = 0; pt1.setX( p2x + u * v2x ); pt1.setY( p2y + u * v2y ); pt2 = pt1; dist = 0; return true; } if ( t > 1.0 ) { pt1.setX( p12.x() ); pt1.setY( p12.y() ); } else if ( t < 0.0 ) { pt1.setX( p11.x() ); pt1.setY( p11.y() ); } if ( u > 1.0 ) { pt2.setX( p22.x() ); pt2.setY( p22.y() ); } if ( u < 0.0 ) { pt2.setX( p21.x() ); pt2.setY( p21.y() ); } if ( t >= 0.0 && t <= 1.0 ) { //project pt2 onto g1 pt2.sqrDistToSegment( p11.x(), p11.y(), p12.x(), p12.y(), pt1 ); } if ( u >= 0.0 && u <= 1.0 ) { //project pt1 onto g2 pt1.sqrDistToSegment( p21.x(), p21.y(), p22.x(), p22.y(), pt2 ); } dist = sqrt( pt1.sqrDist( pt2 ) ); return true; }
QgsPoint::QgsPoint( const QgsPoint& p ) { m_x = p.x(); m_y = p.y(); }
int QgsTransectSample::createSample( QProgressDialog* pd ) { Q_UNUSED( pd ); if ( !mStrataLayer || !mStrataLayer->isValid() ) { return 1; } if ( !mBaselineLayer || !mBaselineLayer->isValid() ) { return 2; } //stratum id is not necessarily an integer QVariant::Type stratumIdType = QVariant::Int; if ( !mStrataIdAttribute.isEmpty() ) { stratumIdType = mStrataLayer->pendingFields().field( mStrataIdAttribute ).type(); } //create vector file writers for output QgsFields outputPointFields; outputPointFields.append( QgsField( "id", stratumIdType ) ); outputPointFields.append( QgsField( "station_id", QVariant::Int ) ); outputPointFields.append( QgsField( "stratum_id", stratumIdType ) ); outputPointFields.append( QgsField( "station_code", QVariant::String ) ); outputPointFields.append( QgsField( "start_lat", QVariant::Double ) ); outputPointFields.append( QgsField( "start_long", QVariant::Double ) ); QgsVectorFileWriter outputPointWriter( mOutputPointLayer, "utf-8", outputPointFields, QGis::WKBPoint, &( mStrataLayer->crs() ) ); if ( outputPointWriter.hasError() != QgsVectorFileWriter::NoError ) { return 3; } outputPointFields.append( QgsField( "bearing", QVariant::Double ) ); //add bearing attribute for lines QgsVectorFileWriter outputLineWriter( mOutputLineLayer, "utf-8", outputPointFields, QGis::WKBLineString, &( mStrataLayer->crs() ) ); if ( outputLineWriter.hasError() != QgsVectorFileWriter::NoError ) { return 4; } QgsFields usedBaselineFields; usedBaselineFields.append( QgsField( "stratum_id", stratumIdType ) ); usedBaselineFields.append( QgsField( "ok", QVariant::String ) ); QgsVectorFileWriter usedBaselineWriter( mUsedBaselineLayer, "utf-8", usedBaselineFields, QGis::WKBLineString, &( mStrataLayer->crs() ) ); if ( usedBaselineWriter.hasError() != QgsVectorFileWriter::NoError ) { return 5; } //debug: write clipped buffer bounds with stratum id to same directory as out_point QFileInfo outputPointInfo( mOutputPointLayer ); QString bufferClipLineOutput = outputPointInfo.absolutePath() + "/out_buffer_clip_line.shp"; QgsFields bufferClipLineFields; bufferClipLineFields.append( QgsField( "id", stratumIdType ) ); QgsVectorFileWriter bufferClipLineWriter( bufferClipLineOutput, "utf-8", bufferClipLineFields, QGis::WKBLineString, &( mStrataLayer->crs() ) ); //configure distanceArea depending on minDistance units and output CRS QgsDistanceArea distanceArea; distanceArea.setSourceCrs( mStrataLayer->crs().srsid() ); if ( mMinDistanceUnits == Meters ) { distanceArea.setEllipsoidalMode( true ); } else { distanceArea.setEllipsoidalMode( false ); } //possibility to transform output points to lat/long QgsCoordinateTransform toLatLongTransform( mStrataLayer->crs(), QgsCoordinateReferenceSystem( 4326, QgsCoordinateReferenceSystem::EpsgCrsId ) ); //init random number generator mt_srand( QTime::currentTime().msec() ); QgsFeatureRequest fr; fr.setSubsetOfAttributes( QStringList() << mStrataIdAttribute << mMinDistanceAttribute << mNPointsAttribute, mStrataLayer->pendingFields() ); QgsFeatureIterator strataIt = mStrataLayer->getFeatures( fr ); QgsFeature fet; int nTotalTransects = 0; int nFeatures = 0; if ( pd ) { pd->setMaximum( mStrataLayer->featureCount() ); } while ( strataIt.nextFeature( fet ) ) { if ( pd ) { pd->setValue( nFeatures ); } if ( pd && pd->wasCanceled() ) { break; } QgsGeometry* strataGeom = fet.geometry(); if ( !strataGeom ) { continue; } //find baseline for strata bool strataIdOk = true; QVariant strataId = fet.attribute( mStrataIdAttribute ); QgsGeometry* baselineGeom = findBaselineGeometry( strataIdOk ? strataId : -1 ); if ( !baselineGeom ) { continue; } double minDistance = fet.attribute( mMinDistanceAttribute ).toDouble(); double minDistanceLayerUnits = minDistance; //if minDistance is in meters and the data in degrees, we need to apply a rough conversion for the buffer distance double bufferDist = minDistance; if ( mMinDistanceUnits == Meters && mStrataLayer->crs().mapUnits() == QGis::DecimalDegrees ) { bufferDist = minDistance / 111319.9; minDistanceLayerUnits = bufferDist; } QgsGeometry* clippedBaseline = strataGeom->intersection( baselineGeom ); if ( !clippedBaseline || clippedBaseline->wkbType() == QGis::WKBUnknown ) { delete clippedBaseline; continue; } QgsGeometry* bufferLineClipped = clipBufferLine( strataGeom, clippedBaseline, bufferDist ); if ( !bufferLineClipped ) { delete clippedBaseline; continue; } //save clipped baseline to file QgsFeature blFeature; blFeature.setGeometry( *clippedBaseline ); blFeature.setAttribute( "stratum_id", strataId ); blFeature.setAttribute( "ok", "f" ); usedBaselineWriter.addFeature( blFeature ); //start loop to create random points along the baseline int nTransects = fet.attribute( mNPointsAttribute ).toInt(); int nCreatedTransects = 0; int nIterations = 0; int nMaxIterations = nTransects * 50; QgsSpatialIndex sIndex; //to check minimum distance QMap< QgsFeatureId, QgsGeometry* > lineFeatureMap; while ( nCreatedTransects < nTransects && nIterations < nMaxIterations ) { double randomPosition = (( double )mt_rand() / MD_RAND_MAX ) * clippedBaseline->length(); QgsGeometry* samplePoint = clippedBaseline->interpolate( randomPosition ); ++nIterations; if ( !samplePoint ) { continue; } QgsPoint sampleQgsPoint = samplePoint->asPoint(); QgsPoint latLongSamplePoint = toLatLongTransform.transform( sampleQgsPoint ); QgsFeature samplePointFeature; samplePointFeature.setGeometry( samplePoint ); samplePointFeature.setAttribute( "id", nTotalTransects + 1 ); samplePointFeature.setAttribute( "station_id", nCreatedTransects + 1 ); samplePointFeature.setAttribute( "stratum_id", strataId ); samplePointFeature.setAttribute( "station_code", strataId.toString() + "_" + QString::number( nCreatedTransects + 1 ) ); samplePointFeature.setAttribute( "start_lat", latLongSamplePoint.y() ); samplePointFeature.setAttribute( "start_long", latLongSamplePoint.x() ); //find closest point on clipped buffer line QgsPoint minDistPoint; int afterVertex; if ( bufferLineClipped->closestSegmentWithContext( sampleQgsPoint, minDistPoint, afterVertex ) < 0 ) { continue; } //bearing between sample point and min dist point (transect direction) double bearing = distanceArea.bearing( sampleQgsPoint, minDistPoint ) / M_PI * 180.0; QgsPolyline sampleLinePolyline; QgsPoint ptFarAway( sampleQgsPoint.x() + ( minDistPoint.x() - sampleQgsPoint.x() ) * 1000000, sampleQgsPoint.y() + ( minDistPoint.y() - sampleQgsPoint.y() ) * 1000000 ); QgsPolyline lineFarAway; lineFarAway << sampleQgsPoint << ptFarAway; QgsGeometry* lineFarAwayGeom = QgsGeometry::fromPolyline( lineFarAway ); QgsGeometry* lineClipStratum = lineFarAwayGeom->intersection( strataGeom ); if ( !lineClipStratum ) { delete lineFarAwayGeom; delete lineClipStratum; continue; } //cancel if distance between sample point and line is too large (line does not start at point if ( lineClipStratum->distance( *samplePoint ) > 0.000001 ) { delete lineFarAwayGeom; delete lineClipStratum; continue; } //if lineClipStratum is a multiline, take the part line closest to sampleQgsPoint if ( lineClipStratum->wkbType() == QGis::WKBMultiLineString || lineClipStratum->wkbType() == QGis::WKBMultiLineString25D ) { QgsGeometry* singleLine = closestMultilineElement( sampleQgsPoint, lineClipStratum ); if ( singleLine ) { delete lineClipStratum; lineClipStratum = singleLine; } } //cancel if length of lineClipStratum is too small double transectLength = distanceArea.measure( lineClipStratum ); if ( transectLength < mMinTransectLength ) { delete lineFarAwayGeom; delete lineClipStratum; continue; } //search closest existing profile. Cancel if dist < minDist if ( otherTransectWithinDistance( lineClipStratum, minDistanceLayerUnits, minDistance, sIndex, lineFeatureMap, distanceArea ) ) { delete lineFarAwayGeom; delete lineClipStratum; continue; } QgsFeatureId fid( nCreatedTransects ); QgsFeature sampleLineFeature( fid ); sampleLineFeature.setGeometry( lineClipStratum ); sampleLineFeature.setAttribute( "id", nTotalTransects + 1 ); sampleLineFeature.setAttribute( "station_id", nCreatedTransects + 1 ); sampleLineFeature.setAttribute( "stratum_id", strataId ); sampleLineFeature.setAttribute( "station_code", strataId.toString() + "_" + QString::number( nCreatedTransects + 1 ) ); sampleLineFeature.setAttribute( "start_lat", latLongSamplePoint.y() ); sampleLineFeature.setAttribute( "start_long", latLongSamplePoint.x() ); sampleLineFeature.setAttribute( "bearing", bearing ); outputLineWriter.addFeature( sampleLineFeature ); //add point to file writer here. //It can only be written if the corresponding transect has been as well outputPointWriter.addFeature( samplePointFeature ); sIndex.insertFeature( sampleLineFeature ); lineFeatureMap.insert( fid, sampleLineFeature.geometryAndOwnership() ); delete lineFarAwayGeom; ++nTotalTransects; ++nCreatedTransects; } delete clippedBaseline; QgsFeature bufferClipFeature; bufferClipFeature.setGeometry( bufferLineClipped ); bufferClipFeature.setAttribute( "id" , strataId ); bufferClipLineWriter.addFeature( bufferClipFeature ); //delete bufferLineClipped; //delete all line geometries in spatial index QMap< QgsFeatureId, QgsGeometry* >::iterator featureMapIt = lineFeatureMap.begin(); for ( ; featureMapIt != lineFeatureMap.end(); ++featureMapIt ) { delete( featureMapIt.value() ); } lineFeatureMap.clear(); delete baselineGeom; ++nFeatures; } if ( pd ) { pd->setValue( mStrataLayer->featureCount() ); } return 0; }
// Slot called when the menu item is triggered // If you created more menu items / toolbar buttons in initiGui, you should // create a separate handler for each action - this single run() method will // not be enough void Heatmap::run() { HeatmapGui d( mQGisIface->mainWindow(), QgisGui::ModalDialogFlags, &mSessionSettings ); if ( d.exec() == QDialog::Accepted ) { // everything runs here // Get the required data from the dialog QgsRectangle myBBox = d.bbox(); int columns = d.columns(); int rows = d.rows(); double cellsize = d.cellSizeX(); // or d.cellSizeY(); both have the same value mDecay = d.decayRatio(); int kernelShape = d.kernelShape(); // Start working on the input vector QgsVectorLayer* inputLayer = d.inputVectorLayer(); // Getting the rasterdataset in place GDALAllRegister(); GDALDataset *emptyDataset; GDALDriver *myDriver; myDriver = GetGDALDriverManager()->GetDriverByName( d.outputFormat().toUtf8() ); if ( myDriver == NULL ) { QMessageBox::information( 0, tr( "GDAL driver error" ), tr( "Cannot open the driver for the specified format" ) ); return; } double geoTransform[6] = { myBBox.xMinimum(), cellsize, 0, myBBox.yMinimum(), 0, cellsize }; emptyDataset = myDriver->Create( d.outputFilename().toUtf8(), columns, rows, 1, GDT_Float32, NULL ); emptyDataset->SetGeoTransform( geoTransform ); // Set the projection on the raster destination to match the input layer emptyDataset->SetProjection( inputLayer->crs().toWkt().toLocal8Bit().data() ); GDALRasterBand *poBand; poBand = emptyDataset->GetRasterBand( 1 ); poBand->SetNoDataValue( NO_DATA ); float* line = ( float * ) CPLMalloc( sizeof( float ) * columns ); for ( int i = 0; i < columns ; i++ ) { line[i] = NO_DATA; } // Write the empty raster for ( int i = 0; i < rows ; i++ ) { poBand->RasterIO( GF_Write, 0, i, columns, 1, line, columns, 1, GDT_Float32, 0, 0 ); } CPLFree( line ); //close the dataset GDALClose(( GDALDatasetH ) emptyDataset ); // open the raster in GA_Update mode GDALDataset *heatmapDS; heatmapDS = ( GDALDataset * ) GDALOpen( TO8F( d.outputFilename() ), GA_Update ); if ( !heatmapDS ) { QMessageBox::information( 0, tr( "Raster update error" ), tr( "Could not open the created raster for updating. The heatmap was not generated." ) ); return; } poBand = heatmapDS->GetRasterBand( 1 ); QgsAttributeList myAttrList; int rField = 0; int wField = 0; // Handle different radius options double radius; double radiusToMapUnits = 1; int myBuffer = 0; if ( d.variableRadius() ) { rField = d.radiusField(); myAttrList.append( rField ); QgsDebugMsg( QString( "Radius Field index received: %1" ).arg( rField ) ); // If not using map units, then calculate a conversion factor to convert the radii to map units if ( d.radiusUnit() == HeatmapGui::Meters ) { radiusToMapUnits = mapUnitsOf( 1, inputLayer->crs() ); } } else { radius = d.radius(); // radius returned by d.radius() is already in map units myBuffer = bufferSize( radius, cellsize ); } if ( d.weighted() ) { wField = d.weightField(); myAttrList.append( wField ); } // This might have attributes or mightnot have attibutes at all // based on the variableRadius() and weighted() QgsFeatureIterator fit = inputLayer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( myAttrList ) ); int totalFeatures = inputLayer->featureCount(); int counter = 0; QProgressDialog p( tr( "Creating heatmap" ), tr( "Abort" ), 0, totalFeatures, mQGisIface->mainWindow() ); p.setWindowModality( Qt::ApplicationModal ); p.show(); QgsFeature myFeature; while ( fit.nextFeature( myFeature ) ) { counter++; p.setValue( counter ); QApplication::processEvents(); if ( p.wasCanceled() ) { QMessageBox::information( 0, tr( "Heatmap generation aborted" ), tr( "QGIS will now load the partially-computed raster." ) ); break; } QgsGeometry* myPointGeometry; myPointGeometry = myFeature.geometry(); // convert the geometry to point QgsPoint myPoint; myPoint = myPointGeometry->asPoint(); // avoiding any empty points or out of extent points if (( myPoint.x() < myBBox.xMinimum() ) || ( myPoint.y() < myBBox.yMinimum() ) || ( myPoint.x() > myBBox.xMaximum() ) || ( myPoint.y() > myBBox.yMaximum() ) ) { continue; } // If radius is variable then fetch it and calculate new pixel buffer size if ( d.variableRadius() ) { radius = myFeature.attribute( rField ).toDouble() * radiusToMapUnits; myBuffer = bufferSize( radius, cellsize ); } int blockSize = 2 * myBuffer + 1; //Block SIDE would be more appropriate // calculate the pixel position unsigned int xPosition, yPosition; xPosition = (( myPoint.x() - myBBox.xMinimum() ) / cellsize ) - myBuffer; yPosition = (( myPoint.y() - myBBox.yMinimum() ) / cellsize ) - myBuffer; // get the data float *dataBuffer = ( float * ) CPLMalloc( sizeof( float ) * blockSize * blockSize ); poBand->RasterIO( GF_Read, xPosition, yPosition, blockSize, blockSize, dataBuffer, blockSize, blockSize, GDT_Float32, 0, 0 ); double weight = 1.0; if ( d.weighted() ) { weight = myFeature.attribute( wField ).toDouble(); } for ( int xp = 0; xp <= myBuffer; xp++ ) { for ( int yp = 0; yp <= myBuffer; yp++ ) { double distance = sqrt( pow( xp, 2.0 ) + pow( yp, 2.0 ) ); // is pixel outside search bandwidth of feature? if ( distance > myBuffer ) { continue; } double pixelValue = weight * calculateKernelValue( distance, myBuffer, kernelShape ); // clearing anamolies along the axes if ( xp == 0 && yp == 0 ) { pixelValue /= 4; } else if ( xp == 0 || yp == 0 ) { pixelValue /= 2; } int pos[4]; pos[0] = ( myBuffer + xp ) * blockSize + ( myBuffer + yp ); pos[1] = ( myBuffer + xp ) * blockSize + ( myBuffer - yp ); pos[2] = ( myBuffer - xp ) * blockSize + ( myBuffer + yp ); pos[3] = ( myBuffer - xp ) * blockSize + ( myBuffer - yp ); for ( int p = 0; p < 4; p++ ) { if ( dataBuffer[ pos[p] ] == NO_DATA ) { dataBuffer[ pos[p] ] = 0; } dataBuffer[ pos[p] ] += pixelValue; } } } poBand->RasterIO( GF_Write, xPosition, yPosition, blockSize, blockSize, dataBuffer, blockSize, blockSize, GDT_Float32, 0, 0 ); CPLFree( dataBuffer ); } // Finally close the dataset GDALClose(( GDALDatasetH ) heatmapDS ); // Open the file in QGIS window mQGisIface->addRasterLayer( d.outputFilename(), QFileInfo( d.outputFilename() ).baseName() ); } }
bool QgsGeorefTransform::transformRasterToWorld( const QgsPoint &raster, QgsPoint &world ) { // flip y coordinate due to different CS orientation QgsPoint raster_flipped( raster.x(), -raster.y() ); return gdal_transform( raster_flipped, world, 0 ); }
double QgsDistanceArea::computeDistanceBearing( const QgsPoint& p1, const QgsPoint& p2, double* course1, double* course2 ) const { if ( qgsDoubleNear( p1.x(), p2.x() ) && qgsDoubleNear( p1.y(), p2.y() ) ) return 0; // ellipsoid double a = mSemiMajor; double b = mSemiMinor; double f = 1 / mInvFlattening; double p1_lat = DEG2RAD( p1.y() ), p1_lon = DEG2RAD( p1.x() ); double p2_lat = DEG2RAD( p2.y() ), p2_lon = DEG2RAD( p2.x() ); double L = p2_lon - p1_lon; double U1 = atan(( 1 - f ) * tan( p1_lat ) ); double U2 = atan(( 1 - f ) * tan( p2_lat ) ); double sinU1 = sin( U1 ), cosU1 = cos( U1 ); double sinU2 = sin( U2 ), cosU2 = cos( U2 ); double lambda = L; double lambdaP = 2 * M_PI; double sinLambda = 0; double cosLambda = 0; double sinSigma = 0; double cosSigma = 0; double sigma = 0; double alpha = 0; double cosSqAlpha = 0; double cos2SigmaM = 0; double C = 0; double tu1 = 0; double tu2 = 0; int iterLimit = 20; while ( qAbs( lambda - lambdaP ) > 1e-12 && --iterLimit > 0 ) { sinLambda = sin( lambda ); cosLambda = cos( lambda ); tu1 = ( cosU2 * sinLambda ); tu2 = ( cosU1 * sinU2 - sinU1 * cosU2 * cosLambda ); sinSigma = sqrt( tu1 * tu1 + tu2 * tu2 ); cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda; sigma = atan2( sinSigma, cosSigma ); alpha = asin( cosU1 * cosU2 * sinLambda / sinSigma ); cosSqAlpha = cos( alpha ) * cos( alpha ); cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha; C = f / 16 * cosSqAlpha * ( 4 + f * ( 4 - 3 * cosSqAlpha ) ); lambdaP = lambda; lambda = L + ( 1 - C ) * f * sin( alpha ) * ( sigma + C * sinSigma * ( cos2SigmaM + C * cosSigma * ( -1 + 2 * cos2SigmaM * cos2SigmaM ) ) ); } if ( iterLimit == 0 ) return -1; // formula failed to converge double uSq = cosSqAlpha * ( a * a - b * b ) / ( b * b ); double A = 1 + uSq / 16384 * ( 4096 + uSq * ( -768 + uSq * ( 320 - 175 * uSq ) ) ); double B = uSq / 1024 * ( 256 + uSq * ( -128 + uSq * ( 74 - 47 * uSq ) ) ); double deltaSigma = B * sinSigma * ( cos2SigmaM + B / 4 * ( cosSigma * ( -1 + 2 * cos2SigmaM * cos2SigmaM ) - B / 6 * cos2SigmaM * ( -3 + 4 * sinSigma * sinSigma ) * ( -3 + 4 * cos2SigmaM * cos2SigmaM ) ) ); double s = b * A * ( sigma - deltaSigma ); if ( course1 ) { *course1 = atan2( tu1, tu2 ); } if ( course2 ) { // PI is added to return azimuth from P2 to P1 *course2 = atan2( cosU1 * sinLambda, -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda ) + M_PI; } return s; }
int QgsPoint::onSegment( const QgsPoint& a, const QgsPoint& b ) const { //algorithm from 'graphics GEMS', A. Paeth: 'A Fast 2D Point-on-line test' if ( qAbs(( b.y() - a.y() ) *( m_x - a.x() ) - ( m_y - a.y() ) *( b.x() - a.x() ) ) >= qMax( qAbs( b.x() - a.x() ), qAbs( b.y() - a.y() ) ) ) { return 0; } if (( b.x() < a.x() && a.x() < m_x ) || ( b.y() < a.y() && a.y() < m_y ) ) { return 1; } if (( m_x < a.x() && a.x() < b.x() ) || ( m_y < a.y() && a.y() < b.y() ) ) { return 1; } if (( a.x() < b.x() && b.x() < m_x ) || ( a.y() < b.y() && b.y() < m_y ) ) { return 3; } if (( m_x < b.x() && b.x() < a.x() ) || ( m_y < b.y() && b.y() < a.y() ) ) { return 3; } return 2; }
double QgsDistanceArea::computeDistanceFlat( const QgsPoint& p1, const QgsPoint& p2 ) const { return sqrt(( p2.x() - p1.x() ) * ( p2.x() - p1.x() ) + ( p2.y() - p1.y() ) * ( p2.y() - p1.y() ) ); }
QgsPointV2 QgsMapTool::toMapCoordinates( QgsMapLayer* layer, const QgsPointV2& point ) { QgsPoint result = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPoint( point.x(), point.y() ) ); return QgsPointV2( result.x(), result.y() ); }
bool QgsMapToolIdentify::identifyVectorLayer( QgsVectorLayer *layer, int x, int y ) { if ( !layer ) return false; QMap< QString, QString > attributes, derivedAttributes; QgsPoint point = mCanvas->getCoordinateTransform()->toMapCoordinates( x, y ); derivedAttributes.insert( tr( "(clicked coordinate)" ), point.toString() ); // load identify radius from settings QSettings settings; double identifyValue = settings.value( "/Map/identifyRadius", QGis::DEFAULT_IDENTIFY_RADIUS ).toDouble(); QString ellipsoid = settings.value( "/qgis/measure/ellipsoid", GEO_NONE ).toString(); if ( identifyValue <= 0.0 ) identifyValue = QGis::DEFAULT_IDENTIFY_RADIUS; int featureCount = 0; QgsFeatureList featureList; // toLayerCoordinates will throw an exception for an 'invalid' point. // For example, if you project a world map onto a globe using EPSG 2163 // and then click somewhere off the globe, an exception will be thrown. try { // create the search rectangle double searchRadius = mCanvas->extent().width() * ( identifyValue / 100.0 ); QgsRectangle r; r.setXMinimum( point.x() - searchRadius ); r.setXMaximum( point.x() + searchRadius ); r.setYMinimum( point.y() - searchRadius ); r.setYMaximum( point.y() + searchRadius ); r = toLayerCoordinates( layer, r ); layer->select( layer->pendingAllAttributesList(), r, true, true ); QgsFeature f; while ( layer->nextFeature( f ) ) featureList << QgsFeature( f ); } catch ( QgsCsException & cse ) { Q_UNUSED( cse ); // catch exception for 'invalid' point and proceed with no features found QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) ); } // init distance/area calculator QgsDistanceArea calc; if ( !featureList.count() == 0 ) { calc.setEllipsoidalMode( mCanvas->hasCrsTransformEnabled() ); calc.setEllipsoid( ellipsoid ); calc.setSourceCrs( layer->crs().srsid() ); } QgsFeatureList::iterator f_it = featureList.begin(); for ( ; f_it != featureList.end(); ++f_it ) { featureCount++; QgsFeatureId fid = f_it->id(); QMap<QString, QString> derivedAttributes; // Calculate derived attributes and insert: // measure distance or area depending on geometry type if ( layer->geometryType() == QGis::Line ) { double dist = calc.measure( f_it->geometry() ); QGis::UnitType myDisplayUnits; convertMeasurement( calc, dist, myDisplayUnits, false ); QString str = calc.textUnit( dist, 3, myDisplayUnits, false ); // dist and myDisplayUnits are out params derivedAttributes.insert( tr( "Length" ), str ); if ( f_it->geometry()->wkbType() == QGis::WKBLineString || f_it->geometry()->wkbType() == QGis::WKBLineString25D ) { // Add the start and end points in as derived attributes str = QLocale::system().toString( f_it->geometry()->asPolyline().first().x(), 'g', 10 ); derivedAttributes.insert( tr( "firstX", "attributes get sorted; translation for lastX should be lexically larger than this one" ), str ); str = QLocale::system().toString( f_it->geometry()->asPolyline().first().y(), 'g', 10 ); derivedAttributes.insert( tr( "firstY" ), str ); str = QLocale::system().toString( f_it->geometry()->asPolyline().last().x(), 'g', 10 ); derivedAttributes.insert( tr( "lastX", "attributes get sorted; translation for firstX should be lexically smaller than this one" ), str ); str = QLocale::system().toString( f_it->geometry()->asPolyline().last().y(), 'g', 10 ); derivedAttributes.insert( tr( "lastY" ), str ); } } else if ( layer->geometryType() == QGis::Polygon ) { double area = calc.measure( f_it->geometry() ); QGis::UnitType myDisplayUnits; convertMeasurement( calc, area, myDisplayUnits, true ); // area and myDisplayUnits are out params QString str = calc.textUnit( area, 3, myDisplayUnits, true ); derivedAttributes.insert( tr( "Area" ), str ); } else if ( layer->geometryType() == QGis::Point && ( f_it->geometry()->wkbType() == QGis::WKBPoint || f_it->geometry()->wkbType() == QGis::WKBPoint25D ) ) { // Include the x and y coordinates of the point as a derived attribute QString str; str = QLocale::system().toString( f_it->geometry()->asPoint().x(), 'g', 10 ); derivedAttributes.insert( "X", str ); str = QLocale::system().toString( f_it->geometry()->asPoint().y(), 'g', 10 ); derivedAttributes.insert( "Y", str ); } derivedAttributes.insert( tr( "feature id" ), fid < 0 ? tr( "new feature" ) : FID_TO_STRING( fid ) ); results()->addFeature( layer, *f_it, derivedAttributes ); } QgsDebugMsg( "Feature count on identify: " + QString::number( featureCount ) ); return featureCount > 0; }
QPoint QgsMapTool::toCanvasCoordinates( const QgsPoint& point ) { qreal x = point.x(), y = point.y(); mCanvas->getCoordinateTransform()->transformInPlace( x, y ); return QPoint( qRound( x ), qRound( y ) ); }
void writePoint( struct Map_info* map, int type, const QgsPoint& point, struct line_cats *cats ) { Vect_reset_line( line ); Vect_append_point( line, point.x(), point.y(), 0 ); Vect_write_line( map, type, line, cats ); }
double QgsLineString::closestSegment( const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon ) const { double sqrDist = std::numeric_limits<double>::max(); double leftOfDist = std::numeric_limits<double>::max(); int prevLeftOf = 0; double prevLeftOfX = 0.0; double prevLeftOfY = 0.0; double testDist = 0; double segmentPtX, segmentPtY; if ( leftOf ) *leftOf = 0; int size = mX.size(); if ( size == 0 || size == 1 ) { vertexAfter = QgsVertexId( 0, 0, 0 ); return -1; } for ( int i = 1; i < size; ++i ) { double prevX = mX.at( i - 1 ); double prevY = mY.at( i - 1 ); double currentX = mX.at( i ); double currentY = mY.at( i ); testDist = QgsGeometryUtils::sqrDistToLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY, segmentPtX, segmentPtY, epsilon ); if ( testDist < sqrDist ) { sqrDist = testDist; segmentPt.setX( segmentPtX ); segmentPt.setY( segmentPtY ); vertexAfter.part = 0; vertexAfter.ring = 0; vertexAfter.vertex = i; } if ( leftOf && qgsDoubleNear( testDist, sqrDist ) ) { int left = QgsGeometryUtils::leftOfLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY ); // if left equals 0, the test could not be performed (e.g. point in line with segment or on segment) // so don't set leftOf in this case, and hope that there's another segment that's the same distance // where we can perform the check if ( left != 0 ) { if ( qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 ) { // we have two possible segments each with equal distance to point, but they disagree // on whether or not the point is to the left of them. // so we test the segments themselves and flip the result. // see https://stackoverflow.com/questions/10583212/elegant-left-of-test-for-polyline *leftOf = -QgsGeometryUtils::leftOfLine( currentX, currentY, prevLeftOfX, prevLeftOfY, prevX, prevY ); } else { *leftOf = left; } prevLeftOf = *leftOf; leftOfDist = testDist; prevLeftOfX = prevX; prevLeftOfY = prevY; } else if ( testDist < leftOfDist ) { *leftOf = left; leftOfDist = testDist; prevLeftOf = 0; } } } return sqrDist; }
void QgsGCPCanvasItem::paint( QPainter* p ) { QgsRenderContext context; if ( !setRenderContextVariables( p, context ) ) { return; } p->setRenderHint( QPainter::Antialiasing ); bool enabled = true; QgsPoint worldCoords; int id = -1; if ( mDataPoint ) { enabled = mDataPoint->isEnabled(); worldCoords = mDataPoint->mapCoords(); id = mDataPoint->id(); } p->setOpacity( enabled ? 1.0 : 0.3 ); // draw the point p->setPen( Qt::black ); p->setBrush( mPointBrush ); p->drawEllipse( -2, -2, 5, 5 ); QSettings s; bool showIDs = s.value( "/Plugin-GeoReferencer/Config/ShowId" ).toBool(); bool showCoords = s.value( "/Plugin-GeoReferencer/Config/ShowCoords" ).toBool(); QString msg; if ( showIDs && showCoords ) { msg = QString( "%1\nX %2\nY %3" ).arg( QString::number( id ), QString::number( worldCoords.x(), 'f' ), QString::number( worldCoords.y(), 'f' ) ); } else if ( showIDs ) { msg = msg = QString::number( id ); } else if ( showCoords ) { msg = QString( "X %1\nY %2" ).arg( QString::number( worldCoords.x(), 'f' ), QString::number( worldCoords.y(), 'f' ) ); } if ( !msg.isEmpty() ) { p->setBrush( mLabelBrush ); QFont textFont( "helvetica" ); textFont.setPixelSize( fontSizePainterUnits( 12, context ) ); p->setFont( textFont ); QRectF textBounds = p->boundingRect( 3 * context.scaleFactor(), 3 * context.scaleFactor(), 5 * context.scaleFactor(), 5 * context.scaleFactor(), Qt::AlignLeft, msg ); mTextBoxRect = QRectF( textBounds.x() - context.scaleFactor() * 1, textBounds.y() - context.scaleFactor() * 1, textBounds.width() + 2 * context.scaleFactor(), textBounds.height() + 2 * context.scaleFactor() ); p->drawRect( mTextBoxRect ); p->drawText( textBounds, Qt::AlignLeft, msg ); } if ( data( 1 ) != "composer" ) //draw residuals only on screen { drawResidualArrow( p, context ); } }
void QgsGeometryAnalyzer::createOffsetGeometry( QgsGeometry* geom, QgsGeometry* lineGeom, double offset ) { if ( !geom || !lineGeom ) { return; } QList<QgsGeometry*> inputGeomList; if ( geom->isMultipart() ) { inputGeomList = geom->asGeometryCollection(); } else { inputGeomList.push_back( geom ); } QList<GEOSGeometry*> outputGeomList; QList<QgsGeometry*>::const_iterator inputGeomIt = inputGeomList.constBegin(); for ( ; inputGeomIt != inputGeomList.constEnd(); ++inputGeomIt ) { if ( geom->type() == QGis::Line ) { //geos 3.3 needed for line offsets #if defined(GEOS_VERSION_MAJOR) && defined(GEOS_VERSION_MINOR) && \ ((GEOS_VERSION_MAJOR>3) || ((GEOS_VERSION_MAJOR==3) && (GEOS_VERSION_MINOR>=3))) outputGeomList.push_back( GEOSOffsetCurve(( *inputGeomIt )->asGeos(), -offset, 8 /*quadSegments*/, 0 /*joinStyle*/, 5.0 /*mitreLimit*/ ) ); #else outputGeomList.push_back( GEOSGeom_clone(( *inputGeomIt )->asGeos() ) ); #endif } else if ( geom->type() == QGis::Point ) { QgsPoint p = ( *inputGeomIt )->asPoint(); p = createPointOffset( p.x(), p.y(), offset, lineGeom ); GEOSCoordSequence* ptSeq = GEOSCoordSeq_create( 1, 2 ); GEOSCoordSeq_setX( ptSeq, 0, p.x() ); GEOSCoordSeq_setY( ptSeq, 0, p.y() ); GEOSGeometry* geosPt = GEOSGeom_createPoint( ptSeq ); outputGeomList.push_back( geosPt ); } } if ( !geom->isMultipart() ) { GEOSGeometry* outputGeom = outputGeomList.at( 0 ); if ( outputGeom ) { geom->fromGeos( outputGeom ); } } else { GEOSGeometry** geomArray = new GEOSGeometry*[outputGeomList.size()]; for ( int i = 0; i < outputGeomList.size(); ++i ) { geomArray[i] = outputGeomList.at( i ); } GEOSGeometry* collection = 0; if ( geom->type() == QGis::Point ) { collection = GEOSGeom_createCollection( GEOS_MULTIPOINT, geomArray, outputGeomList.size() ); } else if ( geom->type() == QGis::Line ) { collection = GEOSGeom_createCollection( GEOS_MULTILINESTRING, geomArray, outputGeomList.size() ); } geom->fromGeos( collection ); delete[] geomArray; } }
void GlobePlugin::setupMap() { QSettings settings; QString cacheDirectory = settings.value( "cache/directory", QgsApplication::qgisSettingsDirPath() + "cache" ).toString(); #if OSGEARTH_VERSION_GREATER_OR_EQUAL( 2, 2, 0 ) FileSystemCacheOptions cacheOptions; cacheOptions.rootPath() = cacheDirectory.toStdString(); #else TMSCacheOptions cacheOptions; cacheOptions.setPath( cacheDirectory.toStdString() ); #endif MapOptions mapOptions; mapOptions.cache() = cacheOptions; osgEarth::Map *map = new osgEarth::Map( mapOptions ); //Default image layer /* GDALOptions driverOptions; driverOptions.url() = QDir::cleanPath( QgsApplication::pkgDataPath() + "/globe/world.tif" ).toStdString(); ImageLayerOptions layerOptions( "world", driverOptions ); map->addImageLayer( new osgEarth::ImageLayer( layerOptions ) ); */ MapNodeOptions nodeOptions; //nodeOptions.proxySettings() = //nodeOptions.enableLighting() = false; //LoadingPolicy loadingPolicy( LoadingPolicy::MODE_SEQUENTIAL ); TerrainOptions terrainOptions; //terrainOptions.loadingPolicy() = loadingPolicy; terrainOptions.compositingTechnique() = TerrainOptions::COMPOSITING_MULTITEXTURE_FFP; //terrainOptions.lodFallOff() = 6.0; nodeOptions.setTerrainOptions( terrainOptions ); // The MapNode will render the Map object in the scene graph. mMapNode = new osgEarth::MapNode( map, nodeOptions ); if ( settings.value( "/Plugin-Globe/baseLayerEnabled", true ).toBool() ) { setBaseMap( settings.value( "/Plugin-Globe/baseLayerURL", "http://readymap.org/readymap/tiles/1.0.0/7/" ).toString() ); } mRootNode = new osg::Group(); mRootNode->addChild( mMapNode ); // Add layers to the map imageLayersChanged(); elevationLayersChanged(); // model placement utils #ifdef HAVE_OSGEARTH_ELEVATION_QUERY #else mElevationManager = new osgEarth::Util::ElevationManager( mMapNode->getMap() ); mElevationManager->setTechnique( osgEarth::Util::ElevationManager::TECHNIQUE_GEOMETRIC ); mElevationManager->setMaxTilesToCache( 50 ); mObjectPlacer = new osgEarth::Util::ObjectPlacer( mMapNode ); // place 3D model on point layer if ( mSettingsDialog->modelLayer() && !mSettingsDialog->modelPath().isEmpty() ) { osg::Node* model = osgDB::readNodeFile( mSettingsDialog->modelPath().toStdString() ); if ( model ) { QgsVectorLayer* layer = mSettingsDialog->modelLayer(); QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) ); //TODO: select only visible features QgsFeature feature; while ( fit.nextFeature( feature ) ) { QgsPoint point = feature.geometry()->asPoint(); placeNode( model, point.y(), point.x() ); } } } #endif }
bool QgsGeometryAnalyzer::clipSegmentByRange( double x1, double y1, double m1, double x2, double y2, double m2, double range1, double range2, QgsPoint& pt1, QgsPoint& pt2, bool& secondPointClipped ) { bool reversed = m1 > m2; double tmp; //reverse m1, m2 if necessary (and consequently also x1,x2 / y1, y2) if ( reversed ) { tmp = m1; m1 = m2; m2 = tmp; tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; } //reverse range1, range2 if necessary if ( range1 > range2 ) { tmp = range1; range1 = range2; range2 = tmp; } //segment completely outside of range if ( m2 < range1 || m1 > range2 ) { return false; } //segment completely inside of range if ( m2 <= range2 && m1 >= range1 ) { if ( reversed ) { pt1.setX( x2 ); pt1.setY( y2 ); pt2.setX( x1 ); pt2.setY( y1 ); } else { pt1.setX( x1 ); pt1.setY( y1 ); pt2.setX( x2 ); pt2.setY( y2 ); } secondPointClipped = false; return true; } //m1 inside and m2 not if ( m1 >= range1 && m1 <= range2 ) { pt1.setX( x1 ); pt1.setY( y1 ); double dist = ( range2 - m1 ) / ( m2 - m1 ); pt2.setX( x1 + ( x2 - x1 ) * dist ); pt2.setY( y1 + ( y2 - y1 ) * dist ); secondPointClipped = !reversed; } //m2 inside and m1 not if ( m2 >= range1 && m2 <= range2 ) { pt2.setX( x2 ); pt2.setY( y2 ); double dist = ( m2 - range1 ) / ( m2 - m1 ); pt1.setX( x2 - ( x2 - x1 ) * dist ); pt1.setY( y2 - ( y2 - y1 ) * dist ); secondPointClipped = reversed; } //range1 and range 2 both inside the segment if ( range1 >= m1 && range2 <= m2 ) { double dist1 = ( range1 - m1 ) / ( m2 - m1 ); double dist2 = ( range2 - m1 ) / ( m2 - m1 ); pt1.setX( x1 + ( x2 - x1 ) * dist1 ); pt1.setY( y1 + ( y2 - y1 ) * dist1 ); pt2.setX( x1 + ( x2 - x1 ) * dist2 ); pt2.setY( y1 + ( y2 - y1 ) * dist2 ); secondPointClipped = true; } if ( reversed ) //switch p1 and p2 { QgsPoint tmpPt = pt1; pt1 = pt2; pt2 = tmpPt; } return true; }
void QgsMapToolSimplify::canvasPressEvent( QMouseEvent * e ) { QgsVectorLayer * vlayer = currentVectorLayer(); if ( !vlayer ) { notifyNotVectorLayer(); return; } QgsPoint layerCoords = mCanvas->getCoordinateTransform()->toMapPoint( e->pos().x(), e->pos().y() ); double r = QgsTolerance::vertexSearchRadius( vlayer, mCanvas->mapSettings() ); QgsRectangle selectRect = QgsRectangle( layerCoords.x() - r, layerCoords.y() - r, layerCoords.x() + r, layerCoords.y() + r ); QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectRect ).setSubsetOfAttributes( QgsAttributeList() ) ); QgsGeometry* geometry = QgsGeometry::fromPoint( layerCoords ); double minDistance = DBL_MAX; double currentDistance; mSelectedFeature.setValid( false ); QgsFeature f; while ( fit.nextFeature( f ) ) { currentDistance = geometry->distance( *( f.geometry() ) ); if ( currentDistance < minDistance ) { minDistance = currentDistance; mSelectedFeature = f; } } // delete previous rubberband (if any) removeRubberBand(); if ( mSelectedFeature.isValid() ) { if ( mSelectedFeature.geometry()->isMultipart() ) { emit messageEmitted( tr( "Multipart features are not supported for simplification." ), QgsMessageBar::CRITICAL ); return; } mRubberBand = new QgsRubberBand( mCanvas ); mRubberBand->setToGeometry( mSelectedFeature.geometry(), 0 ); mRubberBand->setColor( QColor( 255, 0, 0, 65 ) ); mRubberBand->setWidth( 2 ); mRubberBand->show(); //calculate boudaries for slidebar if ( calculateSliderBoudaries() ) { // show dialog as a non-modal window mSimplifyDialog->show(); } else { emit messageEmitted( tr( "This feature cannot be simplified. Check if feature has enough vertices to be simplified." ), QgsMessageBar::WARNING ); } } }
void QgsGeometryAnalyzer::locateAlongSegment( double x1, double y1, double m1, double x2, double y2, double m2, double measure, bool& pt1Ok, QgsPoint& pt1, bool& pt2Ok, QgsPoint& pt2 ) { bool reversed = false; pt1Ok = false; pt2Ok = false; double tolerance = 0.000001; //work with a small tolerance to catch e.g. locations at endpoints if ( m1 > m2 ) { double tmp = m1; m1 = m2; m2 = tmp; reversed = true; } //segment does not match if (( m1 - measure ) > tolerance || ( measure - m2 ) > tolerance ) { pt1Ok = false; pt2Ok = false; return; } //match with vertex1 if ( qgsDoubleNear( m1, measure, tolerance ) ) { if ( reversed ) { pt2Ok = true; pt2.setX( x2 ); pt2.setY( y2 ); } else { pt1Ok = true; pt1.setX( x1 ); pt1.setY( y1 ); } } //match with vertex2 if ( qgsDoubleNear( m2, measure, tolerance ) ) { if ( reversed ) { pt1Ok = true; pt1.setX( x1 ); pt1.setY( y1 ); } else { pt2Ok = true; pt2.setX( x2 ); pt2.setY( y2 ); } } if ( pt1Ok || pt2Ok ) { return; } //match between the vertices if ( qgsDoubleNear( m1, m2 ) ) { pt1.setX( x1 ); pt1.setY( y1 ); pt1Ok = true; return; } double dist = ( measure - m1 ) / ( m2 - m1 ); if ( reversed ) { dist = 1 - dist; } pt1.setX( x1 + dist * ( x2 - x1 ) ); pt1.setY( y1 + dist * ( y2 - y1 ) ); pt1Ok = true; }
bool QgsRectangle::contains( const QgsPoint &p ) const { return xmin <= p.x() && p.x() <= xmax && ymin <= p.y() && p.y() <= ymax; }
QMap< QString, QString > QgsMapToolIdentify::featureDerivedAttributes( QgsFeature *feature, QgsMapLayer *layer ) { // Calculate derived attributes and insert: // measure distance or area depending on geometry type QMap< QString, QString > derivedAttributes; // init distance/area calculator QString ellipsoid = QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ); QgsDistanceArea calc; calc.setEllipsoidalMode( mCanvas->hasCrsTransformEnabled() ); calc.setEllipsoid( ellipsoid ); calc.setSourceCrs( layer->crs().srsid() ); QGis::WkbType wkbType = QGis::WKBNoGeometry; QGis::GeometryType geometryType = QGis::NoGeometry; if ( feature->geometry() ) { geometryType = feature->geometry()->type(); wkbType = feature->geometry()->wkbType(); } if ( geometryType == QGis::Line ) { double dist = calc.measure( feature->geometry() ); QGis::UnitType myDisplayUnits; convertMeasurement( calc, dist, myDisplayUnits, false ); QString str = calc.textUnit( dist, 3, myDisplayUnits, false ); // dist and myDisplayUnits are out params derivedAttributes.insert( tr( "Length" ), str ); if ( wkbType == QGis::WKBLineString || wkbType == QGis::WKBLineString25D ) { // Add the start and end points in as derived attributes QgsPoint pnt = mCanvas->mapRenderer()->layerToMapCoordinates( layer, feature->geometry()->asPolyline().first() ); str = QLocale::system().toString( pnt.x(), 'g', 10 ); derivedAttributes.insert( tr( "firstX", "attributes get sorted; translation for lastX should be lexically larger than this one" ), str ); str = QLocale::system().toString( pnt.y(), 'g', 10 ); derivedAttributes.insert( tr( "firstY" ), str ); pnt = mCanvas->mapRenderer()->layerToMapCoordinates( layer, feature->geometry()->asPolyline().last() ); str = QLocale::system().toString( pnt.x(), 'g', 10 ); derivedAttributes.insert( tr( "lastX", "attributes get sorted; translation for firstX should be lexically smaller than this one" ), str ); str = QLocale::system().toString( pnt.y(), 'g', 10 ); derivedAttributes.insert( tr( "lastY" ), str ); } } else if ( geometryType == QGis::Polygon ) { double area = calc.measure( feature->geometry() ); double perimeter = calc.measurePerimeter( feature->geometry() ); QGis::UnitType myDisplayUnits; convertMeasurement( calc, area, myDisplayUnits, true ); // area and myDisplayUnits are out params QString str = calc.textUnit( area, 3, myDisplayUnits, true ); derivedAttributes.insert( tr( "Area" ), str ); convertMeasurement( calc, perimeter, myDisplayUnits, false ); // perimeter and myDisplayUnits are out params str = calc.textUnit( perimeter, 3, myDisplayUnits, false ); derivedAttributes.insert( tr( "Perimeter" ), str ); } else if ( geometryType == QGis::Point && ( wkbType == QGis::WKBPoint || wkbType == QGis::WKBPoint25D ) ) { // Include the x and y coordinates of the point as a derived attribute QgsPoint pnt = mCanvas->mapRenderer()->layerToMapCoordinates( layer, feature->geometry()->asPoint() ); QString str = QLocale::system().toString( pnt.x(), 'g', 10 ); derivedAttributes.insert( "X", str ); str = QLocale::system().toString( pnt.y(), 'g', 10 ); derivedAttributes.insert( "Y", str ); } return derivedAttributes; }