void TestQgsDistanceArea::collections()
{
  //test measuring for collections
  QgsDistanceArea myDa;
  myDa.setSourceAuthId( "EPSG:4030" );
  myDa.setEllipsoidalMode( true );
  myDa.setEllipsoid( "WGS84" );

  //collection of lines, should be sum of line length
  QgsGeometry lines( QgsGeometryFactory::geomFromWkt( "GeometryCollection( LineString(0 36.53, 5.76 -48.16), LineString(0 25.54, 24.20 36.70) )" ) );
  double result = myDa.measureLength( &lines );
  QGSCOMPARENEAR( result, 12006159, 1 );
  result = myDa.measureArea( &lines );
  QVERIFY( qgsDoubleNear( result, 0 ) );

  //collection of polygons
  QgsGeometry polys( QgsGeometryFactory::geomFromWkt( "GeometryCollection( Polygon((0 36.53, 5.76 -48.16, 0 25.54, 0 36.53)), Polygon((10 20, 15 20, 15 10, 10 20)) )" ) );
  result = myDa.measureArea( &polys );
  QGSCOMPARENEAR( result, 670434859475LL, 1 );
  result = myDa.measureLength( &polys );
  QVERIFY( qgsDoubleNear( result, 0 ) );

  //mixed collection
  QgsGeometry mixed( QgsGeometryFactory::geomFromWkt( "GeometryCollection( LineString(0 36.53, 5.76 -48.16), LineString(0 25.54, 24.20 36.70), Polygon((0 36.53, 5.76 -48.16, 0 25.54, 0 36.53)), Polygon((10 20, 15 20, 15 10, 10 20)) )" ) );
  //measure area specifically
  result = myDa.measureArea( &mixed );
  QGSCOMPARENEAR( result, 670434859475LL, 1 );
  //measure length
  result = myDa.measureLength( &mixed );
  QGSCOMPARENEAR( result, 12006159, 1 );
}
void TestQgsDistanceArea::regression13601()
{
    //test regression #13601
    QgsDistanceArea calc;
    calc.setEllipsoidalMode( true );
    calc.setEllipsoid( "NONE" );
    calc.setSourceCrs( 1108L );
    QgsGeometry geom( QgsGeometryFactory::geomFromWkt( "Polygon ((252000 1389000, 265000 1389000, 265000 1385000, 252000 1385000, 252000 1389000))" ) );
    QVERIFY( qgsDoubleNear( calc.measureArea( &geom ), 52000000, 0.0001 ) );
}
void TestQgsDistanceArea::regression14675()
{
  //test regression #14675
  QgsDistanceArea calc;
  calc.setEllipsoidalMode( true );
  calc.setEllipsoid( "GRS80" );
  calc.setSourceCrs( 145L );
  QgsGeometry geom( QgsGeometryFactory::geomFromWkt( "Polygon ((917593.5791854317067191 6833700.00807378999888897, 917596.43389983859378844 6833700.67099479306489229, 917599.53056440979707986 6833700.78673478215932846, 917593.5791854317067191 6833700.00807378999888897))" ) );
  //lots of tolerance here - the formulas get quite unstable with small areas due to division by very small floats
  QGSCOMPARENEAR( calc.measureArea( &geom ), 0.83301, 0.02 );
}
QList<double> QgsGeometryAnalyzer::simpleMeasure( QgsGeometry& mpGeometry )
{
  QList<double> list;
  double perim;
  if ( mpGeometry.wkbType() == QgsWkbTypes::Point )
  {
    QgsPoint pt = mpGeometry.asPoint();
    list.append( pt.x() );
    list.append( pt.y() );
  }
  else
  {
    QgsDistanceArea measure;
    list.append( measure.measureArea( mpGeometry ) );
    if ( mpGeometry.type() == QgsWkbTypes::PolygonGeometry )
    {
      perim = perimeterMeasure( mpGeometry, measure );
      list.append( perim );
    }
  }
  return list;
}
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()->readEntry( "Measure", "/Ellipsoid", GEO_NONE );
  QgsDistanceArea calc;
  calc.setEllipsoidalMode( mCanvas->hasCrsTransformEnabled() );
  calc.setEllipsoid( ellipsoid );
  calc.setSourceCrs( layer->crs().srsid() );

  QgsWKBTypes::Type wkbType = QgsWKBTypes::NoGeometry;
  QGis::GeometryType geometryType = QGis::NoGeometry;

  QgsVertexId vId;
  QgsPointV2 closestPoint;
  if ( feature->constGeometry() )
  {
    geometryType = feature->constGeometry()->type();
    wkbType = feature->constGeometry()->geometry()->wkbType();
    //find closest vertex to clicked point
    closestPoint = QgsGeometryUtils::closestVertex( *feature->constGeometry()->geometry(), QgsPointV2( layerPoint.x(), layerPoint.y() ), vId );
  }

  if ( QgsWKBTypes::isMultiType( wkbType ) )
  {
    QString str = QLocale::system().toString( static_cast<QgsGeometryCollectionV2*>( feature->constGeometry()->geometry() )->numGeometries() );
    derivedAttributes.insert( tr( "Parts" ), str );
    str = QLocale::system().toString( vId.part + 1 );
    derivedAttributes.insert( tr( "Part number" ), str );
  }

  if ( geometryType == QGis::Line )
  {
    const QgsPolyline &pline = feature->constGeometry()->asPolyline();
    double dist = calc.measureLength( feature->constGeometry() );
    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 );
    str = QLocale::system().toString( pline.size() );
    derivedAttributes.insert( tr( "Vertices" ), str );

    //add details of closest vertex to identify point
    closestVertexAttributes( *feature->constGeometry()->geometry(), vId, layer, derivedAttributes );

    if ( QgsWKBTypes::flatType( wkbType ) == QgsWKBTypes::LineString )
    {
      // Add the start and end points in as derived attributes
      QgsPoint pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, pline.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->mapSettings().layerToMapCoordinates( layer, pline.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.measureArea( feature->constGeometry() );
    double perimeter = calc.measurePerimeter( feature->constGeometry() );
    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 );

    str = QLocale::system().toString( feature->constGeometry()->geometry()->nCoordinates() );
    derivedAttributes.insert( tr( "Vertices" ), str );

    //add details of closest vertex to identify point
    closestVertexAttributes( *feature->constGeometry()->geometry(), vId, layer, derivedAttributes );
  }
  else if ( geometryType == QGis::Point &&
            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->constGeometry()->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 );

    if ( QgsWKBTypes::hasZ( wkbType ) )
    {
      str = QLocale::system().toString( static_cast<QgsPointV2*>( feature->constGeometry()->geometry() )->z(), 'g', 10 );
      derivedAttributes.insert( "Z", str );
    }
    if ( QgsWKBTypes::hasM( wkbType ) )
    {
      str = QLocale::system().toString( static_cast<QgsPointV2*>( feature->constGeometry()->geometry() )->m(), 'g', 10 );
      derivedAttributes.insert( "M", str );
    }
  }

  return derivedAttributes;
}
Exemple #6
0
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 );
}