Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgstriangle.cpp
3 : : -------------------
4 : : begin : January 2017
5 : : copyright : (C) 2017 by Loïc Bartoletti
6 : : email : lbartoletti at tuxfamily dot org
7 : : ***************************************************************************/
8 : :
9 : : /***************************************************************************
10 : : * *
11 : : * This program is free software; you can redistribute it and/or modify *
12 : : * it under the terms of the GNU General Public License as published by *
13 : : * the Free Software Foundation; either version 2 of the License, or *
14 : : * (at your option) any later version. *
15 : : * *
16 : : ***************************************************************************/
17 : :
18 : : #include "qgstriangle.h"
19 : : #include "qgsgeometryutils.h"
20 : : #include "qgslinestring.h"
21 : : #include "qgswkbptr.h"
22 : :
23 : : #include <memory>
24 : :
25 : 258 : QgsTriangle::QgsTriangle()
26 : 516 : {
27 : 258 : mWkbType = QgsWkbTypes::Triangle;
28 : 258 : }
29 : :
30 : 41 : QgsTriangle::QgsTriangle( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3 )
31 : 82 : {
32 : 41 : mWkbType = QgsWkbTypes::Triangle;
33 : :
34 : 41 : QVector< double > x { p1.x(), p2.x(), p3.x(), p1.x() };
35 : 41 : QVector< double > y { p1.y(), p2.y(), p3.y(), p1.y() };
36 : 41 : QVector< double > z;
37 : 41 : if ( p1.is3D() )
38 : : {
39 : 5 : z = { p1.z(), p2.z(), p3.z(), p1.z() };
40 : 5 : }
41 : 41 : QVector< double > m;
42 : 41 : if ( p1.isMeasure() )
43 : : {
44 : 3 : m = {p1.m(), p2.m(), p3.m(), p1.m() };
45 : 3 : }
46 : 41 : setExteriorRing( new QgsLineString( x, y, z, m ) );
47 : 41 : }
48 : :
49 : 2 : QgsTriangle::QgsTriangle( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3 )
50 : 4 : {
51 : 2 : mWkbType = QgsWkbTypes::Triangle;
52 : :
53 : 2 : QVector< double > x { p1.x(), p2.x(), p3.x(), p1.x() };
54 : 2 : QVector< double > y {p1.y(), p2.y(), p3.y(), p1.y() };
55 : 2 : QgsLineString *ext = new QgsLineString( x, y );
56 : 2 : setExteriorRing( ext );
57 : 2 : }
58 : :
59 : 2 : QgsTriangle::QgsTriangle( const QPointF p1, const QPointF p2, const QPointF p3 )
60 : 4 : {
61 : 2 : mWkbType = QgsWkbTypes::Triangle;
62 : :
63 : 2 : QVector< double > x{ p1.x(), p2.x(), p3.x(), p1.x() };
64 : 2 : QVector< double > y{ p1.y(), p2.y(), p3.y(), p1.y() };
65 : 2 : QgsLineString *ext = new QgsLineString( x, y );
66 : 2 : setExteriorRing( ext );
67 : 2 : }
68 : :
69 : 24 : bool QgsTriangle::operator==( const QgsTriangle &other ) const
70 : : {
71 : 24 : if ( isEmpty() && other.isEmpty() )
72 : : {
73 : 5 : return true;
74 : : }
75 : 19 : else if ( isEmpty() || other.isEmpty() )
76 : : {
77 : 4 : return false;
78 : : }
79 : :
80 : 29 : return ( ( vertexAt( 0 ) == other.vertexAt( 0 ) ) &&
81 : 14 : ( vertexAt( 1 ) == other.vertexAt( 1 ) ) &&
82 : 14 : ( vertexAt( 2 ) == other.vertexAt( 2 ) )
83 : : );
84 : 24 : }
85 : :
86 : 5 : bool QgsTriangle::operator!=( const QgsTriangle &other ) const
87 : : {
88 : 5 : return !operator==( other );
89 : : }
90 : :
91 : 446 : QString QgsTriangle::geometryType() const
92 : : {
93 : 892 : return QStringLiteral( "Triangle" );
94 : : }
95 : :
96 : 1 : QgsTriangle *QgsTriangle::createEmptyWithSameType() const
97 : : {
98 : 1 : auto result = std::make_unique< QgsTriangle >();
99 : 1 : result->mWkbType = mWkbType;
100 : 1 : return result.release();
101 : 1 : }
102 : :
103 : 453 : void QgsTriangle::clear()
104 : : {
105 : 453 : QgsPolygon::clear();
106 : 453 : mWkbType = QgsWkbTypes::Triangle;
107 : 453 : }
108 : :
109 : 1 : QgsTriangle *QgsTriangle::clone() const
110 : : {
111 : 1 : return new QgsTriangle( *this );
112 : 0 : }
113 : :
114 : 7 : bool QgsTriangle::fromWkb( QgsConstWkbPtr &wkbPtr )
115 : : {
116 : 7 : clear();
117 : 7 : if ( !wkbPtr )
118 : : {
119 : 1 : return false;
120 : : }
121 : :
122 : 6 : QgsWkbTypes::Type type = wkbPtr.readHeader();
123 : 6 : if ( QgsWkbTypes::flatType( type ) != QgsWkbTypes::Triangle )
124 : : {
125 : 1 : return false;
126 : : }
127 : 5 : mWkbType = type;
128 : :
129 : : QgsWkbTypes::Type ringType;
130 : 5 : switch ( mWkbType )
131 : : {
132 : : case QgsWkbTypes::TriangleZ:
133 : 1 : ringType = QgsWkbTypes::LineStringZ;
134 : 1 : break;
135 : : case QgsWkbTypes::TriangleM:
136 : 1 : ringType = QgsWkbTypes::LineStringM;
137 : 1 : break;
138 : : case QgsWkbTypes::TriangleZM:
139 : 1 : ringType = QgsWkbTypes::LineStringZM;
140 : 1 : break;
141 : : default:
142 : 2 : ringType = QgsWkbTypes::LineString;
143 : 2 : break;
144 : : }
145 : :
146 : : int nRings;
147 : 5 : wkbPtr >> nRings;
148 : 5 : if ( nRings > 1 )
149 : : {
150 : 1 : return false;
151 : : }
152 : :
153 : 4 : QgsLineString *line = new QgsLineString();
154 : 4 : line->fromWkbPoints( ringType, wkbPtr );
155 : 4 : mExteriorRing.reset( line );
156 : :
157 : 4 : return true;
158 : 7 : }
159 : :
160 : 418 : bool QgsTriangle::fromWkt( const QString &wkt )
161 : : {
162 : 418 : clear();
163 : :
164 : 418 : QPair<QgsWkbTypes::Type, QString> parts = QgsGeometryUtils::wktReadBlock( wkt );
165 : :
166 : 418 : if ( QgsWkbTypes::geometryType( parts.first ) != QgsWkbTypes::PolygonGeometry )
167 : 1 : return false;
168 : :
169 : 417 : mWkbType = parts.first;
170 : :
171 : 417 : QString secondWithoutParentheses = parts.second;
172 : 417 : secondWithoutParentheses = secondWithoutParentheses.simplified().remove( ' ' );
173 : 434 : if ( ( parts.second.compare( QLatin1String( "EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
174 : 17 : secondWithoutParentheses.isEmpty() )
175 : 400 : return true;
176 : :
177 : 36 : QString defaultChildWkbType = QStringLiteral( "LineString%1%2" ).arg( is3D() ? QStringLiteral( "Z" ) : QString(), isMeasure() ? QStringLiteral( "M" ) : QString() );
178 : :
179 : 17 : const QStringList blocks = QgsGeometryUtils::wktGetChildBlocks( parts.second, defaultChildWkbType );
180 : 30 : for ( const QString &childWkt : blocks )
181 : : {
182 : 17 : QPair<QgsWkbTypes::Type, QString> childParts = QgsGeometryUtils::wktReadBlock( childWkt );
183 : :
184 : 17 : QgsWkbTypes::Type flatCurveType = QgsWkbTypes::flatType( childParts.first );
185 : :
186 : 17 : if ( flatCurveType == QgsWkbTypes::LineString )
187 : 15 : mInteriorRings.append( new QgsLineString() );
188 : : else
189 : : {
190 : 2 : clear();
191 : 2 : return false;
192 : : }
193 : 15 : if ( !mInteriorRings.back()->fromWkt( childWkt ) )
194 : : {
195 : 2 : clear();
196 : 2 : return false;
197 : : }
198 : 17 : }
199 : :
200 : 13 : mExteriorRing.reset( mInteriorRings.takeFirst() );
201 : 19 : if ( ( mExteriorRing->numPoints() < 3 ) || ( mExteriorRing->numPoints() > 4 ) || ( mExteriorRing->numPoints() == 4 && mExteriorRing->startPoint() != mExteriorRing->endPoint() ) )
202 : : {
203 : 6 : clear();
204 : 6 : return false;
205 : : }
206 : :
207 : : //scan through rings and check if dimensionality of rings is different to CurvePolygon.
208 : : //if so, update the type dimensionality of the CurvePolygon to match
209 : 7 : bool hasZ = false;
210 : 7 : bool hasM = false;
211 : 7 : if ( mExteriorRing )
212 : : {
213 : 7 : hasZ = hasZ || mExteriorRing->is3D();
214 : 7 : hasM = hasM || mExteriorRing->isMeasure();
215 : 7 : }
216 : 7 : if ( hasZ )
217 : 1 : addZValue( 0 );
218 : 7 : if ( hasM )
219 : 1 : addMValue( 0 );
220 : :
221 : 7 : return true;
222 : 418 : }
223 : :
224 : 4 : QDomElement QgsTriangle::asGml3( QDomDocument &doc, int precision, const QString &ns, const AxisOrder axisOrder ) const
225 : : {
226 : :
227 : 8 : QDomElement elemTriangle = doc.createElementNS( ns, QStringLiteral( "Triangle" ) );
228 : :
229 : 4 : if ( isEmpty() )
230 : 1 : return elemTriangle;
231 : :
232 : 6 : QDomElement elemExterior = doc.createElementNS( ns, QStringLiteral( "exterior" ) );
233 : 3 : QDomElement curveElem = exteriorRing()->asGml3( doc, precision, ns, axisOrder );
234 : 3 : if ( curveElem.tagName() == QLatin1String( "LineString" ) )
235 : : {
236 : 6 : curveElem.setTagName( QStringLiteral( "LinearRing" ) );
237 : 3 : }
238 : 3 : elemExterior.appendChild( curveElem );
239 : 3 : elemTriangle.appendChild( elemExterior );
240 : :
241 : 3 : return elemTriangle;
242 : 4 : }
243 : :
244 : 1 : QgsPolygon *QgsTriangle::surfaceToPolygon() const
245 : : {
246 : 1 : return toPolygon();
247 : : }
248 : :
249 : 1 : QgsCurvePolygon *QgsTriangle::toCurveType() const
250 : : {
251 : 1 : std::unique_ptr<QgsCurvePolygon> curvePolygon( new QgsCurvePolygon() );
252 : 1 : curvePolygon->setExteriorRing( mExteriorRing->clone() );
253 : :
254 : 1 : return curvePolygon.release();
255 : 1 : }
256 : :
257 : 1 : void QgsTriangle::addInteriorRing( QgsCurve *ring )
258 : : {
259 : 1 : delete ring;
260 : 1 : }
261 : :
262 : 1 : bool QgsTriangle::deleteVertex( QgsVertexId position )
263 : : {
264 : : Q_UNUSED( position )
265 : 1 : return false;
266 : : }
267 : :
268 : 1 : bool QgsTriangle::insertVertex( QgsVertexId position, const QgsPoint &vertex )
269 : : {
270 : : Q_UNUSED( position )
271 : 1 : Q_UNUSED( vertex )
272 : 1 : return false;
273 : : }
274 : :
275 : 16 : bool QgsTriangle::moveVertex( QgsVertexId vId, const QgsPoint &newPos )
276 : : {
277 : 16 : if ( isEmpty() )
278 : 1 : return false;
279 : :
280 : 15 : if ( !mExteriorRing || vId.part != 0 || vId.ring != 0 || vId.vertex < 0 || vId.vertex > 4 )
281 : : {
282 : 6 : return false;
283 : : }
284 : :
285 : 9 : if ( vId.vertex == 4 )
286 : : {
287 : 2 : vId.vertex = 0;
288 : 2 : }
289 : :
290 : 9 : int n = mExteriorRing->numPoints();
291 : 9 : bool success = mExteriorRing->moveVertex( vId, newPos );
292 : 9 : if ( success )
293 : : {
294 : : // If first or last vertex is moved, also move the last/first vertex
295 : 9 : if ( vId.vertex == 0 )
296 : 4 : mExteriorRing->moveVertex( QgsVertexId( vId.part, vId.ring, n - 1 ), newPos );
297 : 9 : clearCache();
298 : 9 : }
299 : 9 : return success;
300 : 16 : }
301 : :
302 : 59 : void QgsTriangle::setExteriorRing( QgsCurve *ring )
303 : : {
304 : 59 : if ( !ring )
305 : : {
306 : 1 : return;
307 : : }
308 : :
309 : 58 : if ( ring->hasCurvedSegments() )
310 : : {
311 : : //need to segmentize ring as polygon does not support curves
312 : 1 : QgsCurve *line = ring->segmentize();
313 : 1 : delete ring;
314 : 1 : ring = line;
315 : 1 : }
316 : :
317 : 58 : if ( ( ring->numPoints() > 4 ) || ( ring->numPoints() < 3 ) )
318 : : {
319 : 3 : delete ring;
320 : 3 : return;
321 : : }
322 : 55 : else if ( ring->numPoints() == 4 )
323 : : {
324 : 51 : if ( !ring->isClosed() )
325 : : {
326 : 1 : delete ring;
327 : 1 : return;
328 : : }
329 : 50 : }
330 : 4 : else if ( ring->numPoints() == 3 )
331 : : {
332 : 4 : if ( ring->isClosed() )
333 : : {
334 : 1 : delete ring;
335 : 1 : return;
336 : : }
337 : 3 : QgsLineString *lineString = static_cast< QgsLineString *>( ring );
338 : 3 : if ( !lineString->isClosed() )
339 : : {
340 : 3 : lineString->close();
341 : 3 : }
342 : 3 : ring = lineString;
343 : 3 : }
344 : :
345 : 53 : mExteriorRing.reset( ring );
346 : :
347 : : //set proper wkb type
348 : 53 : setZMTypeFromSubGeometry( ring, QgsWkbTypes::Triangle );
349 : :
350 : 53 : clearCache();
351 : 59 : }
352 : :
353 : 2 : QgsCurve *QgsTriangle::boundary() const
354 : : {
355 : 2 : if ( !mExteriorRing )
356 : 1 : return nullptr;
357 : :
358 : 1 : return mExteriorRing->clone();
359 : 2 : }
360 : :
361 : 730 : QgsPoint QgsTriangle::vertexAt( int atVertex ) const
362 : : {
363 : 730 : if ( isEmpty() )
364 : 2 : return QgsPoint();
365 : :
366 : 728 : QgsVertexId id( 0, 0, atVertex );
367 : 728 : return mExteriorRing->vertexAt( id );
368 : 730 : }
369 : :
370 : 32 : QVector<double> QgsTriangle::lengths() const
371 : : {
372 : 32 : QVector<double> lengths;
373 : 32 : if ( isEmpty() )
374 : 1 : return lengths;
375 : :
376 : 31 : lengths.append( vertexAt( 0 ).distance( vertexAt( 1 ) ) );
377 : 31 : lengths.append( vertexAt( 1 ).distance( vertexAt( 2 ) ) );
378 : 31 : lengths.append( vertexAt( 2 ).distance( vertexAt( 0 ) ) );
379 : :
380 : 31 : return lengths;
381 : 32 : }
382 : :
383 : 5 : QVector<double> QgsTriangle::angles() const
384 : : {
385 : 5 : QVector<double> angles;
386 : 5 : if ( isEmpty() )
387 : 1 : return angles;
388 : : double ax, ay, bx, by, cx, cy;
389 : :
390 : 4 : ax = vertexAt( 0 ).x();
391 : 4 : ay = vertexAt( 0 ).y();
392 : 4 : bx = vertexAt( 1 ).x();
393 : 4 : by = vertexAt( 1 ).y();
394 : 4 : cx = vertexAt( 2 ).x();
395 : 4 : cy = vertexAt( 2 ).y();
396 : :
397 : 4 : double a1 = std::fmod( QgsGeometryUtils::angleBetweenThreePoints( cx, cy, ax, ay, bx, by ), M_PI );
398 : 4 : double a2 = std::fmod( QgsGeometryUtils::angleBetweenThreePoints( ax, ay, bx, by, cx, cy ), M_PI );
399 : 4 : double a3 = std::fmod( QgsGeometryUtils::angleBetweenThreePoints( bx, by, cx, cy, ax, ay ), M_PI );
400 : :
401 : 4 : angles.append( ( a1 > M_PI_2 ? a1 - M_PI_2 : a1 ) );
402 : 4 : angles.append( ( a2 > M_PI_2 ? a2 - M_PI_2 : a2 ) );
403 : 4 : angles.append( ( a3 > M_PI_2 ? a3 - M_PI_2 : a3 ) );
404 : :
405 : 4 : return angles;
406 : 5 : }
407 : :
408 : 4 : bool QgsTriangle::isDegenerate()
409 : : {
410 : 4 : if ( isEmpty() )
411 : 1 : return true;
412 : :
413 : 3 : QgsPoint p1( vertexAt( 0 ) );
414 : 3 : QgsPoint p2( vertexAt( 1 ) );
415 : 3 : QgsPoint p3( vertexAt( 2 ) );
416 : 3 : return ( ( ( p1 == p2 ) || ( p1 == p3 ) || ( p2 == p3 ) ) || QgsGeometryUtils::leftOfLine( p1.x(), p1.y(), p2.x(), p2.y(), p3.x(), p3.y() ) == 0 );
417 : 4 : }
418 : :
419 : 7 : bool QgsTriangle::isIsocele( double lengthTolerance ) const
420 : : {
421 : 7 : if ( isEmpty() )
422 : 1 : return false;
423 : 6 : QVector<double> sides = lengths();
424 : 6 : bool ab_bc = qgsDoubleNear( sides.at( 0 ), sides.at( 1 ), lengthTolerance );
425 : 6 : bool bc_ca = qgsDoubleNear( sides.at( 1 ), sides.at( 2 ), lengthTolerance );
426 : 6 : bool ca_ab = qgsDoubleNear( sides.at( 2 ), sides.at( 0 ), lengthTolerance );
427 : :
428 : 6 : return ( ab_bc || bc_ca || ca_ab );
429 : 7 : }
430 : :
431 : 4 : bool QgsTriangle::isEquilateral( double lengthTolerance ) const
432 : : {
433 : 4 : if ( isEmpty() )
434 : 1 : return false;
435 : 3 : QVector<double> sides = lengths();
436 : 3 : bool ab_bc = qgsDoubleNear( sides.at( 0 ), sides.at( 1 ), lengthTolerance );
437 : 3 : bool bc_ca = qgsDoubleNear( sides.at( 1 ), sides.at( 2 ), lengthTolerance );
438 : 3 : bool ca_ab = qgsDoubleNear( sides.at( 2 ), sides.at( 0 ), lengthTolerance );
439 : :
440 : 3 : return ( ab_bc && bc_ca && ca_ab );
441 : 4 : }
442 : :
443 : 4 : bool QgsTriangle::isRight( double angleTolerance ) const
444 : : {
445 : 4 : if ( isEmpty() )
446 : 1 : return false;
447 : 3 : QVector<double> a = angles();
448 : 3 : QVector<double>::iterator ita = a.begin();
449 : 9 : while ( ita != a.end() )
450 : : {
451 : 8 : if ( qgsDoubleNear( *ita, M_PI_2, angleTolerance ) )
452 : 2 : return true;
453 : 6 : ++ita;
454 : : }
455 : 1 : return false;
456 : 4 : }
457 : :
458 : 4 : bool QgsTriangle::isScalene( double lengthTolerance ) const
459 : : {
460 : 4 : if ( isEmpty() )
461 : 1 : return false;
462 : 3 : return !isIsocele( lengthTolerance );
463 : 4 : }
464 : :
465 : 9 : QVector<QgsLineString> QgsTriangle::altitudes() const
466 : : {
467 : 9 : QVector<QgsLineString> alt;
468 : 9 : if ( isEmpty() )
469 : 1 : return alt;
470 : :
471 : 8 : alt.append( QgsGeometryUtils::perpendicularSegment( vertexAt( 0 ), vertexAt( 2 ), vertexAt( 1 ) ) );
472 : 8 : alt.append( QgsGeometryUtils::perpendicularSegment( vertexAt( 1 ), vertexAt( 0 ), vertexAt( 2 ) ) );
473 : 8 : alt.append( QgsGeometryUtils::perpendicularSegment( vertexAt( 2 ), vertexAt( 0 ), vertexAt( 1 ) ) );
474 : :
475 : 8 : return alt;
476 : 9 : }
477 : :
478 : 4 : QVector<QgsLineString> QgsTriangle::medians() const
479 : : {
480 : 4 : QVector<QgsLineString> med;
481 : 4 : if ( isEmpty() )
482 : 1 : return med;
483 : :
484 : 3 : QgsLineString med1;
485 : 3 : QgsLineString med2;
486 : 3 : QgsLineString med3;
487 : 3 : med1.setPoints( QgsPointSequence() << vertexAt( 0 ) << QgsGeometryUtils::midpoint( vertexAt( 1 ), vertexAt( 2 ) ) );
488 : 3 : med2.setPoints( QgsPointSequence() << vertexAt( 1 ) << QgsGeometryUtils::midpoint( vertexAt( 0 ), vertexAt( 2 ) ) );
489 : 3 : med3.setPoints( QgsPointSequence() << vertexAt( 2 ) << QgsGeometryUtils::midpoint( vertexAt( 0 ), vertexAt( 1 ) ) );
490 : 3 : med.append( med1 );
491 : 3 : med.append( med2 );
492 : 3 : med.append( med3 );
493 : :
494 : 3 : return med;
495 : 4 : }
496 : :
497 : 2 : QVector<QgsLineString> QgsTriangle::bisectors( double lengthTolerance ) const
498 : : {
499 : 2 : QVector<QgsLineString> bis;
500 : 2 : if ( isEmpty() )
501 : 1 : return bis;
502 : :
503 : 1 : QgsLineString bis1;
504 : 1 : QgsLineString bis2;
505 : 1 : QgsLineString bis3;
506 : 1 : QgsPoint incenter = inscribedCenter();
507 : 1 : QgsPoint out;
508 : 1 : bool intersection = false;
509 : :
510 : 1 : QgsGeometryUtils::segmentIntersection( vertexAt( 0 ), incenter, vertexAt( 1 ), vertexAt( 2 ), out, intersection, lengthTolerance );
511 : 1 : bis1.setPoints( QgsPointSequence() << vertexAt( 0 ) << out );
512 : :
513 : 1 : QgsGeometryUtils::segmentIntersection( vertexAt( 1 ), incenter, vertexAt( 0 ), vertexAt( 2 ), out, intersection, lengthTolerance );
514 : 1 : bis2.setPoints( QgsPointSequence() << vertexAt( 1 ) << out );
515 : :
516 : 1 : QgsGeometryUtils::segmentIntersection( vertexAt( 2 ), incenter, vertexAt( 0 ), vertexAt( 1 ), out, intersection, lengthTolerance );
517 : 1 : bis3.setPoints( QgsPointSequence() << vertexAt( 2 ) << out );
518 : :
519 : 1 : bis.append( bis1 );
520 : 1 : bis.append( bis2 );
521 : 1 : bis.append( bis3 );
522 : :
523 : 1 : return bis;
524 : 2 : }
525 : :
526 : 3 : QgsTriangle QgsTriangle::medial() const
527 : : {
528 : 3 : if ( isEmpty() )
529 : 1 : return QgsTriangle();
530 : 2 : QgsPoint p1, p2, p3;
531 : 2 : p1 = QgsGeometryUtils::midpoint( vertexAt( 0 ), vertexAt( 1 ) );
532 : 2 : p2 = QgsGeometryUtils::midpoint( vertexAt( 1 ), vertexAt( 2 ) );
533 : 2 : p3 = QgsGeometryUtils::midpoint( vertexAt( 2 ), vertexAt( 0 ) );
534 : 2 : return QgsTriangle( p1, p2, p3 );
535 : 3 : }
536 : :
537 : 7 : QgsPoint QgsTriangle::orthocenter( double lengthTolerance ) const
538 : : {
539 : 7 : if ( isEmpty() )
540 : 1 : return QgsPoint();
541 : 6 : QVector<QgsLineString> alt = altitudes();
542 : 6 : QgsPoint ortho;
543 : : bool intersection;
544 : 6 : QgsGeometryUtils::segmentIntersection( alt.at( 0 ).pointN( 0 ), alt.at( 0 ).pointN( 1 ), alt.at( 1 ).pointN( 0 ), alt.at( 1 ).pointN( 1 ), ortho, intersection, lengthTolerance );
545 : :
546 : 6 : return ortho;
547 : 7 : }
548 : :
549 : 14 : QgsPoint QgsTriangle::circumscribedCenter() const
550 : : {
551 : 14 : if ( isEmpty() )
552 : 1 : return QgsPoint();
553 : : double r, x, y;
554 : 13 : QgsGeometryUtils::circleCenterRadius( vertexAt( 0 ), vertexAt( 1 ), vertexAt( 2 ), r, x, y );
555 : 13 : return QgsPoint( x, y );
556 : 14 : }
557 : :
558 : 14 : double QgsTriangle::circumscribedRadius() const
559 : : {
560 : 14 : if ( isEmpty() )
561 : 1 : return 0.0;
562 : : double r, x, y;
563 : 13 : QgsGeometryUtils::circleCenterRadius( vertexAt( 0 ), vertexAt( 1 ), vertexAt( 2 ), r, x, y );
564 : 13 : return r;
565 : 14 : }
566 : :
567 : 8 : QgsCircle QgsTriangle::circumscribedCircle() const
568 : : {
569 : 8 : if ( isEmpty() )
570 : 1 : return QgsCircle();
571 : 7 : return QgsCircle( circumscribedCenter(), circumscribedRadius() );
572 : 8 : }
573 : :
574 : 22 : QgsPoint QgsTriangle::inscribedCenter() const
575 : : {
576 : 22 : if ( isEmpty() )
577 : 1 : return QgsPoint();
578 : :
579 : 21 : QVector<double> l = lengths();
580 : 63 : double x = ( l.at( 0 ) * vertexAt( 2 ).x() +
581 : 42 : l.at( 1 ) * vertexAt( 0 ).x() +
582 : 21 : l.at( 2 ) * vertexAt( 1 ).x() ) / perimeter();
583 : 63 : double y = ( l.at( 0 ) * vertexAt( 2 ).y() +
584 : 42 : l.at( 1 ) * vertexAt( 0 ).y() +
585 : 21 : l.at( 2 ) * vertexAt( 1 ).y() ) / perimeter();
586 : :
587 : 21 : QgsPoint center( x, y );
588 : :
589 : 21 : QgsPointSequence points;
590 : 21 : points << vertexAt( 0 ) << vertexAt( 1 ) << vertexAt( 2 );
591 : 21 : QgsGeometryUtils::setZValueFromPoints( points, center );
592 : :
593 : 21 : return center;
594 : 22 : }
595 : :
596 : 15 : double QgsTriangle::inscribedRadius() const
597 : : {
598 : 15 : if ( isEmpty() )
599 : 1 : return 0.0;
600 : 14 : return ( 2.0 * area() / perimeter() );
601 : 15 : }
602 : :
603 : 9 : QgsCircle QgsTriangle::inscribedCircle() const
604 : : {
605 : 9 : if ( isEmpty() )
606 : 1 : return QgsCircle();
607 : 8 : return QgsCircle( inscribedCenter(), inscribedRadius() );
608 : 9 : }
|