Skip to content

Commit

Permalink
Use correct geodesic distance and area representation when measuring
Browse files Browse the repository at this point in the history
Ref: e2ec3e4674bd534d8d5af0c52f7278b1d6413348
  • Loading branch information
manisandro committed Jun 14, 2017
1 parent c12e4d8 commit df64318
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 27 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ IF(NOT ENABLE_QT5)
FIND_PACKAGE(QJSON REQUIRED)
ENDIF(NOT ENABLE_QT5)
FIND_PACKAGE(QuaZip REQUIRED)
FIND_PACKAGE(GeographicLib REQUIRED)

IF (WITH_INTERNAL_QEXTSERIALPORT)
SET(QEXTSERIALPORT_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/src/core/gps/qextserialport)
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgsmeasuretoolv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ QgsMeasureToolV2::QgsMeasureToolV2( QgsMapCanvas *canvas, MeasureMode measureMod
}
else
{
mDrawTool = new QgsMapToolDrawPolyLine( canvas, mMeasureMode == MeasurePolygon );
mDrawTool = new QgsMapToolDrawPolyLine( canvas, mMeasureMode == MeasurePolygon, true );
}
mDrawTool->setParent( this );
mDrawTool->setAllowMultipart( mMeasureMode != MeasureAngle && mMeasureMode != MeasureAzimuth );
Expand Down
2 changes: 2 additions & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,7 @@ INCLUDE_DIRECTORIES(${QSCINTILLA_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${GEOS_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${GDAL_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${EXIV2_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${GeographicLib_INCLUDE_DIR})

IF (WIN32)
IF (MSVC)
Expand Down Expand Up @@ -657,6 +658,7 @@ TARGET_LINK_LIBRARIES(qgis_gui
${QJSON_LIBRARIES}
${qjson_LIBRARIES}
${QUAZIP_LIBRARIES}
${GeographicLib_LIBRARIES}
)

IF(WIN32)
Expand Down
24 changes: 20 additions & 4 deletions src/gui/qgsgeometryrubberband.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,10 @@ void QgsGeometryRubberBand::paint( QPainter* painter )
QgsPointV2 vertex;
while ( paintGeom->nextVertex( vertexId, vertex ) )
{
drawVertex( painter, vertex.x(), vertex.y() );
if ( !mHiddenNodes.contains( vertexId ) )
{
drawVertex( painter, vertex.x(), vertex.y() );
}
}

delete paintGeom;
Expand Down Expand Up @@ -185,8 +188,9 @@ void QgsGeometryRubberBand::redrawMeasurements()
}
}

void QgsGeometryRubberBand::setGeometry( QgsAbstractGeometryV2* geom )
void QgsGeometryRubberBand::setGeometry( QgsAbstractGeometryV2* geom , const QList<QgsVertexId> &hiddenNodes )
{
mHiddenNodes.clear();
delete mGeometry;
mGeometry = geom;
qDeleteAll( mMeasurementLabels );
Expand All @@ -198,6 +202,7 @@ void QgsGeometryRubberBand::setGeometry( QgsAbstractGeometryV2* geom )
setRect( QgsRectangle() );
return;
}
mHiddenNodes = hiddenNodes;

setRect( rubberBandRectangle() );

Expand Down Expand Up @@ -396,16 +401,27 @@ void QgsGeometryRubberBand::measureGeometry( QgsAbstractGeometryV2 *geometry, in
case MEASURE_LINE_AND_SEGMENTS:
if ( dynamic_cast<QgsCurveV2*>( geometry ) )
{
QgsVertexId vid;
QgsPointV2 p;
QList<QgsPointV2> points;
static_cast<QgsCurveV2*>( geometry )->points( points );
while ( geometry->nextVertex( vid, p ) )
{
if ( !mHiddenNodes.contains( vid ) )
{
points.append( p );
}
}
double totLength = 0;
for ( int i = 0, n = points.size() - 1; i < n; ++i )
{
QgsPoint p1( points[i].x(), points[i].y() );
QgsPoint p2( points[i+1].x(), points[i+1].y() );
double segmentLength = mDa.measureLine( p1, p2 );
totLength += segmentLength;
addMeasurements( QStringList() << formatMeasurement( segmentLength, false ), QgsPointV2( 0.5 * ( p1.x() + p2.x() ), 0.5 * ( p1.y() + p2.y() ) ) );
if ( n > 1 )
{
addMeasurements( QStringList() << formatMeasurement( segmentLength, false ), QgsPointV2( 0.5 * ( p1.x() + p2.x() ), 0.5 * ( p1.y() + p2.y() ) ) );
}
}
if ( !points.isEmpty() )
{
Expand Down
5 changes: 3 additions & 2 deletions src/gui/qgsgeometryrubberband.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@
#ifndef QGSGEOMETRYRUBBERBAND_H
#define QGSGEOMETRYRUBBERBAND_H

#include "qgsabstractgeometryv2.h"
#include "qgsmapcanvasitem.h"
#include "qgsdistancearea.h"
#include <QBrush>
#include <QPen>


class QgsAbstractGeometryV2;
class QgsPointV2;
struct QgsVertexId;

Expand Down Expand Up @@ -91,7 +91,7 @@ class GUI_EXPORT QgsGeometryRubberBand: public QObject, public QgsMapCanvasItem
~QgsGeometryRubberBand();

/** Sets geometry (takes ownership). Geometry is expected to be in map coordinates */
void setGeometry( QgsAbstractGeometryV2* geom );
void setGeometry( QgsAbstractGeometryV2* geom, const QList<QgsVertexId>& hiddenNodes = QList<QgsVertexId>() );
const QgsAbstractGeometryV2* geometry() { return mGeometry; }

/** Sets the translation offset (offset in map coordinates for drawing geometry) */
Expand Down Expand Up @@ -142,6 +142,7 @@ class GUI_EXPORT QgsGeometryRubberBand: public QObject, public QgsMapCanvasItem

private:
QgsAbstractGeometryV2* mGeometry;
QList<QgsVertexId> mHiddenNodes;
double mTranslationOffset[2];
QBrush mBrush;
QPen mPen;
Expand Down
107 changes: 94 additions & 13 deletions src/gui/qgsmaptooldrawshape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
#include <QMouseEvent>
#include <qmath.h>

#include <GeographicLib/Geodesic.hpp>
#include <GeographicLib/GeodesicLine.hpp>
#include <GeographicLib/Constants.hpp>

QgsMapToolDrawShape::QgsMapToolDrawShape( QgsMapCanvas *canvas, bool isArea, State *initialState )
: QgsMapTool( canvas )
, mIsArea( isArea )
Expand Down Expand Up @@ -127,7 +131,9 @@ void QgsMapToolDrawShape::setMeasurementMode( QgsGeometryRubberBand::Measurement

void QgsMapToolDrawShape::update()
{
mRubberBand->setGeometry( createGeometry( mCanvas->mapSettings().destinationCrs() ) );
QList<QgsVertexId> hiddenNodes;
QgsAbstractGeometryV2* geom = createGeometry( mCanvas->mapSettings().destinationCrs(), &hiddenNodes );
mRubberBand->setGeometry( geom, hiddenNodes );
emit geometryChanged();
}

Expand Down Expand Up @@ -405,7 +411,7 @@ void QgsMapToolDrawPoint::buttonEvent( const QgsPoint& pos, bool press, Qt::Mous
}
}

QgsAbstractGeometryV2* QgsMapToolDrawPoint::createGeometry( const QgsCoordinateReferenceSystem &targetCrs ) const
QgsAbstractGeometryV2* QgsMapToolDrawPoint::createGeometry( const QgsCoordinateReferenceSystem &targetCrs , QList<QgsVertexId> */*hiddenNodes*/ ) const
{
const QgsCoordinateTransform* t = QgsCoordinateTransformCache::instance()->transform( canvas()->mapSettings().destinationCrs().authid(), targetCrs.authid() );
QgsGeometryCollectionV2* multiGeom = new QgsMultiPointV2();
Expand Down Expand Up @@ -539,9 +545,15 @@ void QgsMapToolDrawPoint::setPart( int part, const QgsPoint& p )

///////////////////////////////////////////////////////////////////////////////

QgsMapToolDrawPolyLine::QgsMapToolDrawPolyLine( QgsMapCanvas *canvas, bool closed )
: QgsMapToolDrawShape( canvas, closed, emptyState() )
QgsMapToolDrawPolyLine::QgsMapToolDrawPolyLine( QgsMapCanvas *canvas, bool closed, bool geodesic )
: QgsMapToolDrawShape( canvas, closed, emptyState() ), mGeodesic( geodesic )
{
if ( geodesic )
{
mDa.setEllipsoid( "WGS84" );
mDa.setEllipsoidalMode( true );
mDa.setSourceCrs( QgsCRSCache::instance()->crsByAuthId( "EPSG:4326" ) );
}
}

QgsMapToolDrawShape::State* QgsMapToolDrawPolyLine::emptyState() const
Expand All @@ -567,7 +579,7 @@ void QgsMapToolDrawPolyLine::buttonEvent( const QgsPoint& pos, bool press, Qt::M
}
else if ( !press && button == Qt::RightButton )
{
if ( !mIsArea && state()->points.back().size() >= 2 )
if (( mIsArea && state()->points.back().size() >= 3 ) || state()->points.back().size() >= 2 )
{
State* newState = cloneState();
// If last two points are very close, discard last point
Expand Down Expand Up @@ -599,20 +611,89 @@ void QgsMapToolDrawPolyLine::moveEvent( const QgsPoint &pos )
update();
}

QgsAbstractGeometryV2* QgsMapToolDrawPolyLine::createGeometry( const QgsCoordinateReferenceSystem &targetCrs ) const
QgsAbstractGeometryV2* QgsMapToolDrawPolyLine::createGeometry( const QgsCoordinateReferenceSystem &targetCrs , QList<QgsVertexId> *hiddenNodes ) const
{
const QgsCoordinateTransform* t = QgsCoordinateTransformCache::instance()->transform( canvas()->mapSettings().destinationCrs().authid(), targetCrs.authid() );
QgsGeometryCollectionV2* multiGeom = mIsArea ? static_cast<QgsGeometryCollectionV2*>( new QgsMultiPolygonV2() ) : static_cast<QgsGeometryCollectionV2*>( new QgsMultiLineStringV2() );
foreach ( const QList<QgsPoint>& part, state()->points )
for ( int iPart = 0, nParts = state()->points.size(); iPart < nParts; ++iPart )
{
const QList<QgsPoint>& part = state()->points[iPart];
QgsLineStringV2* ring = new QgsLineStringV2();
foreach ( const QgsPoint& point, part )
if ( mGeodesic )
{
ring->addVertex( QgsPointV2( t->transform( point ) ) );
int nPoints = part.size();
if ( nPoints < 2 )
{
continue;
}
const QgsCoordinateTransform* t1 = QgsCoordinateTransformCache::instance()->transform( canvas()->mapSettings().destinationCrs().authid(), "EPSG:4326" );
const QgsCoordinateTransform* t2 = QgsCoordinateTransformCache::instance()->transform( "EPSG:4326", targetCrs.authid() );
QList<QgsPoint> wgsPoints;

GeographicLib::Geodesic geod( GeographicLib::Constants::WGS84_a(), GeographicLib::Constants::WGS84_f() );

foreach ( const QgsPoint& point, part )
{
wgsPoints.append( t1->transform( point ) );
}

double sdist = 500000; // 500km segments
for ( int i = 0; i < nPoints - 1; ++i )
{
int ringSize = ring->vertexCount();
GeographicLib::GeodesicLine line = geod.InverseLine( wgsPoints[i].y(), wgsPoints[i].x(), wgsPoints[i+1].y(), wgsPoints[i+1].x() );
double dist = line.Distance();
int nIntervals = qMax( 1, int( std::ceil( dist / sdist ) ) );
for ( int j = 0; j < nIntervals; ++j )
{
double lat, lon;
line.Position( j * sdist, lat, lon );
ring->addVertex( QgsPointV2( t2->transform( QgsPoint( lon, lat ) ) ) );
if ( hiddenNodes && j != 0 )
{
hiddenNodes->append( QgsVertexId( iPart, 0, ringSize + j ) );
}
}
if ( !mIsArea && i == nPoints - 2 )
{
double lat, lon;
line.Position( dist, lat, lon );
ring->addVertex( QgsPointV2( t2->transform( QgsPoint( lon, lat ) ) ) );
}
}
if ( mIsArea && !part.isEmpty() )
{
GeographicLib::GeodesicLine line = geod.InverseLine( wgsPoints[nPoints -1].y(), wgsPoints[nPoints -1].x(), wgsPoints[0].y(), wgsPoints[0].x() );
double dist = line.Distance();
int nIntervals = qMax( 1, int( std::ceil( dist / sdist ) ) );
int ringSize = ring->vertexCount();
for ( int j = 0; j < nIntervals; ++j )
{
double lat, lon;
line.Position( j * sdist, lat, lon );
ring->addVertex( QgsPointV2( t2->transform( QgsPoint( lon, lat ) ) ) );
if ( hiddenNodes && j != 0 )
{
hiddenNodes->append( QgsVertexId( iPart, 0, ringSize + j ) );
}
}
ring->addVertex( ring->vertexAt( QgsVertexId( 0, 0, 0 ) ) );
}
}
else
{
foreach ( const QgsPoint& point, part )
{
ring->addVertex( QgsPointV2( t->transform( point ) ) );
}
if ( mIsArea && !part.isEmpty() )
{
ring->addVertex( QgsPointV2( t->transform( part.front() ) ) );
}
}

if ( mIsArea )
{
if ( !part.isEmpty() ) ring->addVertex( QgsPointV2( t->transform( part.front() ) ) );
QgsPolygonV2* poly = new QgsPolygonV2;
poly->setExteriorRing( ring );
multiGeom->addGeometry( poly );
Expand Down Expand Up @@ -951,7 +1032,7 @@ void QgsMapToolDrawRectangle::moveEvent( const QgsPoint &pos )
update();
}

QgsAbstractGeometryV2* QgsMapToolDrawRectangle::createGeometry( const QgsCoordinateReferenceSystem &targetCrs ) const
QgsAbstractGeometryV2* QgsMapToolDrawRectangle::createGeometry( const QgsCoordinateReferenceSystem &targetCrs , QList<QgsVertexId> */*hiddenNodes*/ ) const
{
const QgsCoordinateTransform* t = QgsCoordinateTransformCache::instance()->transform( canvas()->mapSettings().destinationCrs().authid(), targetCrs.authid() );
QgsGeometryCollectionV2* multiGeom = new QgsMultiPolygonV2;
Expand Down Expand Up @@ -1225,7 +1306,7 @@ void QgsMapToolDrawCircle::getPart( int part, QgsPoint &center, double &radius )
radius = qSqrt( state()->centers[part].sqrDist( state()->ringPos[part] ) );
}

QgsAbstractGeometryV2* QgsMapToolDrawCircle::createGeometry( const QgsCoordinateReferenceSystem &targetCrs ) const
QgsAbstractGeometryV2* QgsMapToolDrawCircle::createGeometry( const QgsCoordinateReferenceSystem &targetCrs , QList<QgsVertexId> */*hiddenNodes*/ ) const
{
mPartMap.clear();
QgsGeometryCollectionV2* multiGeom = new QgsMultiPolygonV2();
Expand Down Expand Up @@ -1656,7 +1737,7 @@ void QgsMapToolDrawCircularSector::moveEvent( const QgsPoint &pos )
update();
}

QgsAbstractGeometryV2* QgsMapToolDrawCircularSector::createGeometry( const QgsCoordinateReferenceSystem &targetCrs ) const
QgsAbstractGeometryV2* QgsMapToolDrawCircularSector::createGeometry( const QgsCoordinateReferenceSystem &targetCrs , QList<QgsVertexId> */*hiddenNodes*/ ) const
{
const QgsCoordinateTransform* t = QgsCoordinateTransformCache::instance()->transform( canvas()->mapSettings().destinationCrs().authid(), targetCrs.authid() );
QgsGeometryCollectionV2* multiGeom = new QgsMultiPolygonV2;
Expand Down
16 changes: 9 additions & 7 deletions src/gui/qgsmaptooldrawshape.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class GUI_EXPORT QgsMapToolDrawShape : public QgsMapTool
void canvasReleaseEvent( QMouseEvent* e ) override;
void keyReleaseEvent( QKeyEvent *e ) override;
virtual int getPartCount() const = 0;
virtual QgsAbstractGeometryV2* createGeometry( const QgsCoordinateReferenceSystem& targetCrs ) const = 0;
virtual QgsAbstractGeometryV2* createGeometry( const QgsCoordinateReferenceSystem& targetCrs, QList<QgsVertexId>* hiddenNodes = 0 ) const = 0;
void addGeometry( const QgsAbstractGeometryV2* geometry, const QgsCoordinateReferenceSystem& sourceCrs );

virtual void updateStyle( int outlineWidth, const QColor& outlineColor, const QColor& fillColor, Qt::PenStyle lineStyle, Qt::BrushStyle brushStyle );
Expand Down Expand Up @@ -132,7 +132,7 @@ class GUI_EXPORT QgsMapToolDrawPoint : public QgsMapToolDrawShape
int getPartCount() const override { return state()->points.size(); }
void getPart( int part, QgsPoint& p ) const { p = state()->points[part].front(); }
void setPart( int part, const QgsPoint& p );
QgsAbstractGeometryV2* createGeometry( const QgsCoordinateReferenceSystem& targetCrs ) const override;
QgsAbstractGeometryV2* createGeometry( const QgsCoordinateReferenceSystem& targetCrs, QList<QgsVertexId>* hiddenNodes = 0 ) const override;

protected:
struct State : QgsMapToolDrawShape::State
Expand Down Expand Up @@ -169,11 +169,11 @@ class GUI_EXPORT QgsMapToolDrawPolyLine : public QgsMapToolDrawShape
{
Q_OBJECT
public:
QgsMapToolDrawPolyLine( QgsMapCanvas* canvas, bool closed );
QgsMapToolDrawPolyLine( QgsMapCanvas* canvas, bool closed, bool geodesic = false );
int getPartCount() const override { return state()->points.size(); }
void getPart( int part, QList<QgsPoint>& p ) const { p = state()->points[part]; }
void setPart( int part, const QList<QgsPoint>& p );
QgsAbstractGeometryV2* createGeometry( const QgsCoordinateReferenceSystem& targetCrs ) const override;
QgsAbstractGeometryV2* createGeometry( const QgsCoordinateReferenceSystem& targetCrs, QList<QgsVertexId>* hiddenNodes = 0 ) const override;

protected:
struct State : QgsMapToolDrawShape::State
Expand All @@ -186,6 +186,8 @@ class GUI_EXPORT QgsMapToolDrawPolyLine : public QgsMapToolDrawShape
int node;
};

bool mGeodesic;
QgsDistanceArea mDa;
QPointer<QgsMapToolDrawShapeInputField> mXEdit;
QPointer<QgsMapToolDrawShapeInputField> mYEdit;

Expand Down Expand Up @@ -225,7 +227,7 @@ class GUI_EXPORT QgsMapToolDrawRectangle : public QgsMapToolDrawShape
p2 = state()->p2[part];
}
void setPart( int part, const QgsPoint& p1, const QgsPoint& p2 );
QgsAbstractGeometryV2* createGeometry( const QgsCoordinateReferenceSystem& targetCrs ) const override;
QgsAbstractGeometryV2* createGeometry( const QgsCoordinateReferenceSystem& targetCrs, QList<QgsVertexId>* hiddenNodes = 0 ) const override;

protected:
struct State : QgsMapToolDrawShape::State
Expand Down Expand Up @@ -268,7 +270,7 @@ class GUI_EXPORT QgsMapToolDrawCircle : public QgsMapToolDrawShape
int getPartCount() const override { return state()->centers.size(); }
void getPart( int part, QgsPoint& center, double& radius ) const;
void setPart( int part, const QgsPoint& center, double radius );
QgsAbstractGeometryV2* createGeometry( const QgsCoordinateReferenceSystem& targetCrs ) const override;
QgsAbstractGeometryV2* createGeometry( const QgsCoordinateReferenceSystem& targetCrs, QList<QgsVertexId>* hiddenNodes = 0 ) const override;

protected:
struct State : QgsMapToolDrawShape::State
Expand Down Expand Up @@ -324,7 +326,7 @@ class GUI_EXPORT QgsMapToolDrawCircularSector : public QgsMapToolDrawShape
stopAngle = state()->stopAngles[part];
}
void setPart( int part, const QgsPoint& center, double radius, double startAngle, double stopAngle );
QgsAbstractGeometryV2* createGeometry( const QgsCoordinateReferenceSystem& targetCrs ) const override;
QgsAbstractGeometryV2* createGeometry( const QgsCoordinateReferenceSystem& targetCrs, QList<QgsVertexId>* hiddenNodes = 0 ) const override;

protected:
enum SectorStatus { HaveNothing, HaveCenter, HaveRadius };
Expand Down

0 comments on commit df64318

Please sign in to comment.