LCOV - code coverage report
Current view: top level - core/geometry - qgstriangle.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 384 385 99.7 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           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 : }

Generated by: LCOV version 1.14