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

Generated by: LCOV version 1.14