Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Ensure 3d length is also shown in identify tool results for
multilinestringz geometries

Fixes #43930
  • Loading branch information
nyalldawson committed Jun 28, 2021
1 parent ea0c6e5 commit cce3a41
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 32 deletions.
72 changes: 40 additions & 32 deletions src/gui/qgsmaptoolidentify.cpp
Expand Up @@ -55,6 +55,7 @@
#include "qgspointcloudlayerrenderer.h"
#include "qgspointcloudlayerelevationproperties.h"
#include "qgssymbol.h"
#include "qgsmultilinestring.h"

#include <QMouseEvent>
#include <QCursor>
Expand Down Expand Up @@ -805,6 +806,8 @@ QMap< QString, QString > QgsMapToolIdentify::featureDerivedAttributes( const Qgs

if ( geometryType == QgsWkbTypes::LineGeometry )
{
const QgsAbstractGeometry *geom = feature.geometry().constGet();

double dist = calc.measureLength( feature.geometry() );
dist = calc.convertLengthMeasurement( dist, displayDistanceUnits() );
QString str;
Expand All @@ -813,45 +816,50 @@ QMap< QString, QString > QgsMapToolIdentify::featureDerivedAttributes( const Qgs
str = formatDistance( dist );
derivedAttributes.insert( tr( "Length (Ellipsoidal — %1)" ).arg( ellipsoid ), str );
}
str = formatDistance( feature.geometry().constGet()->length()

str = formatDistance( geom->length()
* QgsUnitTypes::fromUnitToUnitFactor( layer->crs().mapUnits(), cartesianDistanceUnits ), cartesianDistanceUnits );
if ( !QgsWkbTypes::hasZ( feature.geometry().wkbType() ) )
derivedAttributes.insert( tr( "Length (Cartesian)" ), str );
else
derivedAttributes.insert( tr( "Length (Cartesian — 2D)" ), str );
if ( QgsWkbTypes::hasZ( feature.geometry().wkbType() ) && QgsWkbTypes::flatType( feature.geometry().wkbType() ) == QgsWkbTypes::LineString )
if ( QgsWkbTypes::hasZ( geom->wkbType() )
&& QgsWkbTypes::flatType( QgsWkbTypes::singleType( geom->wkbType() ) ) == QgsWkbTypes::LineString )
{
str = formatDistance( qgsgeometry_cast< const QgsLineString * >( feature.geometry().constGet() )->length3D()
* QgsUnitTypes::fromUnitToUnitFactor( layer->crs().mapUnits(), cartesianDistanceUnits ), cartesianDistanceUnits );
// 3d linestring (or multiline)
derivedAttributes.insert( tr( "Length (Cartesian — 2D)" ), str );

double totalLength3d = std::accumulate( geom->const_parts_begin(), geom->const_parts_end(), 0.0, []( double total, const QgsAbstractGeometry * part )
{
return total + qgsgeometry_cast< const QgsLineString * >( part )->length3D();
} );

str = formatDistance( totalLength3d, cartesianDistanceUnits );
derivedAttributes.insert( tr( "Length (Cartesian — 3D)" ), str );
}
else
{
derivedAttributes.insert( tr( "Length (Cartesian)" ), str );
}

const QgsAbstractGeometry *geom = feature.geometry().constGet();
if ( geom )
str = QLocale().toString( geom->nCoordinates() );
derivedAttributes.insert( tr( "Vertices" ), str );
if ( !layerPoint.isEmpty() )
{
str = QLocale().toString( geom->nCoordinates() );
derivedAttributes.insert( tr( "Vertices" ), str );
if ( !layerPoint.isEmpty() )
{
//add details of closest vertex to identify point
closestVertexAttributes( *geom, vId, layer, derivedAttributes );
closestPointAttributes( *geom, layerPoint, derivedAttributes );
}
//add details of closest vertex to identify point
closestVertexAttributes( *geom, vId, layer, derivedAttributes );
closestPointAttributes( *geom, layerPoint, derivedAttributes );
}

if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( geom ) )
{
// Add the start and end points in as derived attributes
QgsPointXY pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPointXY( 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, QgsPointXY( 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 );
}
if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( geom ) )
{
// Add the start and end points in as derived attributes
QgsPointXY pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPointXY( 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, QgsPointXY( 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 )
Expand Down
32 changes: 32 additions & 0 deletions tests/src/app/testqgsmaptoolidentifyaction.cpp
Expand Up @@ -365,6 +365,38 @@ void TestQgsMapToolIdentifyAction::lengthCalculation()
derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Cartesian — 3D)" )];
length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
QGSCOMPARENEAR( length, 26948.827000, 0.1 );

// CircularString with Z (no length 3d for now, not supported by circular string API)
tempLayer = std::make_unique< QgsVectorLayer>( QStringLiteral( "CircularStringZ?crs=epsg:3111&field=pk:int&field=col1:double" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) );
QVERIFY( tempLayer->isValid() );
f1.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "CircularStringZ(2484588 2425722 10, 2483588 2429722 10, 2482767 2398853 1000)" ) ) );
tempLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 );
result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
QCOMPARE( result.length(), 1 );
derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Ellipsoidal — WGS84)" )];
length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
QGSCOMPARENEAR( length, 2.5880, 0.001 );
derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Cartesian)" )];
length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
QGSCOMPARENEAR( length, 288140.206, 0.1 );

// MultiLineString with Z
tempLayer = std::make_unique< QgsVectorLayer>( QStringLiteral( "MultiLineStringZ?crs=epsg:3111&field=pk:int&field=col1:double" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) );
QVERIFY( tempLayer->isValid() );
f1.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "MultiLineStringZ((2484588 2425722 10, 2482767 2398853 1000), (2494588 2435722 10, 2422767 2318853 1000))" ) ) );
tempLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 );
result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
QCOMPARE( result.length(), 1 );
derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Ellipsoidal — WGS84)" )];
length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
QGSCOMPARENEAR( length, 1.4740, 0.001 );
derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Cartesian — 2D)" )];
length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
QGSCOMPARENEAR( length, 164104.319, 0.1 );
derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Cartesian — 3D)" )];
length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
QGSCOMPARENEAR( length, 164126.083, 0.1 );

}

void TestQgsMapToolIdentifyAction::perimeterCalculation()
Expand Down

0 comments on commit cce3a41

Please sign in to comment.