QMap< QString, QString > QgsMapToolIdentify::featureDerivedAttributes( QgsFeature *feature, QgsMapLayer *layer, const QgsPoint& layerPoint ) { // 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()->ellipsoid(); QgsDistanceArea calc; calc.setEllipsoidalMode( mCanvas->hasCrsTransformEnabled() ); calc.setEllipsoid( ellipsoid ); calc.setSourceCrs( layer->crs().srsid() ); QgsWkbTypes::Type wkbType = QgsWkbTypes::NoGeometry; QgsWkbTypes::GeometryType geometryType = QgsWkbTypes::NullGeometry; QgsVertexId vId; QgsPointV2 closestPoint; if ( feature->hasGeometry() ) { geometryType = feature->geometry().type(); wkbType = feature->geometry().geometry()->wkbType(); //find closest vertex to clicked point closestPoint = QgsGeometryUtils::closestVertex( *feature->geometry().geometry(), QgsPointV2( layerPoint.x(), layerPoint.y() ), vId ); } if ( QgsWkbTypes::isMultiType( wkbType ) ) { QString str = QLocale::system().toString( static_cast<const QgsGeometryCollection*>( feature->geometry().geometry() )->numGeometries() ); derivedAttributes.insert( tr( "Parts" ), str ); str = QLocale::system().toString( vId.part + 1 ); derivedAttributes.insert( tr( "Part number" ), str ); } if ( geometryType == QgsWkbTypes::LineGeometry ) { double dist = calc.measureLength( feature->geometry() ); dist = calc.convertLengthMeasurement( dist, displayDistanceUnits() ); QString str = formatDistance( dist ); derivedAttributes.insert( tr( "Length" ), str ); const QgsCurve* curve = dynamic_cast< const QgsCurve* >( feature->geometry().geometry() ); if ( curve ) { str = QLocale::system().toString( curve->nCoordinates() ); derivedAttributes.insert( tr( "Vertices" ), str ); //add details of closest vertex to identify point closestVertexAttributes( *curve, vId, layer, derivedAttributes ); // Add the start and end points in as derived attributes QgsPoint pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPoint( curve->startPoint().x(), curve->startPoint().y() ) ); str = formatXCoordinate( pnt ); derivedAttributes.insert( tr( "firstX", "attributes get sorted; translation for lastX should be lexically larger than this one" ), str ); str = formatYCoordinate( pnt ); derivedAttributes.insert( tr( "firstY" ), str ); pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPoint( curve->endPoint().x(), curve->endPoint().y() ) ); str = formatXCoordinate( pnt ); derivedAttributes.insert( tr( "lastX", "attributes get sorted; translation for firstX should be lexically smaller than this one" ), str ); str = formatYCoordinate( pnt ); derivedAttributes.insert( tr( "lastY" ), str ); } } else if ( geometryType == QgsWkbTypes::PolygonGeometry ) { double area = calc.measureArea( feature->geometry() ); area = calc.convertAreaMeasurement( area, displayAreaUnits() ); QString str = formatArea( area ); derivedAttributes.insert( tr( "Area" ), str ); double perimeter = calc.measurePerimeter( feature->geometry() ); perimeter = calc.convertLengthMeasurement( perimeter, displayDistanceUnits() ); str = formatDistance( perimeter ); derivedAttributes.insert( tr( "Perimeter" ), str ); str = QLocale::system().toString( feature->geometry().geometry()->nCoordinates() ); derivedAttributes.insert( tr( "Vertices" ), str ); //add details of closest vertex to identify point closestVertexAttributes( *feature->geometry().geometry(), vId, layer, derivedAttributes ); } else if ( geometryType == QgsWkbTypes::PointGeometry && QgsWkbTypes::flatType( wkbType ) == QgsWkbTypes::Point ) { // Include the x and y coordinates of the point as a derived attribute QgsPoint pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, feature->geometry().asPoint() ); QString str = formatXCoordinate( pnt ); derivedAttributes.insert( "X", str ); str = formatYCoordinate( pnt ); derivedAttributes.insert( "Y", str ); if ( QgsWkbTypes::hasZ( wkbType ) ) { str = QLocale::system().toString( static_cast<const QgsPointV2*>( feature->geometry().geometry() )->z(), 'g', 10 ); derivedAttributes.insert( "Z", str ); } if ( QgsWkbTypes::hasM( wkbType ) ) { str = QLocale::system().toString( static_cast<const QgsPointV2*>( feature->geometry().geometry() )->m(), 'g', 10 ); derivedAttributes.insert( "M", str ); } } return derivedAttributes; }
void TestQgsDistanceArea::measureAreaAndUnits() { QgsDistanceArea da; da.setSourceCrs( 3452 ); da.setEllipsoidalMode( false ); da.setEllipsoid( "NONE" ); QgsCoordinateReferenceSystem daCRS; daCRS.createFromSrsId( da.sourceCrsId() ); QgsPolyline ring; ring << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) << QgsPoint( 2, 1 ) << QgsPoint( 2, 2 ) << QgsPoint( 0, 2 ) << QgsPoint( 0, 0 ); QgsPolygon poly; poly << ring; QgsGeometry polygon( QgsGeometry::fromPolygon( poly ) ); // We check both the measured area AND the units, in case the logic regarding // ellipsoids and units changes in future double area = da.measureArea( &polygon ); QgsUnitTypes::AreaUnit units = da.areaUnits(); QgsDebugMsg( QString( "measured %1 in %2" ).arg( area ).arg( QgsUnitTypes::toString( units ) ) ); QVERIFY(( qgsDoubleNear( area, 3.0, 0.00000001 ) && units == QgsUnitTypes::AreaSquareDegrees ) || ( qgsDoubleNear( area, 37176087091.5, 0.1 ) && units == QgsUnitTypes::AreaSquareMeters ) ); da.setEllipsoid( "WGS84" ); area = da.measureArea( &polygon ); units = da.areaUnits(); QgsDebugMsg( QString( "measured %1 in %2" ).arg( area ).arg( QgsUnitTypes::toString( units ) ) ); QVERIFY(( qgsDoubleNear( area, 3.0, 0.00000001 ) && units == QgsUnitTypes::AreaSquareDegrees ) || ( qgsDoubleNear( area, 37176087091.5, 0.1 ) && units == QgsUnitTypes::AreaSquareMeters ) ); da.setEllipsoidalMode( true ); area = da.measureArea( &polygon ); units = da.areaUnits(); QgsDebugMsg( QString( "measured %1 in %2" ).arg( area ).arg( QgsUnitTypes::toString( units ) ) ); // should always be in Meters Squared QGSCOMPARENEAR( area, 37416879192.9, 0.1 ); QCOMPARE( units, QgsUnitTypes::AreaSquareMeters ); // test converting the resultant area area = da.convertAreaMeasurement( area, QgsUnitTypes::AreaSquareMiles ); QGSCOMPARENEAR( area, 14446.7378, 0.001 ); // now try with a source CRS which is in feet ring.clear(); ring << QgsPoint( 1850000, 4423000 ) << QgsPoint( 1851000, 4423000 ) << QgsPoint( 1851000, 4424000 ) << QgsPoint( 1852000, 4424000 ) << QgsPoint( 1852000, 4425000 ) << QgsPoint( 1851000, 4425000 ) << QgsPoint( 1850000, 4423000 ); poly.clear(); poly << ring; polygon = QgsGeometry::fromPolygon( poly ); da.setSourceCrs( 27469 ); da.setEllipsoidalMode( false ); // measurement should be in square feet area = da.measureArea( &polygon ); units = da.areaUnits(); QgsDebugMsg( QString( "measured %1 in %2" ).arg( area ).arg( QgsUnitTypes::toString( units ) ) ); QGSCOMPARENEAR( area, 2000000, 0.001 ); QCOMPARE( units, QgsUnitTypes::AreaSquareFeet ); // test converting the resultant area area = da.convertAreaMeasurement( area, QgsUnitTypes::AreaSquareYards ); QGSCOMPARENEAR( area, 222222.2222, 0.001 ); da.setEllipsoidalMode( true ); // now should be in Square Meters again area = da.measureArea( &polygon ); units = da.areaUnits(); QgsDebugMsg( QString( "measured %1 in %2" ).arg( area ).arg( QgsUnitTypes::toString( units ) ) ); QGSCOMPARENEAR( area, 184149.37, 1.0 ); QCOMPARE( units, QgsUnitTypes::AreaSquareMeters ); // test converting the resultant area area = da.convertAreaMeasurement( area, QgsUnitTypes::AreaSquareYards ); QgsDebugMsg( QString( "measured %1 in sq yrds" ).arg( area ) ); QGSCOMPARENEAR( area, 220240.8172549, 0.00001 ); }