Skip to content

Commit 1e54799

Browse files
committed
[FEATURE][API] Add some nice PyQGIS methods and exceptions to QgsLineString
- len(QgsCurve) returns number of points in curve - raise IndexErrors when calling pointN, xAt, yAt, zAt, mAt, setXAt, setYAt, setMAt, setZAt with invalid vertex indices - Add [] getter for retrieving specific vertices, eg. ls[0] returns QgsPoint(...) - Add [] setter for setting specific (existing) vertices, e.g. ls[1] = QgsPoint(1,2) - Add del support for removing vertices, e.g. del ls[1] removes the second vertex
1 parent b5ad33f commit 1e54799

File tree

6 files changed

+511
-3
lines changed

6 files changed

+511
-3
lines changed

python/core/auto_generated/geometry/qgscurve.sip.in

+14
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,20 @@ Returns a list of points within the curve.
101101
Returns the number of points in the curve.
102102
%End
103103

104+
int __len__() const;
105+
%Docstring
106+
Returns the number of points in the curve.
107+
%End
108+
%MethodCode
109+
sipRes = sipCpp->numPoints();
110+
%End
111+
112+
//! Ensures that bool(obj) returns true (otherwise __len__() would be used)
113+
int __bool__() const;
114+
%MethodCode
115+
sipRes = true;
116+
%End
117+
104118
virtual void sumUpArea( double &sum /Out/ ) const = 0;
105119
%Docstring
106120
Sums up the area of the curve by iterating over the vertices (shoelace formula).

python/core/auto_generated/geometry/qgslinestring.sip.in

+161-1
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,52 @@ Construct a linestring from a single 2d line segment.
8181
virtual bool equals( const QgsCurve &other ) const;
8282

8383

84-
QgsPoint pointN( int i ) const;
84+
SIP_PYOBJECT pointN( int i ) const;
8585
%Docstring
8686
Returns the specified point from inside the line string.
8787

8888
:param i: index of point, starting at 0 for the first point
89+
%End
90+
%MethodCode
91+
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
92+
{
93+
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
94+
sipIsErr = 1;
95+
}
96+
else
97+
{
98+
std::unique_ptr< QgsPoint > p = qgis::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
99+
sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
100+
}
89101
%End
90102

91103
virtual double xAt( int index ) const;
92104

105+
%MethodCode
106+
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
107+
{
108+
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
109+
sipIsErr = 1;
110+
}
111+
else
112+
{
113+
return PyFloat_FromDouble( sipCpp->xAt( a0 ) );
114+
}
115+
%End
116+
93117
virtual double yAt( int index ) const;
94118

119+
%MethodCode
120+
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
121+
{
122+
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
123+
sipIsErr = 1;
124+
}
125+
else
126+
{
127+
return PyFloat_FromDouble( sipCpp->yAt( a0 ) );
128+
}
129+
%End
95130

96131

97132

@@ -107,6 +142,17 @@ Returns the z-coordinate of the specified node in the line string.
107142
does not have a z dimension
108143

109144
.. seealso:: :py:func:`setZAt`
145+
%End
146+
%MethodCode
147+
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
148+
{
149+
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
150+
sipIsErr = 1;
151+
}
152+
else
153+
{
154+
return PyFloat_FromDouble( sipCpp->zAt( a0 ) );
155+
}
110156
%End
111157

112158
double mAt( int index ) const;
@@ -119,6 +165,17 @@ Returns the m value of the specified node in the line string.
119165
does not have m values
120166

121167
.. seealso:: :py:func:`setMAt`
168+
%End
169+
%MethodCode
170+
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
171+
{
172+
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
173+
sipIsErr = 1;
174+
}
175+
else
176+
{
177+
return PyFloat_FromDouble( sipCpp->mAt( a0 ) );
178+
}
122179
%End
123180

124181
void setXAt( int index, double x );
@@ -130,6 +187,17 @@ Sets the x-coordinate of the specified node in the line string.
130187
:param x: x-coordinate of node
131188

132189
.. seealso:: :py:func:`xAt`
190+
%End
191+
%MethodCode
192+
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
193+
{
194+
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
195+
sipIsErr = 1;
196+
}
197+
else
198+
{
199+
sipCpp->setXAt( a0, a1 );
200+
}
133201
%End
134202

135203
void setYAt( int index, double y );
@@ -141,6 +209,17 @@ Sets the y-coordinate of the specified node in the line string.
141209
:param y: y-coordinate of node
142210

143211
.. seealso:: :py:func:`yAt`
212+
%End
213+
%MethodCode
214+
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
215+
{
216+
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
217+
sipIsErr = 1;
218+
}
219+
else
220+
{
221+
sipCpp->setYAt( a0, a1 );
222+
}
144223
%End
145224

146225
void setZAt( int index, double z );
@@ -152,6 +231,17 @@ Sets the z-coordinate of the specified node in the line string.
152231
:param z: z-coordinate of node
153232

154233
.. seealso:: :py:func:`zAt`
234+
%End
235+
%MethodCode
236+
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
237+
{
238+
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
239+
sipIsErr = 1;
240+
}
241+
else
242+
{
243+
sipCpp->setZAt( a0, a1 );
244+
}
155245
%End
156246

157247
void setMAt( int index, double m );
@@ -163,6 +253,17 @@ Sets the m value of the specified node in the line string.
163253
:param m: m value of node
164254

165255
.. seealso:: :py:func:`mAt`
256+
%End
257+
%MethodCode
258+
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
259+
{
260+
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
261+
sipIsErr = 1;
262+
}
263+
else
264+
{
265+
sipCpp->setMAt( a0, a1 );
266+
}
166267
%End
167268

168269
void setPoints( const QgsPointSequence &points );
@@ -333,6 +434,65 @@ of the curve.
333434
sipRes = PyUnicode_FromString( str.toUtf8().constData() );
334435
%End
335436

437+
SIP_PYOBJECT __getitem__( int index );
438+
%Docstring
439+
Returns the point at the specified ``index``. An IndexError will be raised if no point with the specified ``index`` exists.
440+
441+
.. versionadded:: 3.6
442+
%End
443+
%MethodCode
444+
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
445+
{
446+
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
447+
sipIsErr = 1;
448+
}
449+
else
450+
{
451+
std::unique_ptr< QgsPoint > p = qgis::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
452+
sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
453+
}
454+
%End
455+
456+
void __setitem__( int index, const QgsPoint &point );
457+
%Docstring
458+
Sets the point at the specified ``index``. A point at the ``index`` must already exist or an IndexError will be raised.
459+
460+
.. versionadded:: 3.6
461+
%End
462+
%MethodCode
463+
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
464+
{
465+
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
466+
sipIsErr = 1;
467+
}
468+
else
469+
{
470+
sipCpp->setXAt( a0, a1->x() );
471+
sipCpp->setYAt( a0, a1->y() );
472+
if ( sipCpp->isMeasure() )
473+
sipCpp->setMAt( a0, a1->m() );
474+
if ( sipCpp->is3D() )
475+
sipCpp->setZAt( a0, a1->z() );
476+
}
477+
%End
478+
479+
void __delitem__( int index );
480+
%Docstring
481+
Deletes the vertex at the specified ``index``. A point at the ``index`` must already exist or an IndexError will be raised.
482+
483+
.. versionadded:: 3.6
484+
%End
485+
%MethodCode
486+
if ( a0 >= 0 && a0 < sipCpp->numPoints() )
487+
sipCpp->deleteVertex( QgsVertexId( -1, -1, a0 ) );
488+
else
489+
{
490+
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
491+
sipIsErr = 1;
492+
}
493+
%End
494+
495+
336496
protected:
337497

338498
virtual QgsRectangle calculateBoundingBox() const;

scripts/sipify.pl

+2-2
Original file line numberDiff line numberDiff line change
@@ -520,14 +520,14 @@ sub detect_non_method_member{
520520
}
521521

522522
# do not process SIP code %XXXCode
523-
if ( $SIP_RUN == 1 && $LINE =~ m/^ *% *(VirtualErrorHandler|MappedType|Type(?:Header)?Code|Module(?:Header)?Code|Convert(?:From|To)(?:Type|SubClass)Code|MethodCode)(.*)?$/ ){
523+
if ( $SIP_RUN == 1 && $LINE =~ m/^ *% *(VirtualErrorHandler|MappedType|Type(?:Header)?Code|Module(?:Header)?Code|Convert(?:From|To)(?:Type|SubClass)Code|MethodCode|Docstring)(.*)?$/ ){
524524
$LINE = "%$1$2";
525525
$COMMENT = '';
526526
dbg_info("do not process SIP code");
527527
while ( $LINE !~ m/^ *% *End/ ){
528528
write_output("COD", $LINE."\n");
529529
$LINE = read_line();
530-
$LINE =~ s/^ *% *(VirtualErrorHandler|MappedType|Type(?:Header)?Code|Module(?:Header)?Code|Convert(?:From|To)(?:Type|SubClass)Code|MethodCode)(.*)?$/%$1$2/;
530+
$LINE =~ s/^ *% *(VirtualErrorHandler|MappedType|Type(?:Header)?Code|Module(?:Header)?Code|Convert(?:From|To)(?:Type|SubClass)Code|MethodCode|Docstring)(.*)?$/%$1$2/;
531531
$LINE =~ s/^\s*SIP_END(.*)$/%End$1/;
532532
}
533533
$LINE =~ s/^\s*% End/%End/;

src/core/geometry/qgscurve.h

+16
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,22 @@ class CORE_EXPORT QgsCurve: public QgsAbstractGeometry
106106
*/
107107
virtual int numPoints() const = 0;
108108

109+
#ifdef SIP_RUN
110+
int __len__() const;
111+
% Docstring
112+
Returns the number of points in the curve.
113+
% End
114+
% MethodCode
115+
sipRes = sipCpp->numPoints();
116+
% End
117+
118+
//! Ensures that bool(obj) returns true (otherwise __len__() would be used)
119+
int __bool__() const;
120+
% MethodCode
121+
sipRes = true;
122+
% End
123+
#endif
124+
109125
/**
110126
* Sums up the area of the curve by iterating over the vertices (shoelace formula).
111127
*/

0 commit comments

Comments
 (0)