Skip to content
Permalink
Browse files

New class QgsBearingUtils with method to calculate true north

  • Loading branch information
nyalldawson committed Oct 18, 2016
1 parent 2835cad commit fb860fb618f785a929ba7ffc15797fdd7589cdc0
@@ -21,6 +21,7 @@
%Include qgsaggregatecalculator.sip
%Include qgsattributetableconfig.sip
%Include qgsattributeeditorelement.sip
%Include qgsbearingutils.sip
%Include qgsbrowsermodel.sip
%Include qgsclipper.sip
%Include qgscolorramp.sip
@@ -0,0 +1,21 @@
/**
* \class QgsBearingUtils
* \ingroup core
* Utilities for calculating bearings and directions.
* \note Added in version 2.18
*/
class QgsBearingUtils
{
%TypeHeaderCode
#include <qgsbearingutils.h>
%End
public:

/**
* Returns the direction to true north from a specified point and for a specified
* coordinate reference system. The returned value is in degrees clockwise from
* vertical. An exception will be thrown if the bearing could not be calculated.
*/
static double bearingTrueNorth( const QgsCoordinateReferenceSystem& crs,
const QgsPoint& point );
};
@@ -85,6 +85,7 @@ SET(QGIS_CORE_SRCS
qgsaggregatecalculator.cpp
qgsattributetableconfig.cpp
qgsattributeeditorelement.cpp
qgsbearingutils.cpp
qgsbrowsermodel.cpp
qgscachedfeatureiterator.cpp
qgscacheindex.cpp
@@ -600,6 +601,7 @@ SET(QGIS_CORE_HDRS
qgsannotation.h
qgsattributetableconfig.h
qgsattributeeditorelement.h
qgsbearingutils.h
qgscachedfeatureiterator.h
qgscacheindex.h
qgscacheindexfeatureid.h
@@ -0,0 +1,49 @@
/***************************************************************************
qgsbearingutils.cpp
-------------------
begin : October 2016
copyright : (C) 2016 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsbearingutils.h"
#include "qgscoordinatereferencesystem.h"
#include "qgspoint.h"
#include "qgscoordinatetransform.h"
#include "qgsexception.h"

double QgsBearingUtils::bearingTrueNorth( const QgsCoordinateReferenceSystem &crs, const QgsPoint &point )
{
// step 1 - transform point into WGS84 geographic crs
QgsCoordinateTransform transform( crs, QgsCoordinateReferenceSystem::fromEpsgId( 4326 ) );

if ( !transform.isValid() )
{
//raise
throw QgsException( QObject::tr( "Could not create transform to calculate true north" ) );
}

if ( transform.isShortCircuited() )
return 0.0;

QgsPoint p1 = transform.transform( point );

// shift point a tiny bit north
QgsPoint p2 = p1;
p2.setY( p2.y() + 0.000001 );

//transform back
QgsPoint p3 = transform.transform( p2, QgsCoordinateTransform::ReverseTransform );

// find bearing from point to p3
return point.azimuth( p3 );
}
@@ -0,0 +1,45 @@
/***************************************************************************
qgsbearingutils.h
-----------------
begin : October 2016
copyright : (C) 2016 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSBEARINGUTILS_H
#define QGSBEARINGUTILS_H

class QgsCoordinateReferenceSystem;
class QgsPoint;


/**
* \class QgsBearingUtils
* \ingroup core
* Utilities for calculating bearings and directions.
* \note Added in version 2.18
*/
class CORE_EXPORT QgsBearingUtils
{
public:

/**
* Returns the direction to true north from a specified point and for a specified
* coordinate reference system. The returned value is in degrees clockwise from
* vertical. An exception will be thrown if the bearing could not be calculated.
*/
static double bearingTrueNorth( const QgsCoordinateReferenceSystem& crs,
const QgsPoint& point );

};

#endif //QGSBEARINGUTILS_H
@@ -17,6 +17,7 @@ ADD_PYTHON_TEST(PyQgsAttributeFormEditorWidget test_qgsattributeformeditorwidget
ADD_PYTHON_TEST(PyQgsAttributeTableConfig test_qgsattributetableconfig.py)
ADD_PYTHON_TEST(PyQgsAttributeTableModel test_qgsattributetablemodel.py)
#ADD_PYTHON_TEST(PyQgsAuthenticationSystem test_qgsauthsystem.py)
ADD_PYTHON_TEST(PyQgsBearingUtils test_qgsbearingutils.py)
ADD_PYTHON_TEST(PyQgsBlendModes test_qgsblendmodes.py)
ADD_PYTHON_TEST(PyQgsCategorizedSymbolRenderer test_qgscategorizedsymbolrenderer.py)
ADD_PYTHON_TEST(PyQgsColorButton test_qgscolorbutton.py)
@@ -0,0 +1,59 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsBearingUtils.
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'Nyall Dawson'
__date__ = '18/10/2016'
__copyright__ = 'Copyright 2016, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

import qgis # switch sip api

from qgis.core import (QgsBearingUtils,
QgsCoordinateReferenceSystem,
QgsPoint
)

from qgis.testing import (start_app,
unittest
)


start_app()


class TestQgsBearingUtils(unittest.TestCase):

def testTrueNorth(self):
""" test calculating bearing to true north"""

# short circuit - already a geographic crs
crs = QgsCoordinateReferenceSystem.fromEpsgId(4326)
self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(0, 0)), 0)
self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(44, 0)), 0)
self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(44, -43)), 0)
self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(44, 43)), 0)

self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(44, 200)), 0)
self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(44, -200)), 0)

# no short circuit
crs = QgsCoordinateReferenceSystem.fromEpsgId(3111)
self.assertAlmostEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(2508807, 2423425)), 0.06, 2)

# try a south-up crs
crs = QgsCoordinateReferenceSystem.fromEpsgId(2053)
self.assertAlmostEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(29, -27.55)), -180.0, 1)

# try a north pole crs
crs = QgsCoordinateReferenceSystem.fromEpsgId(3575)
self.assertAlmostEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(-780770, 652329)), 129.9, 1)
self.assertAlmostEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(513480, 873173)), -149.5, 1)

if __name__ == '__main__':
unittest.main()

0 comments on commit fb860fb

Please sign in to comment.
You can’t perform that action at this time.