Skip to content

Commit 3eea922

Browse files
committed
Negative indices count from back of linestring
(cherry picked from commit f595d53)
1 parent 6e84756 commit 3eea922

File tree

3 files changed

+434
-126
lines changed

3 files changed

+434
-126
lines changed

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

Lines changed: 151 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -81,188 +81,259 @@ Construct a linestring from a single 2d line segment.
8181
virtual bool equals( const QgsCurve &other ) const;
8282

8383

84+
8485
SIP_PYOBJECT pointN( int i ) const;
8586
%Docstring
86-
Returns the specified point from inside the line string.
87+
Returns the point at the specified index. An IndexError will be raised if no point with the specified index exists.
8788

88-
:param i: index of point, starting at 0 for the first point
89+
Indexes can be less than 0, in which case they correspond to positions from the end of the line. E.g. an index of -1
90+
corresponds to the last point in the line.
8991
%End
9092
%MethodCode
91-
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
93+
const int count = sipCpp->numPoints();
94+
if ( a0 < -count || a0 >= count )
9295
{
9396
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
9497
sipIsErr = 1;
9598
}
9699
else
97100
{
98-
std::unique_ptr< QgsPoint > p = qgis::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
101+
std::unique_ptr< QgsPoint > p;
102+
if ( a0 >= 0 )
103+
p = qgis::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
104+
else // negative index, count backwards from end
105+
p = qgis::make_unique< QgsPoint >( sipCpp->pointN( count + a0 ) );
99106
sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
100107
}
101108
%End
102109

110+
103111
virtual double xAt( int index ) const;
104112

113+
%Docstring
114+
Returns the x-coordinate of the specified node in the line string.
115+
116+
An IndexError will be raised if no point with the specified index exists.
117+
118+
Indexes can be less than 0, in which case they correspond to positions from the end of the line. E.g. an index of -1
119+
corresponds to the last point in the line.
120+
%End
105121
%MethodCode
106-
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
122+
const int count = sipCpp->numPoints();
123+
if ( a0 < -count || a0 >= count )
107124
{
108125
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
109126
sipIsErr = 1;
110127
}
111128
else
112129
{
113-
return PyFloat_FromDouble( sipCpp->xAt( a0 ) );
130+
if ( a0 >= 0 )
131+
return PyFloat_FromDouble( sipCpp->xAt( a0 ) );
132+
else
133+
return PyFloat_FromDouble( sipCpp->xAt( count + a0 ) );
114134
}
115135
%End
116136

137+
117138
virtual double yAt( int index ) const;
118139

140+
%Docstring
141+
Returns the y-coordinate of the specified node in the line string.
142+
143+
An IndexError will be raised if no point with the specified index exists.
144+
145+
Indexes can be less than 0, in which case they correspond to positions from the end of the line. E.g. an index of -1
146+
corresponds to the last point in the line.
147+
%End
119148
%MethodCode
120-
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
149+
const int count = sipCpp->numPoints();
150+
if ( a0 < -count || a0 >= count )
121151
{
122152
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
123153
sipIsErr = 1;
124154
}
125155
else
126156
{
127-
return PyFloat_FromDouble( sipCpp->yAt( a0 ) );
157+
if ( a0 >= 0 )
158+
return PyFloat_FromDouble( sipCpp->yAt( a0 ) );
159+
else
160+
return PyFloat_FromDouble( sipCpp->yAt( count + a0 ) );
128161
}
129162
%End
130163

131164

132165

133166

134167

168+
135169
double zAt( int index ) const;
136170
%Docstring
137171
Returns the z-coordinate of the specified node in the line string.
138172

139-
:param index: index of node, where the first node in the line is 0
173+
An IndexError will be raised if no point with the specified index exists.
140174

141-
:return: z-coordinate of node, or ``nan`` if index is out of bounds or the line
142-
does not have a z dimension
175+
If the LineString does not have a z-dimension then ``nan`` will be returned.
143176

144-
.. seealso:: :py:func:`setZAt`
177+
Indexes can be less than 0, in which case they correspond to positions from the end of the line. E.g. an index of -1
178+
corresponds to the last point in the line.
145179
%End
146180
%MethodCode
147-
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
181+
const int count = sipCpp->numPoints();
182+
if ( a0 < -count || a0 >= count )
148183
{
149184
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
150185
sipIsErr = 1;
151186
}
152187
else
153188
{
154-
return PyFloat_FromDouble( sipCpp->zAt( a0 ) );
189+
if ( a0 >= 0 )
190+
return PyFloat_FromDouble( sipCpp->zAt( a0 ) );
191+
else
192+
return PyFloat_FromDouble( sipCpp->zAt( count + a0 ) );
155193
}
156194
%End
157195

196+
158197
double mAt( int index ) const;
159198
%Docstring
160-
Returns the m value of the specified node in the line string.
199+
Returns the m-coordinate of the specified node in the line string.
161200

162-
:param index: index of node, where the first node in the line is 0
201+
An IndexError will be raised if no point with the specified index exists.
163202

164-
:return: m value of node, or ``nan`` if index is out of bounds or the line
165-
does not have m values
203+
If the LineString does not have a m-dimension then ``nan`` will be returned.
166204

167-
.. seealso:: :py:func:`setMAt`
205+
Indexes can be less than 0, in which case they correspond to positions from the end of the line. E.g. an index of -1
206+
corresponds to the last point in the line.
168207
%End
169208
%MethodCode
170-
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
209+
const int count = sipCpp->numPoints();
210+
if ( a0 < -count || a0 >= count )
171211
{
172212
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
173213
sipIsErr = 1;
174214
}
175215
else
176216
{
177-
return PyFloat_FromDouble( sipCpp->mAt( a0 ) );
217+
if ( a0 >= 0 )
218+
return PyFloat_FromDouble( sipCpp->mAt( a0 ) );
219+
else
220+
return PyFloat_FromDouble( sipCpp->mAt( count + a0 ) );
178221
}
179222
%End
180223

224+
181225
void setXAt( int index, double x );
182226
%Docstring
183227
Sets the x-coordinate of the specified node in the line string.
228+
The corresponding node must already exist in line string.
229+
230+
An IndexError will be raised if no point with the specified index exists.
184231

185-
:param index: index of node, where the first node in the line is 0. Corresponding
186-
node must already exist in line string.
187-
:param x: x-coordinate of node
232+
Indexes can be less than 0, in which case they correspond to positions from the end of the line. E.g. an index of -1
233+
corresponds to the last point in the line.
188234

189235
.. seealso:: :py:func:`xAt`
190236
%End
191237
%MethodCode
192-
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
238+
const int count = sipCpp->numPoints();
239+
if ( a0 < -count || a0 >= count )
193240
{
194241
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
195242
sipIsErr = 1;
196243
}
197244
else
198245
{
199-
sipCpp->setXAt( a0, a1 );
246+
if ( a0 >= 0 )
247+
sipCpp->setXAt( a0, a1 );
248+
else
249+
sipCpp->setXAt( count + a0, a1 );
200250
}
201251
%End
202252

253+
203254
void setYAt( int index, double y );
204255
%Docstring
205256
Sets the y-coordinate of the specified node in the line string.
257+
The corresponding node must already exist in line string.
206258

207-
:param index: index of node, where the first node in the line is 0. Corresponding
208-
node must already exist in line string.
209-
:param y: y-coordinate of node
259+
An IndexError will be raised if no point with the specified index exists.
260+
261+
Indexes can be less than 0, in which case they correspond to positions from the end of the line. E.g. an index of -1
262+
corresponds to the last point in the line.
210263

211264
.. seealso:: :py:func:`yAt`
212265
%End
213266
%MethodCode
214-
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
267+
const int count = sipCpp->numPoints();
268+
if ( a0 < -count || a0 >= count )
215269
{
216270
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
217271
sipIsErr = 1;
218272
}
219273
else
220274
{
221-
sipCpp->setYAt( a0, a1 );
275+
if ( a0 >= 0 )
276+
sipCpp->setYAt( a0, a1 );
277+
else
278+
sipCpp->setYAt( count + a0, a1 );
222279
}
223280
%End
224281

282+
225283
void setZAt( int index, double z );
226284
%Docstring
227285
Sets the z-coordinate of the specified node in the line string.
286+
The corresponding node must already exist in line string and the line string must have z-dimension.
228287

229-
:param index: index of node, where the first node in the line is 0. Corresponding
230-
node must already exist in line string, and the line string must have z-dimension.
231-
:param z: z-coordinate of node
288+
An IndexError will be raised if no point with the specified index exists.
289+
290+
Indexes can be less than 0, in which case they correspond to positions from the end of the line. E.g. an index of -1
291+
corresponds to the last point in the line.
232292

233293
.. seealso:: :py:func:`zAt`
234294
%End
235295
%MethodCode
236-
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
296+
const int count = sipCpp->numPoints();
297+
if ( a0 < -count || a0 >= count )
237298
{
238299
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
239300
sipIsErr = 1;
240301
}
241302
else
242303
{
243-
sipCpp->setZAt( a0, a1 );
304+
if ( a0 >= 0 )
305+
sipCpp->setZAt( a0, a1 );
306+
else
307+
sipCpp->setZAt( count + a0, a1 );
244308
}
245309
%End
246310

311+
247312
void setMAt( int index, double m );
248313
%Docstring
249-
Sets the m value of the specified node in the line string.
314+
Sets the m-coordinate of the specified node in the line string.
315+
The corresponding node must already exist in line string and the line string must have m-dimension.
316+
317+
An IndexError will be raised if no point with the specified index exists.
250318

251-
:param index: index of node, where the first node in the line is 0. Corresponding
252-
node must already exist in line string, and the line string must have m values.
253-
:param m: m value of node
319+
Indexes can be less than 0, in which case they correspond to positions from the end of the line. E.g. an index of -1
320+
corresponds to the last point in the line.
254321

255322
.. seealso:: :py:func:`mAt`
256323
%End
257324
%MethodCode
258-
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
325+
const int count = sipCpp->numPoints();
326+
if ( a0 < -count || a0 >= count )
259327
{
260328
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
261329
sipIsErr = 1;
262330
}
263331
else
264332
{
265-
sipCpp->setMAt( a0, a1 );
333+
if ( a0 >= 0 )
334+
sipCpp->setMAt( a0, a1 );
335+
else
336+
sipCpp->setMAt( count + a0, a1 );
266337
}
267338
%End
268339

@@ -439,37 +510,51 @@ of the curve.
439510

440511
SIP_PYOBJECT __getitem__( int index );
441512
%Docstring
442-
Returns the point at the specified ``index``. An IndexError will be raised if no point with the specified ``index`` exists.
513+
Returns the point at the specified ``index``. An IndexError will be raised if no point with the specified ``index`` exists.
443514

444-
.. versionadded:: 3.6
515+
Indexes can be less than 0, in which case they correspond to positions from the end of the line. E.g. an index of -1
516+
corresponds to the last point in the line.
517+
518+
.. versionadded:: 3.6
445519
%End
446520
%MethodCode
447-
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
448-
{
449-
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
450-
sipIsErr = 1;
451-
}
521+
const int count = sipCpp->numPoints();
522+
if ( a0 < -count || a0 >= count )
523+
{
524+
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
525+
sipIsErr = 1;
526+
}
527+
else
528+
{
529+
std::unique_ptr< QgsPoint > p;
530+
if ( a0 >= 0 )
531+
p = qgis::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
452532
else
453-
{
454-
std::unique_ptr< QgsPoint > p = qgis::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
455-
sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
456-
}
533+
p = qgis::make_unique< QgsPoint >( sipCpp->pointN( count + a0 ) );
534+
sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
535+
}
457536
%End
458537

459538
void __setitem__( int index, const QgsPoint &point );
460539
%Docstring
461-
Sets the point at the specified ``index``. A point at the ``index`` must already exist or an IndexError will be raised.
540+
Sets the point at the specified ``index``. A point at the ``index`` must already exist or an IndexError will be raised.
541+
542+
Indexes can be less than 0, in which case they correspond to positions from the end of the line. E.g. an index of -1
543+
corresponds to the last point in the line.
462544

463-
.. versionadded:: 3.6
545+
.. versionadded:: 3.6
464546
%End
465547
%MethodCode
466-
if ( a0 < 0 || a0 >= sipCpp->numPoints() )
548+
const int count = sipCpp->numPoints();
549+
if ( a0 < -count || a0 >= count )
467550
{
468551
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
469552
sipIsErr = 1;
470553
}
471554
else
472555
{
556+
if ( a0 < 0 )
557+
a0 = count + a0;
473558
sipCpp->setXAt( a0, a1->x() );
474559
sipCpp->setYAt( a0, a1->y() );
475560
if ( sipCpp->isMeasure() )
@@ -479,15 +564,22 @@ of the curve.
479564
}
480565
%End
481566

567+
482568
void __delitem__( int index );
483569
%Docstring
484-
Deletes the vertex at the specified ``index``. A point at the ``index`` must already exist or an IndexError will be raised.
570+
Deletes the vertex at the specified ``index``. A point at the ``index`` must already exist or an IndexError will be raised.
571+
572+
Indexes can be less than 0, in which case they correspond to positions from the end of the line. E.g. an index of -1
573+
corresponds to the last point in the line.
485574

486-
.. versionadded:: 3.6
575+
.. versionadded:: 3.6
487576
%End
488577
%MethodCode
489-
if ( a0 >= 0 && a0 < sipCpp->numPoints() )
578+
const int count = sipCpp->numPoints();
579+
if ( a0 >= 0 && a0 < count )
490580
sipCpp->deleteVertex( QgsVertexId( -1, -1, a0 ) );
581+
else if ( a0 < 0 && a0 >= -count )
582+
sipCpp->deleteVertex( QgsVertexId( -1, -1, count + a0 ) );
491583
else
492584
{
493585
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );

0 commit comments

Comments
 (0)