Profile request

This commit is contained in:
Nyall Dawson 2022-03-18 11:53:34 +10:00
parent 98dbcc3c94
commit 0a6dac826f
7 changed files with 495 additions and 0 deletions

View File

@ -0,0 +1,131 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/elevation/qgsprofilerequest.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsProfileRequest
{
%Docstring(signature="appended")
Encapsulates properties and constraints relating to fetching elevation profiles from different sources.
.. versionadded:: 3.26
%End
%TypeHeaderCode
#include "qgsprofilerequest.h"
%End
public:
QgsProfileRequest( QgsCurve *curve /Transfer/ );
%Docstring
Constructor for QgsProfileRequest.
The ``curve`` argument specifies the line along which the profile should be generated. Ownership is transferred
to the request.
%End
QgsProfileRequest( const QgsProfileRequest &other );
%Docstring
Copy constructor.
%End
~QgsProfileRequest();
bool operator==( const QgsProfileRequest &other ) const;
bool operator!=( const QgsProfileRequest &other ) const;
QgsProfileRequest &setProfileCurve( QgsCurve *curve /Transfer/ );
%Docstring
Sets the cross section profile ``curve``, which represents the line along which the profile should be generated.
Ownership of ``curve`` is transferred to the request.
The coordinate reference system of the ``curve`` is set via :py:func:`~QgsProfileRequest.setCrs`.
.. seealso:: :py:func:`profileCurve`
%End
QgsCurve *profileCurve();
%Docstring
Returns the cross section profile curve, which represents the line along which the profile should be generated.
The coordinate reference system of the curve is retrieved via :py:func:`~QgsProfileRequest.crs`.
.. seealso:: :py:func:`setProfileCurve`
%End
QgsProfileRequest &setCrs( const QgsCoordinateReferenceSystem &crs );
%Docstring
Sets the desired Coordinate Reference System (``crs``) for the profile.
This also represents the CRS associated with the :py:func:`~QgsProfileRequest.profileCurve`.
.. seealso:: :py:func:`crs`
%End
QgsCoordinateReferenceSystem crs() const;
%Docstring
Returns the desired Coordinate Reference System for the profile.
This also represents the CRS associated with the :py:func:`~QgsProfileRequest.profileCurve`.
.. seealso:: :py:func:`setCrs`
%End
QgsCoordinateTransformContext transformContext() const;
%Docstring
Returns the transform context, for use when transforming coordinates from a source
to the request's :py:func:`~QgsProfileRequest.crs`
.. seealso:: :py:func:`setTransformContext`
%End
QgsProfileRequest &setTransformContext( const QgsCoordinateTransformContext &context );
%Docstring
Sets the transform ``context``, for use when transforming coordinates from a source
to the request's :py:func:`~QgsProfileRequest.crs`
.. seealso:: :py:func:`transformContext`
%End
QgsProfileRequest &setTolerance( double tolerance );
%Docstring
Sets the tolerance of the request (in :py:func:`~QgsProfileRequest.crs` units).
This value determines how far from the :py:func:`~QgsProfileRequest.profileCurve` is appropriate for inclusion of results. For instance,
when a profile is generated for a point vector layer this tolerance distance will dictate how far from the
actual profile curve a point can reside within to be included in the results. Other sources may completely
ignore this tolerance if it is not appropriate for the particular source.
.. seealso:: :py:func:`tolerance`
%End
double tolerance() const;
%Docstring
Returns the tolerance of the request (in :py:func:`~QgsProfileRequest.crs` units).
This value determines how far from the :py:func:`~QgsProfileRequest.profileCurve` is appropriate for inclusion of results. For instance,
when a profile is generated for a point vector layer this tolerance distance will dictate how far from the
actual profile curve a point can reside within to be included in the results. Other sources may completely
ignore this tolerance if it is not appropriate for the particular source.
.. seealso:: :py:func:`setTolerance`
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/elevation/qgsprofilerequest.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -268,6 +268,7 @@
%Include auto_generated/editform/qgsattributeeditorrelation.sip
%Include auto_generated/editform/qgsattributeeditorhtmlelement.sip
%Include auto_generated/editform/qgsattributeeditorqmlelement.sip
%Include auto_generated/elevation/qgsprofilerequest.sip
%Include auto_generated/elevation/qgsterrainprovider.sip
%Include auto_generated/externalstorage/qgsexternalstorage.sip
%Include auto_generated/externalstorage/qgsexternalstorageregistry.sip

View File

@ -44,6 +44,7 @@ set(QGIS_CORE_SRCS
classification/qgsclassificationstandarddeviation.cpp
classification/qgsclassificationlogarithmic.cpp
elevation/qgsprofilerequest.cpp
elevation/qgsterrainprovider.cpp
geocoding/qgsabstractgeocoderlocatorfilter.cpp
@ -1260,6 +1261,7 @@ set(QGIS_CORE_HDRS
editform/qgsattributeeditorhtmlelement.h
editform/qgsattributeeditorqmlelement.h
elevation/qgsprofilerequest.h
elevation/qgsterrainprovider.h
externalstorage/qgsexternalstorage.h

View File

@ -0,0 +1,110 @@
/***************************************************************************
qgsprofilerequest.cpp
---------------
begin : February 2022
copyright : (C) 2022 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 "qgsprofilerequest.h"
#include "qgscurve.h"
QgsProfileRequest::QgsProfileRequest( QgsCurve *curve )
: mCurve( curve )
{
}
QgsProfileRequest::~QgsProfileRequest() = default;
QgsProfileRequest::QgsProfileRequest( const QgsProfileRequest &other )
: mCurve( other.mCurve ? other.mCurve->clone() : nullptr )
, mCrs( other.mCrs )
, mTransformContext( other.mTransformContext )
, mTolerance( other.mTolerance )
{
}
QgsProfileRequest &QgsProfileRequest::operator=( const QgsProfileRequest &other )
{
mCurve.reset( other.mCurve ? other.mCurve->clone() : nullptr );
mCrs = other.mCrs;
mTransformContext = other.mTransformContext;
mTolerance = other.mTolerance;
return *this;
}
bool QgsProfileRequest::operator==( const QgsProfileRequest &other ) const
{
if ( !qgsDoubleNear( mTolerance, other.mTolerance )
|| mCrs != other.mCrs
|| !( mTransformContext == other.mTransformContext ) )
return false;
if ( ( !mCurve && other.mCurve )
|| ( mCurve && !other.mCurve ) )
{
return false;
}
else if ( mCurve && other.mCurve )
{
if ( !mCurve->equals( *other.mCurve ) )
return false;
}
return true;
}
bool QgsProfileRequest::operator!=( const QgsProfileRequest &other ) const
{
return !( *this == other );
}
QgsProfileRequest &QgsProfileRequest::setProfileCurve( QgsCurve *curve )
{
mCurve.reset( curve );
return *this;
}
QgsCurve *QgsProfileRequest::profileCurve()
{
return mCurve.get();
}
QgsProfileRequest &QgsProfileRequest::setCrs( const QgsCoordinateReferenceSystem &crs )
{
mCrs = crs;
return *this;
}
QgsCoordinateReferenceSystem QgsProfileRequest::crs() const
{
return mCrs;
}
QgsCoordinateTransformContext QgsProfileRequest::transformContext() const
{
return mTransformContext;
}
QgsProfileRequest &QgsProfileRequest::setTransformContext( const QgsCoordinateTransformContext &context )
{
mTransformContext = context;
return *this;
}
QgsProfileRequest &QgsProfileRequest::setTolerance( double tolerance )
{
mTolerance = tolerance;
return *this;
}

View File

@ -0,0 +1,149 @@
/***************************************************************************
qgsprofilerequest.h
---------------
begin : February 2022
copyright : (C) 2022 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 QGSPROFILEREQUEST_H
#define QGSPROFILEREQUEST_H
#include "qgis_core.h"
#include "qgscoordinatereferencesystem.h"
#include "qgscoordinatetransformcontext.h"
#include <memory>
class QgsCurve;
/**
* \brief Encapsulates properties and constraints relating to fetching elevation profiles from different sources.
*
* \ingroup core
* \since QGIS 3.26
*/
class CORE_EXPORT QgsProfileRequest
{
public:
/**
* Constructor for QgsProfileRequest.
*
* The \a curve argument specifies the line along which the profile should be generated. Ownership is transferred
* to the request.
*/
QgsProfileRequest( QgsCurve *curve SIP_TRANSFER );
/**
* Copy constructor.
*/
QgsProfileRequest( const QgsProfileRequest &other );
~QgsProfileRequest();
/**
* Assignment operator
*/
QgsProfileRequest &operator=( const QgsProfileRequest &other );
bool operator==( const QgsProfileRequest &other ) const;
bool operator!=( const QgsProfileRequest &other ) const;
/**
* Sets the cross section profile \a curve, which represents the line along which the profile should be generated.
*
* Ownership of \a curve is transferred to the request.
*
* The coordinate reference system of the \a curve is set via setCrs().
*
* \see profileCurve()
*/
QgsProfileRequest &setProfileCurve( QgsCurve *curve SIP_TRANSFER );
/**
* Returns the cross section profile curve, which represents the line along which the profile should be generated.
*
* The coordinate reference system of the curve is retrieved via crs().
*
* \see setProfileCurve()
*/
QgsCurve *profileCurve();
/**
* Sets the desired Coordinate Reference System (\a crs) for the profile.
*
* This also represents the CRS associated with the profileCurve().
*
* \see crs()
*/
QgsProfileRequest &setCrs( const QgsCoordinateReferenceSystem &crs );
/**
* Returns the desired Coordinate Reference System for the profile.
*
* This also represents the CRS associated with the profileCurve().
*
* \see setCrs()
*/
QgsCoordinateReferenceSystem crs() const;
/**
* Returns the transform context, for use when transforming coordinates from a source
* to the request's crs()
*
* \see setTransformContext()
*/
QgsCoordinateTransformContext transformContext() const;
/**
* Sets the transform \a context, for use when transforming coordinates from a source
* to the request's crs()
*
* \see transformContext()
*/
QgsProfileRequest &setTransformContext( const QgsCoordinateTransformContext &context );
/**
* Sets the tolerance of the request (in crs() units).
*
* This value determines how far from the profileCurve() is appropriate for inclusion of results. For instance,
* when a profile is generated for a point vector layer this tolerance distance will dictate how far from the
* actual profile curve a point can reside within to be included in the results. Other sources may completely
* ignore this tolerance if it is not appropriate for the particular source.
*
* \see tolerance()
*/
QgsProfileRequest &setTolerance( double tolerance );
/**
* Returns the tolerance of the request (in crs() units).
*
* This value determines how far from the profileCurve() is appropriate for inclusion of results. For instance,
* when a profile is generated for a point vector layer this tolerance distance will dictate how far from the
* actual profile curve a point can reside within to be included in the results. Other sources may completely
* ignore this tolerance if it is not appropriate for the particular source.
*
* \see setTolerance()
*/
double tolerance() const { return mTolerance; }
private:
std::unique_ptr< QgsCurve> mCurve;
QgsCoordinateReferenceSystem mCrs;
QgsCoordinateTransformContext mTransformContext;
double mTolerance = 0;
};
#endif // QGSPROFILEREQUEST_H

View File

@ -253,6 +253,7 @@ ADD_PYTHON_TEST(PyQgsProcessingAlgDecorator test_processing_alg_decorator.py)
ADD_PYTHON_TEST(PyQgsProcessingBatch test_qgsprocessingbatch.py)
ADD_PYTHON_TEST(PyQgsProcessingParameters test_qgsprocessingparameters.py)
ADD_PYTHON_TEST(PyQgsProcessingUtils test_qgsprocessingutils.py)
ADD_PYTHON_TEST(PyQgsProfileRequest test_qgsprofilerequest.py)
ADD_PYTHON_TEST(PyQgsProjectionSelectionWidgets test_qgsprojectionselectionwidgets.py)
ADD_PYTHON_TEST(PyQgsProjectElevationProperties test_qgsprojectelevationproperties.py)
ADD_PYTHON_TEST(PyQgsProjectMetadata test_qgsprojectmetadata.py)

View File

@ -0,0 +1,101 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsProfileRequest
.. 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/03/2022'
__copyright__ = 'Copyright 2022, The QGIS Project'
import os
import qgis # NOQA
from qgis.PyQt.QtCore import QTemporaryDir
from qgis.core import (
QgsLineString,
QgsProfileRequest,
QgsCoordinateReferenceSystem,
QgsCoordinateTransformContext
)
from qgis.PyQt.QtXml import QDomDocument
from qgis.testing import start_app, unittest
from utilities import unitTestDataPath
start_app()
class TestQgsProfileRequest(unittest.TestCase):
def testBasic(self):
req = QgsProfileRequest(QgsLineString([[1, 2], [3, 4]]))
self.assertEqual(req.profileCurve().asWkt(), 'LineString (1 2, 3 4)')
req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')).setTolerance(5)
self.assertEqual(req.crs().authid(), 'EPSG:3857')
self.assertEqual(req.tolerance(), 5)
proj_string = '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1'
transform_context = QgsCoordinateTransformContext()
transform_context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'),
QgsCoordinateReferenceSystem('EPSG:4283'), proj_string)
req.setTransformContext(transform_context)
self.assertEqual(req.transformContext().calculateCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'),
QgsCoordinateReferenceSystem('EPSG:4283')), proj_string)
copy = QgsProfileRequest(req)
self.assertEqual(copy.profileCurve().asWkt(), 'LineString (1 2, 3 4)')
self.assertEqual(copy.crs().authid(), 'EPSG:3857')
self.assertEqual(copy.tolerance(), 5)
self.assertEqual(copy.transformContext().calculateCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'),
QgsCoordinateReferenceSystem('EPSG:4283')), proj_string)
def testEquality(self):
"""
Test equality operator
"""
req = QgsProfileRequest(None)
req2 = QgsProfileRequest(None)
self.assertEqual(req, req2)
req.setProfileCurve(QgsLineString([[1, 2], [3, 4]]))
self.assertNotEqual(req, req2)
req2.setProfileCurve(QgsLineString([[1, 2], [3, 5]]))
self.assertNotEqual(req, req2)
req.setProfileCurve(None)
self.assertNotEqual(req, req2)
req.setProfileCurve(QgsLineString([[1, 2], [3, 5]]))
self.assertEqual(req, req2)
req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857'))
self.assertNotEqual(req, req2)
req2.setCrs(QgsCoordinateReferenceSystem('EPSG:3857'))
self.assertEqual(req, req2)
proj_string = '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1'
transform_context = QgsCoordinateTransformContext()
transform_context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'),
QgsCoordinateReferenceSystem('EPSG:4283'), proj_string)
req.setTransformContext(transform_context)
self.assertNotEqual(req, req2)
req2.setTransformContext(transform_context)
self.assertEqual(req, req2)
req.setTolerance(5)
self.assertNotEqual(req, req2)
req2.setTolerance(5)
self.assertEqual(req, req2)
if __name__ == '__main__':
unittest.main()