mirror of
https://github.com/qgis/QGIS.git
synced 2025-11-22 00:14:55 -05:00
Make asGridified and newSameType (helper function)
This commit is contained in:
parent
99b1c74c4e
commit
3f5b11bffe
@ -71,6 +71,16 @@ class QgsAbstractGeometry
|
||||
virtual ~QgsAbstractGeometry();
|
||||
QgsAbstractGeometry( const QgsAbstractGeometry &geom );
|
||||
|
||||
virtual QgsAbstractGeometry *createEmptyWithSameType() const = 0 /Factory/;
|
||||
%Docstring
|
||||
Makes a new geometry with the same class and same WKB and transfers ownership.
|
||||
To create it, the geometry is default constructedand then the WKB is changed.
|
||||
:return: the new empty geometry. Callee takes ownership.
|
||||
.. seealso:: clone
|
||||
.. versionadded:: 3.0
|
||||
:rtype: QgsAbstractGeometry
|
||||
%End
|
||||
|
||||
virtual QgsAbstractGeometry *clone() const = 0 /Factory/;
|
||||
%Docstring
|
||||
Clones the geometry by performing a deep copy
|
||||
@ -402,6 +412,32 @@ Returns the centroid of the geometry
|
||||
:rtype: QgsAbstractGeometry
|
||||
%End
|
||||
|
||||
virtual QgsAbstractGeometry *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0, double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const = 0 /Factory/;
|
||||
%Docstring
|
||||
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
|
||||
It transfers ownership to the callee.
|
||||
If it couldn't make the gridified geometry it returns None.
|
||||
It may generate an invalid geometry (in some corner cases).
|
||||
It can also be thought as rounding the edges and it may be useful for removing errors.
|
||||
If the geometry is curved, it will be segmentized before gridifying it.
|
||||
Example:
|
||||
\code
|
||||
geometry->snappedToGrid(1, 1);
|
||||
\endcode
|
||||
In this case we use a 2D grid of 1x1 to gridify.
|
||||
In this case, it can be thought like rounding the x and y of all the points/vertices to full units (remove all decimals).
|
||||
\param hSpacing Horizontal spacing of the grid (x axis). 0 to disable.
|
||||
\param vSpacing Vertical spacing of the grid (y axis). 0 to disable.
|
||||
\param dSpacing Depth spacing of the grid (z axis). 0 (default) to disable.
|
||||
\param mSpacing Custom dimension spacing of the grid (m axis). 0 (default) to disable.
|
||||
\param tolerance In case of segmentation, the tolerance to use (passed to segmentize as is).
|
||||
\param toleranceType In case of segmentation, the toleranceType to use (passed to segmentize as is).
|
||||
:return: the segmentized geometry or None if it wasn't possible to make. Caller takes ownership.
|
||||
.. seealso:: segmentize
|
||||
.. versionadded:: 3.0
|
||||
:rtype: QgsAbstractGeometry
|
||||
%End
|
||||
|
||||
virtual double vertexAngle( QgsVertexId vertex ) const = 0;
|
||||
%Docstring
|
||||
Returns approximate angle at a vertex. This is usually the average angle between adjacent
|
||||
|
||||
@ -29,6 +29,7 @@ class QgsCircularString: QgsCurve
|
||||
|
||||
virtual QString geometryType() const;
|
||||
virtual int dimension() const;
|
||||
virtual QgsCircularString *createEmptyWithSameType() const /Factory/;
|
||||
virtual QgsCircularString *clone() const /Factory/;
|
||||
virtual void clear();
|
||||
|
||||
|
||||
@ -29,6 +29,7 @@ class QgsCompoundCurve: QgsCurve
|
||||
|
||||
virtual QString geometryType() const;
|
||||
virtual int dimension() const;
|
||||
virtual QgsCompoundCurve *createEmptyWithSameType() const /Factory/;
|
||||
virtual QgsCompoundCurve *clone() const /Factory/;
|
||||
virtual void clear();
|
||||
|
||||
|
||||
@ -126,6 +126,8 @@ class QgsCurve: QgsAbstractGeometry
|
||||
|
||||
virtual QgsAbstractGeometry *boundary() const /Factory/;
|
||||
|
||||
virtual QgsCurve *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0,
|
||||
double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;
|
||||
|
||||
virtual QgsCurve *segmentize( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ class QgsCurvePolygon: QgsSurface
|
||||
virtual QString geometryType() const;
|
||||
|
||||
virtual int dimension() const;
|
||||
|
||||
virtual QgsCurvePolygon *createEmptyWithSameType() const /Factory/;
|
||||
virtual QgsCurvePolygon *clone() const /Factory/;
|
||||
|
||||
virtual void clear();
|
||||
@ -64,7 +64,8 @@ class QgsCurvePolygon: QgsSurface
|
||||
virtual QgsPolygonV2 *surfaceToPolygon() const /Factory/;
|
||||
|
||||
virtual QgsAbstractGeometry *boundary() const /Factory/;
|
||||
|
||||
virtual QgsCurvePolygon *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0,
|
||||
double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;
|
||||
|
||||
int numInteriorRings() const;
|
||||
%Docstring
|
||||
|
||||
@ -26,6 +26,7 @@ class QgsGeometryCollection: QgsAbstractGeometry
|
||||
QgsGeometryCollection( const QgsGeometryCollection &c );
|
||||
virtual ~QgsGeometryCollection();
|
||||
|
||||
virtual QgsGeometryCollection *createEmptyWithSameType() const /Factory/;
|
||||
virtual QgsGeometryCollection *clone() const /Factory/;
|
||||
|
||||
|
||||
@ -50,7 +51,8 @@ class QgsGeometryCollection: QgsAbstractGeometry
|
||||
virtual QString geometryType() const;
|
||||
|
||||
virtual void clear();
|
||||
|
||||
virtual QgsGeometryCollection *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0,
|
||||
double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;
|
||||
virtual QgsAbstractGeometry *boundary() const /Factory/;
|
||||
|
||||
virtual void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex /Out/, QgsVertexId &nextVertex /Out/ ) const;
|
||||
|
||||
@ -170,13 +170,15 @@ Closes the line string by appending the first point to the end of the line, if i
|
||||
virtual QString geometryType() const;
|
||||
|
||||
virtual int dimension() const;
|
||||
|
||||
virtual QgsLineString *createEmptyWithSameType() const /Factory/;
|
||||
virtual QgsLineString *clone() const /Factory/;
|
||||
|
||||
virtual void clear();
|
||||
|
||||
virtual bool isEmpty() const;
|
||||
|
||||
virtual QgsLineString *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0,
|
||||
double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;
|
||||
|
||||
virtual bool fromWkb( QgsConstWkbPtr &wkb );
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ class QgsMultiCurve: QgsGeometryCollection
|
||||
public:
|
||||
QgsMultiCurve();
|
||||
virtual QString geometryType() const;
|
||||
|
||||
virtual QgsMultiCurve *createEmptyWithSameType() const /Factory/;
|
||||
virtual QgsMultiCurve *clone() const /Factory/;
|
||||
|
||||
virtual void clear();
|
||||
|
||||
@ -22,7 +22,7 @@ class QgsMultiLineString: QgsMultiCurve
|
||||
QgsMultiLineString();
|
||||
|
||||
virtual QString geometryType() const;
|
||||
|
||||
virtual QgsMultiLineString *createEmptyWithSameType() const /Factory/;
|
||||
virtual QgsMultiLineString *clone() const /Factory/;
|
||||
|
||||
virtual void clear();
|
||||
|
||||
@ -22,7 +22,7 @@ class QgsMultiPointV2: QgsGeometryCollection
|
||||
QgsMultiPointV2();
|
||||
|
||||
virtual QString geometryType() const;
|
||||
|
||||
virtual QgsMultiPointV2 *createEmptyWithSameType() const /Factory/;
|
||||
virtual QgsMultiPointV2 *clone() const /Factory/;
|
||||
|
||||
virtual QgsMultiPointV2 *toCurveType() const /Factory/;
|
||||
|
||||
@ -21,7 +21,7 @@ class QgsMultiPolygonV2: QgsMultiSurface
|
||||
public:
|
||||
QgsMultiPolygonV2();
|
||||
virtual QString geometryType() const;
|
||||
|
||||
virtual QgsMultiPolygonV2 *createEmptyWithSameType() const /Factory/;
|
||||
virtual void clear();
|
||||
|
||||
virtual QgsMultiPolygonV2 *clone() const /Factory/;
|
||||
|
||||
@ -21,9 +21,8 @@ class QgsMultiSurface: QgsGeometryCollection
|
||||
public:
|
||||
QgsMultiSurface();
|
||||
virtual QString geometryType() const;
|
||||
|
||||
virtual void clear();
|
||||
|
||||
virtual QgsMultiSurface *createEmptyWithSameType() const /Factory/;
|
||||
virtual QgsMultiSurface *clone() const /Factory/;
|
||||
|
||||
virtual QgsMultiSurface *toCurveType() const /Factory/;
|
||||
|
||||
@ -335,9 +335,10 @@ class QgsPoint: QgsAbstractGeometry
|
||||
virtual QString geometryType() const;
|
||||
|
||||
virtual int dimension() const;
|
||||
|
||||
virtual QgsPoint *createEmptyWithSameType() const /Factory/;
|
||||
virtual QgsPoint *clone() const /Factory/;
|
||||
|
||||
virtual QgsPoint *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0,
|
||||
double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;
|
||||
virtual void clear();
|
||||
|
||||
virtual bool fromWkb( QgsConstWkbPtr &wkb );
|
||||
|
||||
@ -23,7 +23,7 @@ class QgsPolygonV2: QgsCurvePolygon
|
||||
QgsPolygonV2();
|
||||
|
||||
virtual QString geometryType() const;
|
||||
|
||||
virtual QgsPolygonV2 *createEmptyWithSameType() const /Factory/;
|
||||
virtual QgsPolygonV2 *clone() const /Factory/;
|
||||
|
||||
virtual void clear();
|
||||
|
||||
@ -25,6 +25,9 @@ class QgsSurface: QgsAbstractGeometry
|
||||
:rtype: QgsPolygonV2
|
||||
%End
|
||||
|
||||
virtual QgsSurface *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0,
|
||||
double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;
|
||||
|
||||
virtual QgsRectangle boundingBox() const;
|
||||
%Docstring
|
||||
Returns the minimal bounding box for the geometry
|
||||
|
||||
@ -53,7 +53,7 @@ class QgsTriangle : QgsPolygonV2
|
||||
%End
|
||||
|
||||
virtual QString geometryType() const;
|
||||
|
||||
virtual QgsTriangle *createEmptyWithSameType() const /Factory/;
|
||||
virtual QgsTriangle *clone() const /Factory/;
|
||||
|
||||
virtual void clear();
|
||||
|
||||
@ -467,6 +467,7 @@ SET(QGIS_CORE_SRCS
|
||||
geometry/qgsrectangle.cpp
|
||||
geometry/qgsreferencedgeometry.cpp
|
||||
geometry/qgsregularpolygon.cpp
|
||||
geometry/qgssurface.cpp
|
||||
geometry/qgstriangle.cpp
|
||||
geometry/qgswkbptr.cpp
|
||||
geometry/qgswkbtypes.cpp
|
||||
|
||||
@ -110,6 +110,14 @@ class CORE_EXPORT QgsAbstractGeometry
|
||||
QgsAbstractGeometry( const QgsAbstractGeometry &geom );
|
||||
QgsAbstractGeometry &operator=( const QgsAbstractGeometry &geom );
|
||||
|
||||
/** Makes a new geometry with the same class and same WKB and transfers ownership.
|
||||
* To create it, the geometry is default constructedand then the WKB is changed.
|
||||
* \returns the new empty geometry. Callee takes ownership.
|
||||
* \see clone
|
||||
* \since 3.0
|
||||
*/
|
||||
virtual QgsAbstractGeometry *createEmptyWithSameType() const = 0 SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Clones the geometry by performing a deep copy
|
||||
*/
|
||||
@ -411,6 +419,30 @@ class CORE_EXPORT QgsAbstractGeometry
|
||||
*/
|
||||
virtual QgsAbstractGeometry *toCurveType() const = 0 SIP_FACTORY;
|
||||
|
||||
/** Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
|
||||
* It transfers ownership to the callee.
|
||||
* If it couldn't make the gridified geometry it returns nullptr.
|
||||
* It may generate an invalid geometry (in some corner cases).
|
||||
* It can also be thought as rounding the edges and it may be useful for removing errors.
|
||||
* If the geometry is curved, it will be segmentized before gridifying it.
|
||||
* Example:
|
||||
* \code
|
||||
* geometry->snappedToGrid(1, 1);
|
||||
* \endcode
|
||||
* In this case we use a 2D grid of 1x1 to gridify.
|
||||
* In this case, it can be thought like rounding the x and y of all the points/vertices to full units (remove all decimals).
|
||||
* \param hSpacing Horizontal spacing of the grid (x axis). 0 to disable.
|
||||
* \param vSpacing Vertical spacing of the grid (y axis). 0 to disable.
|
||||
* \param dSpacing Depth spacing of the grid (z axis). 0 (default) to disable.
|
||||
* \param mSpacing Custom dimension spacing of the grid (m axis). 0 (default) to disable.
|
||||
* \param tolerance In case of segmentation, the tolerance to use (passed to segmentize as is).
|
||||
* \param toleranceType In case of segmentation, the toleranceType to use (passed to segmentize as is).
|
||||
* \returns the segmentized geometry or nullptr if it wasn't possible to make. Caller takes ownership.
|
||||
* \see segmentize
|
||||
* \since 3.0
|
||||
*/
|
||||
virtual QgsAbstractGeometry *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0, double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const = 0 SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Returns approximate angle at a vertex. This is usually the average angle between adjacent
|
||||
* segments, and can be pictured as the orientation of a line following the curvature of the
|
||||
|
||||
@ -66,6 +66,13 @@ bool QgsCircularString::operator!=( const QgsCurve &other ) const
|
||||
return !operator==( other );
|
||||
}
|
||||
|
||||
QgsCircularString *QgsCircularString::createEmptyWithSameType() const
|
||||
{
|
||||
auto result = new QgsCircularString();
|
||||
result->mWkbType = mWkbType;
|
||||
return result;
|
||||
}
|
||||
|
||||
QString QgsCircularString::geometryType() const
|
||||
{
|
||||
return QStringLiteral( "CircularString" );
|
||||
|
||||
@ -41,6 +41,7 @@ class CORE_EXPORT QgsCircularString: public QgsCurve
|
||||
|
||||
virtual QString geometryType() const override;
|
||||
virtual int dimension() const override;
|
||||
virtual QgsCircularString *createEmptyWithSameType() const override SIP_FACTORY;
|
||||
virtual QgsCircularString *clone() const override SIP_FACTORY;
|
||||
virtual void clear() override;
|
||||
|
||||
|
||||
@ -61,6 +61,13 @@ bool QgsCompoundCurve::operator!=( const QgsCurve &other ) const
|
||||
return !operator==( other );
|
||||
}
|
||||
|
||||
QgsCompoundCurve *QgsCompoundCurve::createEmptyWithSameType() const
|
||||
{
|
||||
auto result = new QgsCompoundCurve();
|
||||
result->mWkbType = mWkbType;
|
||||
return result;
|
||||
}
|
||||
|
||||
QString QgsCompoundCurve::geometryType() const
|
||||
{
|
||||
return QStringLiteral( "CompoundCurve" );
|
||||
|
||||
@ -41,6 +41,7 @@ class CORE_EXPORT QgsCompoundCurve: public QgsCurve
|
||||
|
||||
virtual QString geometryType() const override;
|
||||
virtual int dimension() const override;
|
||||
virtual QgsCompoundCurve *createEmptyWithSameType() const override SIP_FACTORY;
|
||||
virtual QgsCompoundCurve *clone() const override SIP_FACTORY;
|
||||
virtual void clear() override;
|
||||
|
||||
|
||||
@ -15,6 +15,8 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "qgscurve.h"
|
||||
#include "qgslinestring.h"
|
||||
#include "qgspoint.h"
|
||||
@ -129,6 +131,13 @@ QgsAbstractGeometry *QgsCurve::boundary() const
|
||||
return multiPoint;
|
||||
}
|
||||
|
||||
QgsCurve *QgsCurve::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing,
|
||||
double tolerance, SegmentationToleranceType toleranceType ) const
|
||||
{
|
||||
std::unique_ptr<QgsLineString> line { curveToLine( tolerance, toleranceType ) };
|
||||
return line->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing );
|
||||
}
|
||||
|
||||
QgsCurve *QgsCurve::segmentize( double tolerance, SegmentationToleranceType toleranceType ) const
|
||||
{
|
||||
return curveToLine( tolerance, toleranceType );
|
||||
|
||||
@ -123,6 +123,9 @@ class CORE_EXPORT QgsCurve: public QgsAbstractGeometry
|
||||
|
||||
QgsAbstractGeometry *boundary() const override SIP_FACTORY;
|
||||
|
||||
virtual QgsCurve *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0,
|
||||
double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const override SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Returns a geometry without curves. Caller takes ownership
|
||||
* \param tolerance segmentation tolerance
|
||||
|
||||
@ -38,6 +38,13 @@ QgsCurvePolygon::~QgsCurvePolygon()
|
||||
clear();
|
||||
}
|
||||
|
||||
QgsCurvePolygon *QgsCurvePolygon::createEmptyWithSameType() const
|
||||
{
|
||||
auto result = new QgsCurvePolygon();
|
||||
result->mWkbType = mWkbType;
|
||||
return result;
|
||||
}
|
||||
|
||||
QString QgsCurvePolygon::geometryType() const
|
||||
{
|
||||
return QStringLiteral( "CurvePolygon" );
|
||||
@ -495,6 +502,49 @@ QgsAbstractGeometry *QgsCurvePolygon::boundary() const
|
||||
}
|
||||
}
|
||||
|
||||
QgsCurvePolygon *QgsCurvePolygon::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing,
|
||||
double tolerance, SegmentationToleranceType toleranceType ) const
|
||||
{
|
||||
if ( !mExteriorRing )
|
||||
return nullptr;
|
||||
|
||||
std::unique_ptr<QgsPolygonV2> polygon;
|
||||
if ( QgsWkbTypes::flatType( mWkbType ) == QgsWkbTypes::Triangle || QgsWkbTypes::flatType( mWkbType ) == QgsWkbTypes::Polygon )
|
||||
{
|
||||
polygon = std::unique_ptr<QgsPolygonV2> { static_cast< QgsPolygonV2 const *>( this )->createEmptyWithSameType() };
|
||||
}
|
||||
else
|
||||
{
|
||||
polygon = std::unique_ptr<QgsPolygonV2> { new QgsPolygonV2() };
|
||||
polygon->mWkbType = QgsWkbTypes::zmType( QgsWkbTypes::Polygon, QgsWkbTypes::hasZ( mWkbType ), QgsWkbTypes::hasM( mWkbType ) );
|
||||
}
|
||||
|
||||
// exterior ring
|
||||
auto exterior = std::unique_ptr<QgsCurve> { mExteriorRing->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing, tolerance, toleranceType ) };
|
||||
|
||||
if ( !exterior )
|
||||
return nullptr;
|
||||
|
||||
polygon->mExteriorRing = exterior.release();
|
||||
|
||||
//interior rings
|
||||
for ( auto interior : mInteriorRings )
|
||||
{
|
||||
if ( !interior )
|
||||
continue;
|
||||
|
||||
QgsCurve *gridifiedInterior = interior->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing, tolerance, toleranceType );
|
||||
|
||||
if ( !gridifiedInterior )
|
||||
continue;
|
||||
|
||||
polygon->mInteriorRings.append( gridifiedInterior );
|
||||
}
|
||||
|
||||
return polygon.release();
|
||||
|
||||
}
|
||||
|
||||
QgsPolygonV2 *QgsCurvePolygon::toPolygon( double tolerance, SegmentationToleranceType toleranceType ) const
|
||||
{
|
||||
std::unique_ptr< QgsPolygonV2 > poly( new QgsPolygonV2() );
|
||||
|
||||
@ -45,6 +45,7 @@ class CORE_EXPORT QgsCurvePolygon: public QgsSurface
|
||||
|
||||
QString geometryType() const override;
|
||||
int dimension() const override;
|
||||
virtual QgsCurvePolygon *createEmptyWithSameType() const override SIP_FACTORY;
|
||||
QgsCurvePolygon *clone() const override SIP_FACTORY;
|
||||
void clear() override;
|
||||
|
||||
@ -62,6 +63,8 @@ class CORE_EXPORT QgsCurvePolygon: public QgsSurface
|
||||
double perimeter() const override;
|
||||
QgsPolygonV2 *surfaceToPolygon() const override SIP_FACTORY;
|
||||
QgsAbstractGeometry *boundary() const override SIP_FACTORY;
|
||||
virtual QgsCurvePolygon *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0,
|
||||
double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const override SIP_FACTORY;
|
||||
|
||||
//curve polygon interface
|
||||
int numInteriorRings() const;
|
||||
|
||||
@ -26,6 +26,7 @@ email : marco.hugentobler at sourcepole dot com
|
||||
#include "qgspolygon.h"
|
||||
#include "qgsmultipolygon.h"
|
||||
#include "qgswkbptr.h"
|
||||
#include <memory>
|
||||
|
||||
QgsGeometryCollection::QgsGeometryCollection()
|
||||
{
|
||||
@ -63,6 +64,13 @@ QgsGeometryCollection::~QgsGeometryCollection()
|
||||
clear();
|
||||
}
|
||||
|
||||
QgsGeometryCollection *QgsGeometryCollection::createEmptyWithSameType() const
|
||||
{
|
||||
auto result = new QgsGeometryCollection();
|
||||
result->mWkbType = mWkbType;
|
||||
return result;
|
||||
}
|
||||
|
||||
QgsGeometryCollection *QgsGeometryCollection::clone() const
|
||||
{
|
||||
return new QgsGeometryCollection( *this );
|
||||
@ -75,6 +83,26 @@ void QgsGeometryCollection::clear()
|
||||
clearCache(); //set bounding box invalid
|
||||
}
|
||||
|
||||
QgsGeometryCollection *QgsGeometryCollection::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing,
|
||||
double tolerance, SegmentationToleranceType toleranceType ) const
|
||||
{
|
||||
std::unique_ptr<QgsGeometryCollection> result;
|
||||
|
||||
for ( auto geom : mGeometries )
|
||||
{
|
||||
std::unique_ptr<QgsAbstractGeometry> gridified { geom->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing, tolerance, toleranceType ) };
|
||||
if ( gridified )
|
||||
{
|
||||
if ( !result )
|
||||
result = std::unique_ptr<QgsGeometryCollection> { createEmptyWithSameType() };
|
||||
|
||||
result->mGeometries.append( gridified.release() );
|
||||
}
|
||||
}
|
||||
|
||||
return result.release();
|
||||
}
|
||||
|
||||
QgsAbstractGeometry *QgsGeometryCollection::boundary() const
|
||||
{
|
||||
return nullptr;
|
||||
|
||||
@ -39,6 +39,7 @@ class CORE_EXPORT QgsGeometryCollection: public QgsAbstractGeometry
|
||||
QgsGeometryCollection &operator=( const QgsGeometryCollection &c );
|
||||
virtual ~QgsGeometryCollection();
|
||||
|
||||
virtual QgsGeometryCollection *createEmptyWithSameType() const override SIP_FACTORY;
|
||||
QgsGeometryCollection *clone() const override SIP_FACTORY;
|
||||
|
||||
/**
|
||||
@ -64,6 +65,8 @@ class CORE_EXPORT QgsGeometryCollection: public QgsAbstractGeometry
|
||||
int dimension() const override;
|
||||
QString geometryType() const override;
|
||||
void clear() override;
|
||||
virtual QgsGeometryCollection *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0,
|
||||
double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const override SIP_FACTORY;
|
||||
QgsAbstractGeometry *boundary() const override SIP_FACTORY;
|
||||
void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex SIP_OUT, QgsVertexId &nextVertex SIP_OUT ) const override;
|
||||
int vertexNumberFromVertexId( QgsVertexId id ) const override;
|
||||
|
||||
@ -23,6 +23,8 @@
|
||||
#include "qgsmaptopixel.h"
|
||||
#include "qgswkbptr.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <QPainter>
|
||||
#include <limits>
|
||||
#include <QDomDocument>
|
||||
@ -187,6 +189,84 @@ bool QgsLineString::isEmpty() const
|
||||
return mX.isEmpty();
|
||||
}
|
||||
|
||||
QgsLineString *QgsLineString::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing,
|
||||
double /*tolerance*/, SegmentationToleranceType /*toleranceType*/ ) const
|
||||
{
|
||||
int length = numPoints();
|
||||
|
||||
if ( length <= 0 )
|
||||
return nullptr;
|
||||
|
||||
// prepare result
|
||||
std::unique_ptr<QgsLineString> result { createEmptyWithSameType() };
|
||||
|
||||
|
||||
// helper functions
|
||||
auto roundVertex = [&]( QgsPoint & out, int i )
|
||||
{
|
||||
if ( hSpacing > 0 )
|
||||
out.setX( std::round( mX.at( i ) / hSpacing ) * hSpacing );
|
||||
|
||||
if ( vSpacing > 0 )
|
||||
out.setY( std::round( mY.at( i ) / vSpacing ) * vSpacing );
|
||||
|
||||
if ( dSpacing > 0 && QgsWkbTypes::hasZ( mWkbType ) )
|
||||
out.setZ( std::round( mZ.at( i ) / dSpacing ) * dSpacing );
|
||||
|
||||
if ( mSpacing > 0 && QgsWkbTypes::hasM( mWkbType ) )
|
||||
out.setM( std::round( mM.at( i ) / mSpacing ) * mSpacing );
|
||||
};
|
||||
|
||||
|
||||
auto append = [this, &result]( QgsPoint const & point )
|
||||
{
|
||||
result->mX.append( point.x() );
|
||||
|
||||
result->mY.append( point.y() );
|
||||
|
||||
if ( QgsWkbTypes::hasZ( mWkbType ) )
|
||||
result->mZ.append( point.z() );
|
||||
|
||||
if ( QgsWkbTypes::hasM( mWkbType ) )
|
||||
result->mM.append( point.m() );
|
||||
};
|
||||
|
||||
|
||||
auto isPointEqual = [&]( const QgsPoint & a, const QgsPoint & b )
|
||||
{
|
||||
return ( a.x() == b.x() )
|
||||
&& ( a.y() == b.y() )
|
||||
&& ( !QgsWkbTypes::hasZ( mWkbType ) || dSpacing <= 0 || a.z() == b.z() )
|
||||
&& ( !QgsWkbTypes::hasM( mWkbType ) || mSpacing <= 0 || a.m() == b.m() );
|
||||
};
|
||||
|
||||
// temporary values
|
||||
QgsWkbTypes::Type pointType = QgsWkbTypes::zmType( QgsWkbTypes::Point, QgsWkbTypes::hasZ( mWkbType ), QgsWkbTypes::hasM( mWkbType ) );
|
||||
QgsPoint last( pointType );
|
||||
QgsPoint current( pointType );
|
||||
|
||||
// Actual code (what does all the work)
|
||||
roundVertex( last, 0 );
|
||||
append( last );
|
||||
|
||||
for ( int i = 1; i < length; ++i )
|
||||
{
|
||||
roundVertex( current, i );
|
||||
if ( !isPointEqual( current, last ) )
|
||||
{
|
||||
append( current );
|
||||
last = current;
|
||||
}
|
||||
}
|
||||
|
||||
// if it's not closed, with 2 points you get a correct line
|
||||
// if it is, you need at least 4 (3 + the vertex that closes)
|
||||
if ( result->mX.length() < 2 || ( isClosed() && result->mX.length() < 4 ) )
|
||||
return nullptr;
|
||||
|
||||
return result.release();
|
||||
}
|
||||
|
||||
bool QgsLineString::fromWkb( QgsConstWkbPtr &wkbPtr )
|
||||
{
|
||||
if ( !wkbPtr )
|
||||
@ -711,6 +791,13 @@ void QgsLineString::extend( double startDistance, double endDistance )
|
||||
}
|
||||
}
|
||||
|
||||
QgsLineString *QgsLineString::createEmptyWithSameType() const
|
||||
{
|
||||
auto result = new QgsLineString();
|
||||
result->mWkbType = mWkbType;
|
||||
return result;
|
||||
}
|
||||
|
||||
QString QgsLineString::geometryType() const
|
||||
{
|
||||
return QStringLiteral( "LineString" );
|
||||
|
||||
@ -176,9 +176,12 @@ class CORE_EXPORT QgsLineString: public QgsCurve
|
||||
|
||||
QString geometryType() const override;
|
||||
int dimension() const override;
|
||||
virtual QgsLineString *createEmptyWithSameType() const override SIP_FACTORY;
|
||||
QgsLineString *clone() const override SIP_FACTORY;
|
||||
void clear() override;
|
||||
bool isEmpty() const override;
|
||||
virtual QgsLineString *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0,
|
||||
double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const override SIP_FACTORY;
|
||||
|
||||
bool fromWkb( QgsConstWkbPtr &wkb ) override;
|
||||
bool fromWkt( const QString &wkt ) override;
|
||||
|
||||
@ -33,6 +33,13 @@ QString QgsMultiCurve::geometryType() const
|
||||
return QStringLiteral( "MultiCurve" );
|
||||
}
|
||||
|
||||
QgsMultiCurve *QgsMultiCurve::createEmptyWithSameType() const
|
||||
{
|
||||
auto result = new QgsMultiCurve();
|
||||
result->mWkbType = mWkbType;
|
||||
return result;
|
||||
}
|
||||
|
||||
QgsMultiCurve *QgsMultiCurve::clone() const
|
||||
{
|
||||
return new QgsMultiCurve( *this );
|
||||
|
||||
@ -31,6 +31,7 @@ class CORE_EXPORT QgsMultiCurve: public QgsGeometryCollection
|
||||
public:
|
||||
QgsMultiCurve();
|
||||
QString geometryType() const override;
|
||||
virtual QgsMultiCurve *createEmptyWithSameType() const override SIP_FACTORY;
|
||||
QgsMultiCurve *clone() const override SIP_FACTORY;
|
||||
void clear() override;
|
||||
QgsMultiCurve *toCurveType() const override SIP_FACTORY;
|
||||
|
||||
@ -32,6 +32,13 @@ QString QgsMultiLineString::geometryType() const
|
||||
return QStringLiteral( "MultiLineString" );
|
||||
}
|
||||
|
||||
QgsMultiLineString *QgsMultiLineString::createEmptyWithSameType() const
|
||||
{
|
||||
auto result = new QgsMultiLineString();
|
||||
result->mWkbType = mWkbType;
|
||||
return result;
|
||||
}
|
||||
|
||||
QgsMultiLineString *QgsMultiLineString::clone() const
|
||||
{
|
||||
return new QgsMultiLineString( *this );
|
||||
|
||||
@ -32,6 +32,7 @@ class CORE_EXPORT QgsMultiLineString: public QgsMultiCurve
|
||||
QgsMultiLineString();
|
||||
|
||||
QString geometryType() const override;
|
||||
virtual QgsMultiLineString *createEmptyWithSameType() const override SIP_FACTORY;
|
||||
QgsMultiLineString *clone() const override SIP_FACTORY;
|
||||
void clear() override;
|
||||
bool fromWkt( const QString &wkt ) override;
|
||||
|
||||
@ -29,6 +29,13 @@ QString QgsMultiPointV2::geometryType() const
|
||||
return QStringLiteral( "MultiPoint" );
|
||||
}
|
||||
|
||||
QgsMultiPointV2 *QgsMultiPointV2::createEmptyWithSameType() const
|
||||
{
|
||||
auto result = new QgsMultiPointV2();
|
||||
result->mWkbType = mWkbType;
|
||||
return result;
|
||||
}
|
||||
|
||||
QgsMultiPointV2 *QgsMultiPointV2::clone() const
|
||||
{
|
||||
return new QgsMultiPointV2( *this );
|
||||
|
||||
@ -32,6 +32,7 @@ class CORE_EXPORT QgsMultiPointV2: public QgsGeometryCollection
|
||||
QgsMultiPointV2();
|
||||
|
||||
QString geometryType() const override;
|
||||
virtual QgsMultiPointV2 *createEmptyWithSameType() const override SIP_FACTORY;
|
||||
QgsMultiPointV2 *clone() const override SIP_FACTORY;
|
||||
QgsMultiPointV2 *toCurveType() const override SIP_FACTORY;
|
||||
bool fromWkt( const QString &wkt ) override;
|
||||
|
||||
@ -38,6 +38,13 @@ void QgsMultiPolygonV2::clear()
|
||||
mWkbType = QgsWkbTypes::MultiPolygon;
|
||||
}
|
||||
|
||||
QgsMultiPolygonV2 *QgsMultiPolygonV2::createEmptyWithSameType() const
|
||||
{
|
||||
auto result = new QgsMultiPolygonV2();
|
||||
result->mWkbType = mWkbType;
|
||||
return result;
|
||||
}
|
||||
|
||||
QgsMultiPolygonV2 *QgsMultiPolygonV2::clone() const
|
||||
{
|
||||
return new QgsMultiPolygonV2( *this );
|
||||
|
||||
@ -32,6 +32,7 @@ class CORE_EXPORT QgsMultiPolygonV2: public QgsMultiSurface
|
||||
QgsMultiPolygonV2();
|
||||
QString geometryType() const override;
|
||||
void clear() override;
|
||||
virtual QgsMultiPolygonV2 *createEmptyWithSameType() const override SIP_FACTORY;
|
||||
QgsMultiPolygonV2 *clone() const override SIP_FACTORY;
|
||||
bool fromWkt( const QString &wkt ) override;
|
||||
QDomElement asGML2( QDomDocument &doc, int precision = 17, const QString &ns = "gml" ) const override;
|
||||
|
||||
@ -39,6 +39,13 @@ void QgsMultiSurface::clear()
|
||||
mWkbType = QgsWkbTypes::MultiSurface;
|
||||
}
|
||||
|
||||
QgsMultiSurface *QgsMultiSurface::createEmptyWithSameType() const
|
||||
{
|
||||
auto result = new QgsMultiSurface();
|
||||
result->mWkbType = mWkbType;
|
||||
return result;
|
||||
}
|
||||
|
||||
QgsMultiSurface *QgsMultiSurface::clone() const
|
||||
{
|
||||
return new QgsMultiSurface( *this );
|
||||
|
||||
@ -32,6 +32,7 @@ class CORE_EXPORT QgsMultiSurface: public QgsGeometryCollection
|
||||
QgsMultiSurface();
|
||||
QString geometryType() const override;
|
||||
void clear() override;
|
||||
virtual QgsMultiSurface *createEmptyWithSameType() const override SIP_FACTORY;
|
||||
QgsMultiSurface *clone() const override SIP_FACTORY;
|
||||
QgsMultiSurface *toCurveType() const override SIP_FACTORY;
|
||||
bool fromWkt( const QString &wkt ) override;
|
||||
|
||||
@ -22,6 +22,8 @@
|
||||
#include "qgsgeometryutils.h"
|
||||
#include "qgsmaptopixel.h"
|
||||
#include "qgswkbptr.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <QPainter>
|
||||
#include <QRegularExpression>
|
||||
|
||||
@ -114,6 +116,28 @@ QgsPoint *QgsPoint::clone() const
|
||||
return new QgsPoint( *this );
|
||||
}
|
||||
|
||||
QgsPoint *QgsPoint::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing,
|
||||
double /*tolerance*/, SegmentationToleranceType /*toleranceType*/ ) const
|
||||
{
|
||||
// helper function
|
||||
auto gridifyValue = []( double value, double spacing, bool extraCondition = true ) -> double
|
||||
{
|
||||
if ( spacing > 0 && extraCondition )
|
||||
return std::round( value / spacing ) * spacing;
|
||||
else
|
||||
return value;
|
||||
};
|
||||
|
||||
// Get the new values
|
||||
auto x = gridifyValue( mX, hSpacing );
|
||||
auto y = gridifyValue( mY, vSpacing );
|
||||
auto z = gridifyValue( mZ, dSpacing, QgsWkbTypes::hasZ( mWkbType ) );
|
||||
auto m = gridifyValue( mM, mSpacing, QgsWkbTypes::hasM( mWkbType ) );
|
||||
|
||||
// return the new object
|
||||
return new QgsPoint( mWkbType, x, y, z, m );
|
||||
}
|
||||
|
||||
bool QgsPoint::fromWkb( QgsConstWkbPtr &wkbPtr )
|
||||
{
|
||||
QgsWkbTypes::Type type = wkbPtr.readHeader();
|
||||
@ -669,3 +693,9 @@ QgsPoint QgsPoint::childPoint( int index ) const
|
||||
Q_ASSERT( index == 0 );
|
||||
return *this;
|
||||
}
|
||||
|
||||
QgsPoint *QgsPoint::createEmptyWithSameType() const
|
||||
{
|
||||
double nan = std::numeric_limits<double>::quiet_NaN();
|
||||
return new QgsPoint( nan, nan, nan, nan, mWkbType );
|
||||
}
|
||||
|
||||
@ -390,7 +390,10 @@ class CORE_EXPORT QgsPoint: public QgsAbstractGeometry
|
||||
QgsRectangle boundingBox() const override;
|
||||
QString geometryType() const override;
|
||||
int dimension() const override;
|
||||
virtual QgsPoint *createEmptyWithSameType() const override SIP_FACTORY;
|
||||
QgsPoint *clone() const override SIP_FACTORY;
|
||||
virtual QgsPoint *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0,
|
||||
double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const override SIP_FACTORY;
|
||||
void clear() override;
|
||||
bool fromWkb( QgsConstWkbPtr &wkb ) override;
|
||||
bool fromWkt( const QString &wkt ) override;
|
||||
|
||||
@ -32,6 +32,13 @@ QString QgsPolygonV2::geometryType() const
|
||||
return QStringLiteral( "Polygon" );
|
||||
}
|
||||
|
||||
QgsPolygonV2 *QgsPolygonV2::createEmptyWithSameType() const
|
||||
{
|
||||
auto result = new QgsPolygonV2();
|
||||
result->mWkbType = mWkbType;
|
||||
return result;
|
||||
}
|
||||
|
||||
QgsPolygonV2 *QgsPolygonV2::clone() const
|
||||
{
|
||||
return new QgsPolygonV2( *this );
|
||||
|
||||
@ -35,6 +35,7 @@ class CORE_EXPORT QgsPolygonV2: public QgsCurvePolygon
|
||||
|
||||
QString geometryType() const override;
|
||||
QgsPolygonV2 *clone() const override SIP_FACTORY;
|
||||
virtual QgsPolygonV2 *createEmptyWithSameType() const override SIP_FACTORY;
|
||||
void clear() override;
|
||||
bool fromWkb( QgsConstWkbPtr &wkb ) override;
|
||||
QByteArray asWkb() const override;
|
||||
|
||||
32
src/core/geometry/qgssurface.cpp
Normal file
32
src/core/geometry/qgssurface.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
/***************************************************************************
|
||||
qgscurvepolygon.cpp
|
||||
---------------------
|
||||
begin : August 2017
|
||||
copyright : (C) 2017 by Martí Angelats i Ribera
|
||||
email : marti dot angelats at psig dot cat
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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 "qgssurface.h"
|
||||
#include "qgspoint.h"
|
||||
#include "qgspolygon.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
QgsSurface *QgsSurface::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing,
|
||||
double /*tolerance*/, SegmentationToleranceType /*toleranceType*/ ) const
|
||||
{
|
||||
std::unique_ptr<QgsPolygonV2> polygon { surfaceToPolygon() };
|
||||
if ( !polygon )
|
||||
return nullptr;
|
||||
|
||||
return polygon->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing );
|
||||
}
|
||||
@ -39,6 +39,9 @@ class CORE_EXPORT QgsSurface: public QgsAbstractGeometry
|
||||
*/
|
||||
virtual QgsPolygonV2 *surfaceToPolygon() const = 0 SIP_FACTORY;
|
||||
|
||||
virtual QgsSurface *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0,
|
||||
double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const override SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Returns the minimal bounding box for the geometry
|
||||
*/
|
||||
|
||||
@ -89,6 +89,13 @@ QString QgsTriangle::geometryType() const
|
||||
return QStringLiteral( "Triangle" );
|
||||
}
|
||||
|
||||
QgsTriangle *QgsTriangle::createEmptyWithSameType() const
|
||||
{
|
||||
auto result = new QgsTriangle();
|
||||
result->mWkbType = mWkbType;
|
||||
return result;
|
||||
}
|
||||
|
||||
void QgsTriangle::clear()
|
||||
{
|
||||
QgsCurvePolygon::clear();
|
||||
|
||||
@ -64,6 +64,7 @@ class CORE_EXPORT QgsTriangle : public QgsPolygonV2
|
||||
|
||||
QString geometryType() const override;
|
||||
QgsTriangle *clone() const override SIP_FACTORY;
|
||||
virtual QgsTriangle *createEmptyWithSameType() const override SIP_FACTORY;
|
||||
void clear() override;
|
||||
|
||||
bool fromWkb( QgsConstWkbPtr &wkbPtr ) override;
|
||||
|
||||
@ -13,6 +13,9 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
#include "qgstest.h"
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <limits>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
@ -101,6 +104,8 @@ class TestQgsGeometry : public QObject
|
||||
void comparePolylines();
|
||||
void comparePolygons();
|
||||
|
||||
void createEmptyWithSameType();
|
||||
|
||||
// MK, Disabled 14.11.2014
|
||||
// Too unclear what exactly should be tested and which variations are allowed for the line
|
||||
#if 0
|
||||
@ -138,6 +143,7 @@ class TestQgsGeometry : public QObject
|
||||
|
||||
void minimalEnclosingCircle( );
|
||||
void splitGeometry();
|
||||
void snappedToGrid();
|
||||
|
||||
private:
|
||||
//! A helper method to do a render check to see if the geometry op is as expected
|
||||
@ -14749,6 +14755,66 @@ void TestQgsGeometry::comparePolygons()
|
||||
}
|
||||
|
||||
|
||||
// Helper function (in anonymous namespace to prevent possible link with the extirior)
|
||||
namespace
|
||||
{
|
||||
template<typename T>
|
||||
inline void testCreateEmptyWithSameType( bool canBeEmpty = true )
|
||||
{
|
||||
std::unique_ptr<QgsAbstractGeometry> geom { new T() };
|
||||
std::unique_ptr<QgsAbstractGeometry> created { geom->createEmptyWithSameType() };
|
||||
if ( canBeEmpty )
|
||||
{
|
||||
QVERIFY( created->isEmpty() );
|
||||
}
|
||||
// Check that it is the correct type
|
||||
QVERIFY( static_cast<T *>( created.get() ) != nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
void TestQgsGeometry::createEmptyWithSameType()
|
||||
{
|
||||
qDebug( "createEmptyWithSameType(): QgsCircularString" );
|
||||
testCreateEmptyWithSameType<QgsCircularString>();
|
||||
|
||||
qDebug( "createEmptyWithSameType(): QgsCompoundCurve" );
|
||||
testCreateEmptyWithSameType<QgsCompoundCurve>();
|
||||
|
||||
qDebug( "createEmptyWithSameType(): QgsLineString" );
|
||||
testCreateEmptyWithSameType<QgsLineString>();
|
||||
|
||||
|
||||
qDebug( "createEmptyWithSameType(): QgsGeometryCollection" );
|
||||
testCreateEmptyWithSameType<QgsGeometryCollection>();
|
||||
|
||||
qDebug( "createEmptyWithSameType(): QgsMultiCurve" );
|
||||
testCreateEmptyWithSameType<QgsMultiCurve>();
|
||||
|
||||
qDebug( "createEmptyWithSameType(): QgsMultiLineString" );
|
||||
testCreateEmptyWithSameType<QgsMultiLineString>();
|
||||
|
||||
qDebug( "createEmptyWithSameType(): QgsMultiPointV2" );
|
||||
testCreateEmptyWithSameType<QgsMultiPointV2>();
|
||||
|
||||
qDebug( "createEmptyWithSameType(): QgsMultiSurface" );
|
||||
testCreateEmptyWithSameType<QgsMultiSurface>();
|
||||
|
||||
|
||||
qDebug( "createEmptyWithSameType(): QgsPoint" );
|
||||
testCreateEmptyWithSameType<QgsPoint>( false );
|
||||
|
||||
|
||||
qDebug( "createEmptyWithSameType(): QgsCurvePolygon" );
|
||||
testCreateEmptyWithSameType<QgsCurvePolygon>();
|
||||
|
||||
qDebug( "createEmptyWithSameType(): QgsPolygonV2" );
|
||||
testCreateEmptyWithSameType<QgsPolygonV2>();
|
||||
|
||||
qDebug( "createEmptyWithSameType(): QgsTriangle" );
|
||||
testCreateEmptyWithSameType<QgsTriangle>();
|
||||
|
||||
}
|
||||
|
||||
|
||||
// MK, Disabled 14.11.2014
|
||||
// Too unclear what exactly should be tested and which variations are allowed for the line
|
||||
@ -15595,6 +15661,95 @@ void TestQgsGeometry::splitGeometry()
|
||||
QVERIFY( newGeoms.isEmpty() );
|
||||
}
|
||||
|
||||
void TestQgsGeometry::snappedToGrid()
|
||||
{
|
||||
qDebug( "SnappedToGrid" );
|
||||
// points
|
||||
{
|
||||
qDebug( "\tPoints:" );
|
||||
auto check = []( QgsPoint * _a, QgsPoint const & b )
|
||||
{
|
||||
std::unique_ptr<QgsPoint> a {_a};
|
||||
// because it is to check after snapping, there shouldn't be small precision errors
|
||||
|
||||
qDebug( "\t\tGridified point: %f, %f, %f, %f", a->x(), a->y(), a->z(), a->m() );
|
||||
qDebug( "\t\tExpected point: %f, %f, %f, %f", b.x(), b.y(), b.z(), b.m() );
|
||||
if ( !std::isnan( b.x() ) )
|
||||
QVERIFY( ( float )a->x() == ( float )b.x() );
|
||||
|
||||
if ( !std::isnan( b.y() ) )
|
||||
QVERIFY( ( float )a->y() == ( float )b.y() );
|
||||
|
||||
if ( !std::isnan( b.z() ) )
|
||||
QVERIFY( ( float )a->z() == ( float )b.z() );
|
||||
|
||||
if ( !std::isnan( b.m() ) )
|
||||
QVERIFY( ( float )a->m() == ( float )b.m() );
|
||||
};
|
||||
|
||||
|
||||
check( QgsPoint( 0, 0 ).snappedToGrid( 1, 1 ),
|
||||
QgsPoint( 0, 0 ) );
|
||||
|
||||
check( QgsPoint( 1, 2.732 ).snappedToGrid( 1, 1 ),
|
||||
QgsPoint( 1, 3 ) );
|
||||
|
||||
check( QgsPoint( 1.3, 6.4 ).snappedToGrid( 1, 1 ),
|
||||
QgsPoint( 1, 6 ) );
|
||||
|
||||
check( QgsPoint( 1.3, 6.4 ).snappedToGrid( 1, 0 ),
|
||||
QgsPoint( 1, 6.4 ) );
|
||||
|
||||
|
||||
// multiple checks with the same point
|
||||
auto p1 = QgsPoint( 1.38, 2.4432 );
|
||||
|
||||
check( p1.snappedToGrid( 1, 1 ),
|
||||
QgsPoint( 1, 2 ) );
|
||||
|
||||
check( p1.snappedToGrid( 1, 0.1 ),
|
||||
QgsPoint( 1, 2.4 ) );
|
||||
|
||||
check( p1.snappedToGrid( 1, 0.01 ),
|
||||
QgsPoint( 1, 2.44 ) );
|
||||
|
||||
// Let's test more dimensions
|
||||
auto p2 = QgsPoint( 4.2134212, 543.1231, 0.123, 12.944145 );
|
||||
|
||||
check( p2.snappedToGrid( 0, 0, 0, 0 ),
|
||||
p2 );
|
||||
|
||||
check( p2.snappedToGrid( 0, 0, 1, 1 ),
|
||||
QgsPoint( 4.2134212, 543.1231, 0, 13 ) );
|
||||
|
||||
check( p2.snappedToGrid( 1, 0.1, 0.01, 0.001 ),
|
||||
QgsPoint( 4, 543.1, 0.12, 12.944 ) );
|
||||
|
||||
}
|
||||
|
||||
// MultiPolygon (testing QgsCollection, QgsCurvePolygon and QgsLineString)
|
||||
{
|
||||
/*
|
||||
* List of tested edge cases:
|
||||
*
|
||||
* - QgsLineString becoming a point
|
||||
* - QgsLineString losing enough points so it is no longer closed
|
||||
* - QgsCurvePolygon losing its external ring
|
||||
* - QgsCurvePolygon losing an internal ring
|
||||
* - QgsCurvePolygon losing all internal rings
|
||||
* - QgsCollection losing one of its members
|
||||
* - QgsCollection losing all its members
|
||||
*/
|
||||
|
||||
auto in = QString( "MultiPolygon (((-1.2 -0.87, -0.943 0.8, 0.82 1.4, 1.2 0.9, 0.9 -0.6, -1.2 -0.87),(0.4 0, -0.4 0, 0 0.2, 0.4 0)),((2 0, 2.2 0.2, 2.2 -0.2)),((3 0, 4 0.2, 4 -0.2, 3 0)),((4 8, 3.6 4.1, 0.3 4.9, -0.2 7.8, 4 8),(6.7 7.3, 7 6.4, 5.6 5.9, 6.2 6.8, 6.7 7.3),(6 5.2, 4.9 5.3, 4.8 6.2, 6 5.2)))" );
|
||||
auto out = QString( "MultiPolygon (((-1 -1, -1 1, 1 1, 1 -1, -1 -1)),((4 8, 4 4, 0 5, 0 8, 4 8),(7 7, 7 6, 6 6, 6 7, 7 7),(6 5, 5 5, 5 6, 6 5)))" );
|
||||
|
||||
auto inGeom = QgsGeometryFactory::geomFromWkt( in );
|
||||
|
||||
std::unique_ptr<QgsAbstractGeometry> snapped { inGeom->snappedToGrid( 1, 1 ) };
|
||||
QCOMPARE( snapped->asWkt(), out );
|
||||
}
|
||||
}
|
||||
|
||||
QGSTEST_MAIN( TestQgsGeometry )
|
||||
#include "testqgsgeometry.moc"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user