mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-06 00:07:29 -04:00
Add extrude function to QgsGeometry
This commit is contained in:
parent
e290c985f7
commit
542541007c
@ -433,9 +433,12 @@ class QgsGeometry
|
|||||||
/** Returns a geometry representing the points making up this geometry that do not make up other. */
|
/** Returns a geometry representing the points making up this geometry that do not make up other. */
|
||||||
QgsGeometry* difference( const QgsGeometry* geometry ) const /Factory/;
|
QgsGeometry* difference( const QgsGeometry* geometry ) const /Factory/;
|
||||||
|
|
||||||
/** Returns a Geometry representing the points making up this Geometry that do not make up other. */
|
/** Returns a Geometry representing the points making up this geometry that do not make up other. */
|
||||||
QgsGeometry* symDifference( const QgsGeometry* geometry ) const /Factory/;
|
QgsGeometry* symDifference( const QgsGeometry* geometry ) const /Factory/;
|
||||||
|
|
||||||
|
/** Returns an extruded version of this geometry. */
|
||||||
|
QgsGeometry extrude( double x, double y );
|
||||||
|
|
||||||
/** Exports the geometry to WKT
|
/** Exports the geometry to WKT
|
||||||
* @note precision parameter added in 2.4
|
* @note precision parameter added in 2.4
|
||||||
* @return true in case of success and false else
|
* @return true in case of success and false else
|
||||||
|
20
resources/function_help/json/extrude
Normal file
20
resources/function_help/json/extrude
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "extrude",
|
||||||
|
"type": "function",
|
||||||
|
"description": "Returns an extruded version of the input (Multi-)Curve or (Multi-)Linestring geometry with an extension specified by x and y.",
|
||||||
|
"arguments": [
|
||||||
|
{"arg":"geom","description":"a polygon geometry"},
|
||||||
|
{"arg":"x","description":"x extension, numeric value"},
|
||||||
|
{"arg":"y","description":"y extension, numeric value"}
|
||||||
|
],
|
||||||
|
"examples": [
|
||||||
|
{
|
||||||
|
"expression":"extrude(geom_from_wkt('LineString(1 2, 3 2, 4 3)'), 1, 2)",
|
||||||
|
"returns":"Polygon ((1 2, 3 2, 4 3, 5 5, 4 4, 2 4, 1 2))"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expression":"extrude(geom_from_wkt('MultiLineString((1 2, 3 2), (4 3, 8 3)'), 1, 2)",
|
||||||
|
"returns":"MultiPolygon (((1 2, 3 2, 4 4, 2 4, 1 2)),((4 3, 8 3, 9 5, 5 5, 4 3)))"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -320,6 +320,7 @@ SET(QGIS_CORE_SRCS
|
|||||||
geometry/qgsgeometry.cpp
|
geometry/qgsgeometry.cpp
|
||||||
geometry/qgsgeometrycollectionv2.cpp
|
geometry/qgsgeometrycollectionv2.cpp
|
||||||
geometry/qgsgeometryeditutils.cpp
|
geometry/qgsgeometryeditutils.cpp
|
||||||
|
geometry/qgsinternalgeometryengine.cpp
|
||||||
geometry/qgsgeometryfactory.cpp
|
geometry/qgsgeometryfactory.cpp
|
||||||
geometry/qgsgeometryutils.cpp
|
geometry/qgsgeometryutils.cpp
|
||||||
geometry/qgsgeos.cpp
|
geometry/qgsgeos.cpp
|
||||||
@ -788,6 +789,7 @@ SET(QGIS_CORE_HDRS
|
|||||||
layertree/qgslayertreeutils.h
|
layertree/qgslayertreeutils.h
|
||||||
|
|
||||||
geometry/qgsgeometry.h
|
geometry/qgsgeometry.h
|
||||||
|
geometry/qgsinternalgeometryengine.h
|
||||||
geometry/qgsabstractgeometryv2.h
|
geometry/qgsabstractgeometryv2.h
|
||||||
geometry/qgswkbtypes.h
|
geometry/qgswkbtypes.h
|
||||||
geometry/qgspointv2.h
|
geometry/qgspointv2.h
|
||||||
|
@ -23,6 +23,7 @@ email : morb at ozemail dot com dot au
|
|||||||
#include "qgsgeometryeditutils.h"
|
#include "qgsgeometryeditutils.h"
|
||||||
#include "qgsgeometryfactory.h"
|
#include "qgsgeometryfactory.h"
|
||||||
#include "qgsgeometryutils.h"
|
#include "qgsgeometryutils.h"
|
||||||
|
#include "qgsinternalgeometryengine.h"
|
||||||
#include "qgsgeos.h"
|
#include "qgsgeos.h"
|
||||||
#include "qgsapplication.h"
|
#include "qgsapplication.h"
|
||||||
#include "qgslogger.h"
|
#include "qgslogger.h"
|
||||||
@ -1404,6 +1405,13 @@ QgsGeometry* QgsGeometry::symDifference( const QgsGeometry* geometry ) const
|
|||||||
return new QgsGeometry( resultGeom );
|
return new QgsGeometry( resultGeom );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QgsGeometry QgsGeometry::extrude( double x, double y )
|
||||||
|
{
|
||||||
|
QgsInternalGeometryEngine engine( *this );
|
||||||
|
|
||||||
|
return engine.extrude( x, y );
|
||||||
|
}
|
||||||
|
|
||||||
QList<QgsGeometry*> QgsGeometry::asGeometryCollection() const
|
QList<QgsGeometry*> QgsGeometry::asGeometryCollection() const
|
||||||
{
|
{
|
||||||
QList<QgsGeometry*> geometryList;
|
QList<QgsGeometry*> geometryList;
|
||||||
|
@ -480,9 +480,12 @@ class CORE_EXPORT QgsGeometry
|
|||||||
/** Returns a geometry representing the points making up this geometry that do not make up other. */
|
/** Returns a geometry representing the points making up this geometry that do not make up other. */
|
||||||
QgsGeometry* difference( const QgsGeometry* geometry ) const;
|
QgsGeometry* difference( const QgsGeometry* geometry ) const;
|
||||||
|
|
||||||
/** Returns a Geometry representing the points making up this Geometry that do not make up other. */
|
/** Returns a geometry representing the points making up this geometry that do not make up other. */
|
||||||
QgsGeometry* symDifference( const QgsGeometry* geometry ) const;
|
QgsGeometry* symDifference( const QgsGeometry* geometry ) const;
|
||||||
|
|
||||||
|
/** Returns an extruded version of this geometry. */
|
||||||
|
QgsGeometry extrude( double x, double y );
|
||||||
|
|
||||||
/** Exports the geometry to WKT
|
/** Exports the geometry to WKT
|
||||||
* @note precision parameter added in 2.4
|
* @note precision parameter added in 2.4
|
||||||
* @return true in case of success and false else
|
* @return true in case of success and false else
|
||||||
|
@ -13,8 +13,8 @@ email : marco.hugentobler at sourcepole dot com
|
|||||||
* *
|
* *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifndef QGSVECTORTOPOLOGY_H
|
#ifndef QGSGEOMETRYENGINE_H
|
||||||
#define QGSVECTORTOPOLOGY_H
|
#define QGSGEOMETRYENGINE_H
|
||||||
|
|
||||||
#include "qgspointv2.h"
|
#include "qgspointv2.h"
|
||||||
#include "qgslinestringv2.h"
|
#include "qgslinestringv2.h"
|
||||||
@ -106,4 +106,4 @@ class CORE_EXPORT QgsGeometryEngine
|
|||||||
QgsGeometryEngine();
|
QgsGeometryEngine();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // QGSVECTORTOPOLOGY_H
|
#endif // QGSGEOMETRYENGINE_H
|
||||||
|
88
src/core/geometry/qgsinternalgeometryengine.cpp
Normal file
88
src/core/geometry/qgsinternalgeometryengine.cpp
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
qgsinternalgeometryengine.cpp - QgsInternalGeometryEngine
|
||||||
|
|
||||||
|
---------------------
|
||||||
|
begin : 13.1.2016
|
||||||
|
copyright : (C) 2016 by Matthias Kuhn
|
||||||
|
email : matthias@opengis.ch
|
||||||
|
***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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 "qgsinternalgeometryengine.h"
|
||||||
|
|
||||||
|
#include "qgslinestringv2.h"
|
||||||
|
#include "qgsmultipolygonv2.h"
|
||||||
|
#include "qgspolygonv2.h"
|
||||||
|
#include "qgsmulticurvev2.h"
|
||||||
|
|
||||||
|
#include <QTransform>
|
||||||
|
|
||||||
|
QgsInternalGeometryEngine::QgsInternalGeometryEngine( const QgsGeometry& geometry )
|
||||||
|
: mGeometry( geometry.geometry() )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This class is considered CRITICAL and any change MUST be accompanied with
|
||||||
|
* full unit tests.
|
||||||
|
* See details in QEP #17
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
QgsGeometry QgsInternalGeometryEngine::extrude( double x, double y )
|
||||||
|
{
|
||||||
|
QList<QgsLineStringV2*> linesToProcess;
|
||||||
|
|
||||||
|
const QgsMultiCurveV2* multiCurve = dynamic_cast< const QgsMultiCurveV2* >( mGeometry );
|
||||||
|
if ( multiCurve )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < multiCurve->partCount(); ++i )
|
||||||
|
{
|
||||||
|
linesToProcess << static_cast<QgsLineStringV2*>( multiCurve->geometryN( i )->clone() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const QgsCurveV2* curve = dynamic_cast< const QgsCurveV2* >( mGeometry );
|
||||||
|
if ( curve )
|
||||||
|
{
|
||||||
|
linesToProcess << static_cast<QgsLineStringV2*>( curve->segmentize() );
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsMultiPolygonV2* multipolygon = linesToProcess.size() > 1 ? new QgsMultiPolygonV2() : nullptr;
|
||||||
|
QgsPolygonV2* polygon;
|
||||||
|
|
||||||
|
if ( !linesToProcess.empty() )
|
||||||
|
{
|
||||||
|
Q_FOREACH ( QgsLineStringV2* line, linesToProcess )
|
||||||
|
{
|
||||||
|
QTransform transform = QTransform::fromTranslate( x, y );
|
||||||
|
|
||||||
|
QgsLineStringV2* secondline = line->reversed();
|
||||||
|
secondline->transform( transform );
|
||||||
|
|
||||||
|
line->append( secondline );
|
||||||
|
line->addVertex( line->pointN( 0 ) );
|
||||||
|
|
||||||
|
polygon = new QgsPolygonV2();
|
||||||
|
polygon->setExteriorRing( line );
|
||||||
|
|
||||||
|
if ( multipolygon )
|
||||||
|
multipolygon->addGeometry( polygon );
|
||||||
|
|
||||||
|
delete secondline;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( multipolygon )
|
||||||
|
return QgsGeometry( multipolygon );
|
||||||
|
else
|
||||||
|
return QgsGeometry( polygon );
|
||||||
|
}
|
||||||
|
|
||||||
|
return QgsGeometry();
|
||||||
|
}
|
54
src/core/geometry/qgsinternalgeometryengine.h
Normal file
54
src/core/geometry/qgsinternalgeometryengine.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
qgsinternalgeometryengine.h - QgsInternalGeometryEngine
|
||||||
|
|
||||||
|
---------------------
|
||||||
|
begin : 13.1.2016
|
||||||
|
copyright : (C) 2016 by Matthias Kuhn
|
||||||
|
email : matthias@opengis.ch
|
||||||
|
***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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 QGSINTERNALGEOMETRYENGINE_H
|
||||||
|
#define QGSINTERNALGEOMETRYENGINE_H
|
||||||
|
|
||||||
|
#include "qgsgeometry.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class offers geometry processing methods.
|
||||||
|
*
|
||||||
|
* The methods are available via QgsGeometry::[geometryfunction]
|
||||||
|
* and therefore this does not need to be accessed directly.
|
||||||
|
*
|
||||||
|
* @note not available in Python bindings
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QgsInternalGeometryEngine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* The caller is responsible that the geometry is available and unchanged
|
||||||
|
* for the whole lifetime of this object.
|
||||||
|
* @param geometry
|
||||||
|
*/
|
||||||
|
QgsInternalGeometryEngine( const QgsGeometry& geometry );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will extrude a line or (segmentized) curve by a given offset and return a polygon
|
||||||
|
* representation of it.
|
||||||
|
*
|
||||||
|
* @param x offset in x direction
|
||||||
|
* @param y offset in y direction
|
||||||
|
* @return an extruded polygon
|
||||||
|
*/
|
||||||
|
QgsGeometry extrude( double x, double y );
|
||||||
|
|
||||||
|
private:
|
||||||
|
const QgsAbstractGeometryV2* mGeometry;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QGSINTERNALGEOMETRYENGINE_H
|
@ -2153,6 +2153,21 @@ static QVariant fcnAzimuth( const QVariantList& values, const QgsExpressionConte
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QVariant fcnExtrude( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
|
||||||
|
{
|
||||||
|
if ( values.length() != 3 )
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
|
||||||
|
double x = getDoubleValue( values.at( 1 ), parent );
|
||||||
|
double y = getDoubleValue( values.at( 2 ), parent );
|
||||||
|
|
||||||
|
QgsGeometry geom = fGeom.extrude( x, y );
|
||||||
|
|
||||||
|
QVariant result = geom.geometry() ? QVariant::fromValue( geom ) : QVariant();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static QVariant fcnRound( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
|
static QVariant fcnRound( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
|
||||||
{
|
{
|
||||||
if ( values.length() == 2 )
|
if ( values.length() == 2 )
|
||||||
@ -2915,6 +2930,7 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
|
|||||||
<< new StaticFunction( "geom_to_wkt", -1, fcnGeomToWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomToWKT" )
|
<< new StaticFunction( "geom_to_wkt", -1, fcnGeomToWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomToWKT" )
|
||||||
<< new StaticFunction( "geometry", 1, fcnGetGeometry, "GeometryGroup", QString(), true )
|
<< new StaticFunction( "geometry", 1, fcnGetGeometry, "GeometryGroup", QString(), true )
|
||||||
<< new StaticFunction( "transform", 3, fcnTransformGeometry, "GeometryGroup" )
|
<< new StaticFunction( "transform", 3, fcnTransformGeometry, "GeometryGroup" )
|
||||||
|
<< new StaticFunction( "extrude", 3, fcnExtrude, "GeometryGroup", QString() )
|
||||||
<< new StaticFunction( "$rownum", 0, fcnRowNumber, "deprecated" )
|
<< new StaticFunction( "$rownum", 0, fcnRowNumber, "deprecated" )
|
||||||
<< new StaticFunction( "$id", 0, fcnFeatureId, "Record" )
|
<< new StaticFunction( "$id", 0, fcnFeatureId, "Record" )
|
||||||
<< new StaticFunction( "$currentfeature", 0, fcnFeature, "Record" )
|
<< new StaticFunction( "$currentfeature", 0, fcnFeature, "Record" )
|
||||||
|
@ -280,7 +280,7 @@ class CORE_EXPORT QgsExpression
|
|||||||
QgsDistanceArea* geomCalculator();
|
QgsDistanceArea* geomCalculator();
|
||||||
|
|
||||||
//! Sets the geometry calculator used in evaluation of expressions,
|
//! Sets the geometry calculator used in evaluation of expressions,
|
||||||
// instead of the default.
|
//! instead of the default.
|
||||||
void setGeomCalculator( const QgsDistanceArea &calc );
|
void setGeomCalculator( const QgsDistanceArea &calc );
|
||||||
|
|
||||||
/** This function currently replaces each expression between [% and %]
|
/** This function currently replaces each expression between [% and %]
|
||||||
|
@ -345,7 +345,7 @@ class TestQgsGeometry(TestCase):
|
|||||||
'simplify_error.wkt'), 'rt')
|
'simplify_error.wkt'), 'rt')
|
||||||
myWKT = myWKTFile.readline()
|
myWKT = myWKTFile.readline()
|
||||||
myWKTFile.close()
|
myWKTFile.close()
|
||||||
print myWKT
|
# print myWKT
|
||||||
myGeometry = QgsGeometry().fromWkt(myWKT)
|
myGeometry = QgsGeometry().fromWkt(myWKT)
|
||||||
assert myGeometry is not None
|
assert myGeometry is not None
|
||||||
myStartLength = len(myWKT)
|
myStartLength = len(myWKT)
|
||||||
@ -1191,6 +1191,17 @@ class TestQgsGeometry(TestCase):
|
|||||||
expwkt = "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))"
|
expwkt = "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))"
|
||||||
wkt = polygon.exportToWkt()
|
wkt = polygon.exportToWkt()
|
||||||
|
|
||||||
|
def testExtrude(self):
|
||||||
|
points = [QgsPoint(1, 2), QgsPoint(3, 2), QgsPoint(4, 3)]
|
||||||
|
line = QgsGeometry.fromPolyline(points)
|
||||||
|
expected = QgsGeometry.fromWkt('Polygon ((1 2, 3 2, 4 3, 5 5, 4 4, 2 4, 1 2))')
|
||||||
|
self.assertEqual(line.extrude(1, 2).exportToWkt(), expected.exportToWkt())
|
||||||
|
|
||||||
|
points2 = [[QgsPoint(1, 2), QgsPoint(3, 2)], [QgsPoint(4, 3), QgsPoint(8, 3)]]
|
||||||
|
multiline = QgsGeometry.fromMultiPolyline(points2)
|
||||||
|
expected = QgsGeometry.fromWkt('MultiPolygon (((1 2, 3 2, 4 4, 2 4, 1 2)),((4 3, 8 3, 9 5, 5 5, 4 3)))')
|
||||||
|
self.assertEqual(multiline.extrude(1, 2).exportToWkt(), expected.exportToWkt())
|
||||||
|
|
||||||
def testBoundingBox(self):
|
def testBoundingBox(self):
|
||||||
# 2-+-+-+-+-3
|
# 2-+-+-+-+-3
|
||||||
# | |
|
# | |
|
||||||
|
Loading…
x
Reference in New Issue
Block a user