Skip to content

Commit 7e01602

Browse files
committed
- Fix crash for QgsMapToolCircle3Tangents when segment is not activated
or segments are parallels. - Add preconditions for methods of QgsTriangle when is empty or invalid. Tests and docs are updated.
1 parent c66b893 commit 7e01602

File tree

6 files changed

+366
-59
lines changed

6 files changed

+366
-59
lines changed

python/core/geometry/qgstriangle.sip

Lines changed: 130 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -109,25 +109,39 @@ Inherited method not used. You cannot delete or insert a vertex directly. Return
109109
QVector<double> lengths() const;
110110
%Docstring
111111
Returns the three lengths of the triangle.
112-
:return: Lengths of triangle ABC where [AB] is at 0, [BC] is at 1, [CA] is at 2
112+
:return: Lengths of triangle ABC where [AB] is at 0, [BC] is at 1, [CA] is at 2.
113+
An empty list is returned for empty or invalid triangle.
113114
* Example:
114115
\code{.py}
115116
tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
116117
tri.lengths()
117118
# [5.0, 5.0, 7.0710678118654755]
119+
QgsTriangle().lengths()
120+
# []
121+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).lengths()
122+
# []
123+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).lengths()
124+
# []
118125
\endcode
119126
:rtype: list of float
120127
%End
121128

122129
QVector<double> angles() const;
123130
%Docstring
124131
Returns the three angles of the triangle.
125-
:return: Angles in radians of triangle ABC where angle BAC is at 0, angle ABC is at 1, angle BCA is at 2
132+
:return: Angles in radians of triangle ABC where angle BAC is at 0, angle ABC is at 1, angle BCA is at 2.
133+
An empty list is returned for empty or invalid triangle.
126134
* Example:
127135
\code{.py}
128136
tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
129137
[math.degrees(i) for i in tri.angles()]
130138
# [45.0, 90.0, 45.0]
139+
QgsTriangle().angles()
140+
# []
141+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).angles()
142+
# []
143+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).angles()
144+
# []
131145
\endcode
132146
:rtype: list of float
133147
%End
@@ -136,7 +150,7 @@ Inherited method not used. You cannot delete or insert a vertex directly. Return
136150
%Docstring
137151
Is the triangle isocele (two sides with the same length)?
138152
\param lengthTolerance The tolerance to use
139-
:return: True or False
153+
:return: True or False. Always false for empty or invalid triangle.
140154
* Example:
141155
\code{.py}
142156
tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
@@ -145,6 +159,12 @@ Inherited method not used. You cannot delete or insert a vertex directly. Return
145159
tri.isIsocele()
146160
# True
147161
# length of [AB] == length of [BC]
162+
QgsTriangle().isIsocele()
163+
# False
164+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).isIsocele()
165+
# False
166+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).isIsocele()
167+
# False
148168
\endcode
149169
:rtype: bool
150170
%End
@@ -153,7 +173,7 @@ Inherited method not used. You cannot delete or insert a vertex directly. Return
153173
%Docstring
154174
Is the triangle equilateral (three sides with the same length)?
155175
\param lengthTolerance The tolerance to use
156-
:return: True or False
176+
:return: True or False. Always false for empty or invalid triangle.
157177
* Example:
158178
\code{.py}
159179
tri = QgsTriangle( QgsPoint( 10, 10 ), QgsPoint( 16, 10 ), QgsPoint( 13, 15.1962 ) )
@@ -162,6 +182,12 @@ Inherited method not used. You cannot delete or insert a vertex directly. Return
162182
tri.isEquilateral()
163183
# True
164184
# All lengths are close to 6.0
185+
QgsTriangle().isEquilateral()
186+
# False
187+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).isEquilateral()
188+
# False
189+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).isEquilateral()
190+
# False
165191
\endcode
166192
:rtype: bool
167193
%End
@@ -170,7 +196,7 @@ Inherited method not used. You cannot delete or insert a vertex directly. Return
170196
%Docstring
171197
Is the triangle right-angled?
172198
\param angleTolerance The tolerance to use
173-
:return: True or False
199+
:return: True or False. Always false for empty or invalid triangle.
174200
* Example:
175201
\code{.py}
176202
tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
@@ -179,6 +205,12 @@ Inherited method not used. You cannot delete or insert a vertex directly. Return
179205
tri.isRight()
180206
# True
181207
# angle of ABC == 90
208+
QgsTriangle().isRight()
209+
# False
210+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).isRight()
211+
# False
212+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).isRight()
213+
# False
182214
\endcode
183215
:rtype: bool
184216
%End
@@ -187,8 +219,7 @@ Inherited method not used. You cannot delete or insert a vertex directly. Return
187219
%Docstring
188220
Is the triangle scalene (all sides have differen lengths)?
189221
\param lengthTolerance The tolerance to use
190-
:return: True or False
191-
:return: True or False
222+
:return: True or False. Always false for empty or invalid triangle.
192223
* Example:
193224
\code{.py}
194225
tri = QgsTriangle( QgsPoint( 7.2825, 4.2368 ), QgsPoint( 13.0058, 3.3218 ), QgsPoint( 9.2145, 6.5242 ) )
@@ -197,59 +228,93 @@ Inherited method not used. You cannot delete or insert a vertex directly. Return
197228
tri.isScalene()
198229
# True
199230
# All lengths are different
231+
QgsTriangle().isScalene()
232+
# False
233+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).isScalene()
234+
# False
235+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).isScalene()
236+
# False
200237
\endcode
201238
:rtype: bool
202239
%End
203240

204241
QVector<QgsLineString> altitudes() const;
205242
%Docstring
206243
An altitude is a segment (defined by a QgsLineString) from a vertex to the opposite side (or, if necessary, to the extension of the opposite side).
207-
:return: Three altitudes from this triangle
244+
:return: Three altitudes from this triangle.
245+
An empty list is returned for empty or invalid triangle.
208246
* Example:
209247
\code{.py}
210248
tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
211249
[alt.asWkt() for alt in tri.altitudes()]
212250
# ['LineString (0 0, 0 5)', 'LineString (0 5, 2.5 2.5)', 'LineString (5 5, 0 5)']
251+
QgsTriangle().altitudes()
252+
# []
253+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).altitudes()
254+
# []
255+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).altitudes()
256+
# []
213257
\endcode
214258
:rtype: list of QgsLineString
215259
%End
216260

217261
QVector<QgsLineString> medians() const;
218262
%Docstring
219263
A median is a segment (defined by a QgsLineString) from a vertex to the midpoint of the opposite side.
220-
:return: Three medians from this triangle
264+
:return: Three medians from this triangle.
265+
An empty list is returned for empty or invalid triangle.
221266
* Example:
222267
\code{.py}
223268
tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
224269
[med.asWkt() for med in tri.medians()]
225270
# ['LineString (0 0, 2.5 5)', 'LineString (0 5, 2.5 2.5)', 'LineString (5 5, 0 2.5)']
271+
QgsTriangle().medians()
272+
# []
273+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).medians()
274+
# []
275+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).medians()
276+
# []
226277
\endcode
227278
:rtype: list of QgsLineString
228279
%End
229280

230281
QVector<QgsLineString> bisectors( double lengthTolerance = 0.0001 ) const;
231282
%Docstring
232283
The segment (defined by a QgsLineString) returned bisect the angle of a vertex to the opposite side.
233-
\param lengthTolerance The tolerance to use
234-
:return: Three angle bisector from this triangle
284+
\param lengthTolerance The tolerance to use.
285+
:return: Three angle bisector from this triangle.
286+
An empty list is returned for empty or invalid triangle.
235287
* Example:
236288
\code{.py}
237289
tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
238290
[bis.asWkt() for bis in tri.bisectors()]
239291
# ['LineString (0 0, 2.07106781186547462 5)', 'LineString (0 5, 2.5 2.5)', 'LineString (5 5, 0 2.92893218813452538)']
292+
QgsTriangle().bisectors()
293+
# []
294+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).bisectors()
295+
# []
296+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).bisectors()
297+
# []
240298
\endcode
241299
:rtype: list of QgsLineString
242300
%End
243301

244302
QgsTriangle medial() const;
245303
%Docstring
246304
Medial (or midpoint) triangle of a triangle ABC is the triangle with vertices at the midpoints of the triangle's sides.
247-
:return: The medial from this triangle
305+
:return: The medial from this triangle.
306+
An empty triangle is returned for empty or invalid triangle.
248307
* Example:
249308
\code{.py}
250309
tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
251310
tri.medial().asWkt()
252311
# 'Triangle ((0 2.5, 2.5 5, 2.5 2.5, 0 2.5))'
312+
QgsTriangle().medial().asWkt()
313+
# 'Triangle ( )'
314+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).medial().asWkt()
315+
# 'Triangle ( )'
316+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).medial().asWkt()
317+
# 'Triangle ( )'
253318
\endcode
254319
:rtype: QgsTriangle
255320
%End
@@ -259,37 +324,58 @@ Inherited method not used. You cannot delete or insert a vertex directly. Return
259324
An orthocenter is the point of intersection of the altitudes of a triangle.
260325
\param lengthTolerance The tolerance to use
261326
:return: The orthocenter of the triangle.
327+
An empty point is returned for empty or invalid triangle.
262328
* Example:
263329
\code{.py}
264330
tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
265331
tri.orthocenter().asWkt()
266332
# 'Point (0 5)'
333+
QgsTriangle().orthocenter().asWkt()
334+
# 'Point (0 0)'
335+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).orthocenter().asWkt()
336+
# 'Point (0 0)'
337+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).orthocenter().asWkt()
338+
# 'Point (0 0)'
267339
\endcode
268340
:rtype: QgsPoint
269341
%End
270342

271343
QgsPoint circumscribedCenter() const;
272344
%Docstring
273345
Center of the circumscribed circle of the triangle.
274-
:return: The center of the circumscribed circle of the triangle
346+
:return: The center of the circumscribed circle of the triangle.
347+
An empty point is returned for empty or invalid triangle.
275348
* Example:
276349
\code{.py}
277350
tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
278351
tri.circumscribedCenter().asWkt()
279352
# 'Point (2.5 2.5)'
353+
QgsTriangle().circumscribedCenter().asWkt()
354+
# 'Point (0 0)'
355+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).circumscribedCenter().asWkt()
356+
# 'Point (0 0)'
357+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).circumscribedCenter().asWkt()
358+
# 'Point (0 0)'
280359
\endcode
281360
:rtype: QgsPoint
282361
%End
283362

284363
double circumscribedRadius() const;
285364
%Docstring
286365
Radius of the circumscribed circle of the triangle.
287-
:return: The radius of the circumscribed circle of the triangle
366+
:return: The radius of the circumscribed circle of the triangle.
367+
0.0 is returned for empty or invalid triangle.
288368
* Example:
289369
\code{.py}
290370
tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
291371
tri.circumscribedRadius()
292372
# 3.5355339059327378
373+
QgsTriangle().circumscribedRadius()
374+
# 0.0
375+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).circumscribedRadius()
376+
# 0.0
377+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).circumscribedRadius()
378+
# 0.0
293379
\endcode
294380
:rtype: float
295381
%End
@@ -298,37 +384,58 @@ Inherited method not used. You cannot delete or insert a vertex directly. Return
298384
%Docstring
299385
Circumscribed circle of the triangle.
300386
@return The circumbscribed of the triangle with a QgsCircle.
387+
An empty circle is returned for empty or invalid triangle.
301388
Example:
302389
\code{.py}
303390
tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
304391
tri.circumscribedCircle()
305392
# QgsCircle(Point (2.5 2.5), 3.5355339059327378, 0)
393+
QgsTriangle().circumscribedCircle()
394+
# QgsCircle()
395+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).circumscribedCircle()
396+
# QgsCircle()
397+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).circumscribedCircle()
398+
# QgsCircle()
306399
\endcode
307400
:rtype: QgsCircle
308401
%End
309402

310403
QgsPoint inscribedCenter() const;
311404
%Docstring
312405
Center of the inscribed circle of the triangle.
313-
:return: The center of the inscribed circle of the triangle
406+
:return: The center of the inscribed circle of the triangle.
407+
An empty point is returned for empty or invalid triangle.
314408
* Example:
315409
\code{.py}
316410
tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
317411
tri.inscribedCenter().asWkt()
318412
# 'Point (1.46446609406726225 3.53553390593273775)'
413+
QgsTriangle().inscribedCenter().asWkt()
414+
# 'Point (0 0)'
415+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).inscribedCenter().asWkt()
416+
# 'Point (0 0)'
417+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).inscribedCenter().asWkt()
418+
# 'Point (0 0)'
319419
\endcode
320420
:rtype: QgsPoint
321421
%End
322422

323423
double inscribedRadius() const;
324424
%Docstring
325425
Radius of the inscribed circle of the triangle.
326-
:return: The radius of the inscribed circle of the triangle
426+
:return: The radius of the inscribed circle of the triangle.
427+
0.0 is returned for empty or invalid triangle.
327428
* Example:
328429
\code{.py}
329430
tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
330431
tri.inscribedRadius()
331432
# 1.4644660940672622
433+
QgsTriangle().inscribedRadius()
434+
# 0.0
435+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).inscribedRadius()
436+
# 0.0
437+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).inscribedRadius()
438+
# 0.0
332439
\endcode
333440
:rtype: float
334441
%End
@@ -337,11 +444,18 @@ Inherited method not used. You cannot delete or insert a vertex directly. Return
337444
%Docstring
338445
Inscribed circle of the triangle.
339446
@return The inscribed of the triangle with a QgsCircle.
447+
An empty circle is returned for empty or invalid triangle.
340448
Example:
341449
\code{.py}
342450
tri = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) )
343451
tri.inscribedCircle()
344452
# QgsCircle(Point (1.46446609406726225 3.53553390593273775), 1.4644660940672622, 0)
453+
QgsTriangle().inscribedCircle()
454+
# QgsCircle()
455+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 10 ) ).inscribedCircle()
456+
# QgsCircle()
457+
QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) ).inscribedCircle()
458+
# QgsCircle()
345459
\endcode
346460
:rtype: QgsCircle
347461
%End

src/app/qgsmaptooladdcircle.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,5 @@ void QgsMapToolAddCircle::clean()
123123
{
124124
mParentTool->deleteTempRubberBand();
125125
}
126+
mCircle = QgsCircle();
126127
}

0 commit comments

Comments
 (0)