LCOV - code coverage report
Current view: top level - core/geometry - qgsregularpolygon.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 164 164 100.0 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                          qgsregularpolygon.cpp
       3                 :            :                          --------------
       4                 :            :     begin                : May 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 "qgsregularpolygon.h"
      19                 :            : #include "qgsgeometryutils.h"
      20                 :            : 
      21                 :            : #include <memory>
      22                 :            : 
      23                 :         11 : QgsRegularPolygon::QgsRegularPolygon( const QgsPoint &center, const double radius, const double azimuth, const unsigned int numSides, const ConstructionOption circle )
      24                 :         11 :   : mCenter( center )
      25                 :            : {
      26                 :            :   // TODO: inclination
      27                 :            : 
      28                 :         11 :   if ( numSides >= 3 )
      29                 :            :   {
      30                 :         10 :     mNumberSides = numSides;
      31                 :            : 
      32                 :         10 :     switch ( circle )
      33                 :            :     {
      34                 :            :       case InscribedCircle:
      35                 :            :       {
      36                 :          5 :         mRadius = std::fabs( radius );
      37                 :          5 :         mFirstVertex = mCenter.project( mRadius, azimuth );
      38                 :          5 :         break;
      39                 :            :       }
      40                 :            :       case CircumscribedCircle:
      41                 :            :       {
      42                 :          4 :         mRadius = apothemToRadius( std::fabs( radius ), numSides );
      43                 :          4 :         mFirstVertex = mCenter.project( mRadius, azimuth - centralAngle( numSides ) / 2 );
      44                 :          4 :         break;
      45                 :            :       }
      46                 :            :     }
      47                 :            : 
      48                 :         10 :   }
      49                 :            : 
      50                 :         11 : }
      51                 :            : 
      52                 :          9 : QgsRegularPolygon::QgsRegularPolygon( const QgsPoint &center, const QgsPoint &pt1, const unsigned int numSides, const ConstructionOption circle )
      53                 :          9 :   : mCenter( center )
      54                 :            : {
      55                 :          9 :   if ( numSides >= 3 )
      56                 :            :   {
      57                 :          6 :     mNumberSides = numSides;
      58                 :            : 
      59                 :          6 :     switch ( circle )
      60                 :            :     {
      61                 :            :       case InscribedCircle:
      62                 :            :       {
      63                 :          3 :         mFirstVertex = pt1;
      64                 :          3 :         mRadius = center.distance( pt1 );
      65                 :          3 :         break;
      66                 :            :       }
      67                 :            :       case CircumscribedCircle:
      68                 :            :       {
      69                 :          1 :         mRadius = apothemToRadius( center.distance( pt1 ), numSides );
      70                 :          1 :         double azimuth = center.azimuth( pt1 );
      71                 :            :         // TODO: inclination
      72                 :          1 :         mFirstVertex = mCenter.project( mRadius, azimuth - centralAngle( numSides ) / 2 );
      73                 :          1 :         break;
      74                 :            :       }
      75                 :            :     }
      76                 :            : 
      77                 :          6 :   }
      78                 :            : 
      79                 :          9 : }
      80                 :            : 
      81                 :          3 : QgsRegularPolygon::QgsRegularPolygon( const QgsPoint &pt1, const QgsPoint &pt2, const unsigned int numSides )
      82                 :            : {
      83                 :          3 :   if ( numSides >= 3 )
      84                 :            :   {
      85                 :          3 :     mNumberSides = numSides;
      86                 :            : 
      87                 :          3 :     double azimuth = pt1.azimuth( pt2 );
      88                 :          3 :     QgsPoint pm = QgsGeometryUtils::midpoint( pt1, pt2 );
      89                 :          3 :     double length = pt1.distance( pm );
      90                 :            : 
      91                 :          3 :     double angle = ( 180 - ( 360 / numSides ) ) / 2.0;
      92                 :          3 :     double hypothenuse = length / std::cos( angle * M_PI / 180 );
      93                 :            :     // TODO: inclination
      94                 :            : 
      95                 :          3 :     mCenter = pt1.project( hypothenuse, azimuth + angle );
      96                 :          3 :     mFirstVertex = pt1;
      97                 :          3 :     mRadius = std::fabs( hypothenuse );
      98                 :          3 :   }
      99                 :          3 : }
     100                 :            : 
     101                 :         10 : bool QgsRegularPolygon::operator ==( const QgsRegularPolygon &rp ) const
     102                 :            : {
     103                 :         16 :   return ( ( mCenter == rp.mCenter ) &&
     104                 :          6 :            ( mFirstVertex == rp.mFirstVertex ) &&
     105                 :          6 :            ( mNumberSides == rp.mNumberSides )
     106                 :            :          );
     107                 :            : }
     108                 :            : 
     109                 :          4 : bool QgsRegularPolygon::operator !=( const QgsRegularPolygon &rp ) const
     110                 :            : {
     111                 :          4 :   return !operator==( rp );
     112                 :            : }
     113                 :            : 
     114                 :         51 : bool QgsRegularPolygon::isEmpty() const
     115                 :            : {
     116                 :         83 :   return ( ( mNumberSides < 3 ) ||
     117                 :         32 :            ( mCenter.isEmpty() ) ||
     118                 :         31 :            ( mFirstVertex.isEmpty() ) ||
     119                 :         30 :            ( mCenter == mFirstVertex )
     120                 :            :          );
     121                 :            : }
     122                 :            : 
     123                 :          2 : void QgsRegularPolygon::setCenter( const QgsPoint &center )
     124                 :            : {
     125                 :          2 :   double azimuth = mFirstVertex.isEmpty() ? 0 : mCenter.azimuth( mFirstVertex );
     126                 :            :   // TODO: double inclination = mCenter.inclination(mFirstVertex);
     127                 :          2 :   mCenter = center;
     128                 :          2 :   mFirstVertex = center.project( mRadius, azimuth );
     129                 :          2 : }
     130                 :            : 
     131                 :          1 : void QgsRegularPolygon::setRadius( const double radius )
     132                 :            : {
     133                 :          1 :   mRadius = std::fabs( radius );
     134                 :          1 :   double azimuth = mFirstVertex.isEmpty() ? 0 : mCenter.azimuth( mFirstVertex );
     135                 :            :   // TODO: double inclination = mCenter.inclination(mFirstVertex);
     136                 :          1 :   mFirstVertex = mCenter.project( mRadius, azimuth );
     137                 :          1 : }
     138                 :            : 
     139                 :          1 : void QgsRegularPolygon::setFirstVertex( const QgsPoint &firstVertex )
     140                 :            : {
     141                 :          1 :   double azimuth = mCenter.azimuth( mFirstVertex );
     142                 :            :   // TODO: double inclination = mCenter.inclination(firstVertex);
     143                 :          1 :   mFirstVertex = firstVertex;
     144                 :          1 :   mCenter = mFirstVertex.project( mRadius, azimuth );
     145                 :          1 : }
     146                 :            : 
     147                 :          8 : void QgsRegularPolygon::setNumberSides( const unsigned int numSides )
     148                 :            : {
     149                 :          8 :   if ( numSides >= 3 )
     150                 :            :   {
     151                 :          5 :     mNumberSides = numSides;
     152                 :          5 :   }
     153                 :          8 : }
     154                 :            : 
     155                 :          6 : QgsPointSequence QgsRegularPolygon::points() const
     156                 :            : {
     157                 :          6 :   QgsPointSequence pts;
     158                 :          6 :   if ( isEmpty() )
     159                 :            :   {
     160                 :          1 :     return pts;
     161                 :            :   }
     162                 :            : 
     163                 :          5 :   double azimuth = mCenter.azimuth( mFirstVertex );
     164                 :          5 :   double azimuth_add = centralAngle();
     165                 :            :   // TODO: inclination
     166                 :            : 
     167                 :          5 :   unsigned int n = 1;
     168                 :         23 :   while ( n <= mNumberSides )
     169                 :            :   {
     170                 :         18 :     pts.push_back( mCenter.project( mRadius, azimuth ) );
     171                 :         18 :     azimuth += azimuth_add;
     172                 :         18 :     if ( ( azimuth_add > 0 ) && ( azimuth > 180.0 ) )
     173                 :            :     {
     174                 :          5 :       azimuth -= 360.0;
     175                 :          5 :     }
     176                 :            : 
     177                 :         18 :     n++;
     178                 :            :   }
     179                 :            : 
     180                 :          5 :   return pts;
     181                 :          6 : }
     182                 :            : 
     183                 :          2 : QgsPolygon *QgsRegularPolygon::toPolygon() const
     184                 :            : {
     185                 :          2 :   std::unique_ptr<QgsPolygon> polygon( new QgsPolygon() );
     186                 :          2 :   if ( isEmpty() )
     187                 :            :   {
     188                 :          1 :     return polygon.release();
     189                 :            :   }
     190                 :            : 
     191                 :          1 :   polygon->setExteriorRing( toLineString() );
     192                 :            : 
     193                 :          1 :   return polygon.release();
     194                 :          2 : }
     195                 :            : 
     196                 :          3 : QgsLineString *QgsRegularPolygon::toLineString() const
     197                 :            : {
     198                 :          3 :   std::unique_ptr<QgsLineString> ext( new QgsLineString() );
     199                 :          3 :   if ( isEmpty() )
     200                 :            :   {
     201                 :          1 :     return ext.release();
     202                 :            :   }
     203                 :            : 
     204                 :          2 :   QgsPointSequence pts;
     205                 :          2 :   pts = points();
     206                 :            : 
     207                 :          2 :   ext->setPoints( pts );
     208                 :          2 :   ext->addVertex( pts.at( 0 ) ); //close regular polygon
     209                 :            : 
     210                 :          2 :   return ext.release();
     211                 :          3 : }
     212                 :            : 
     213                 :          3 : QgsTriangle QgsRegularPolygon::toTriangle() const
     214                 :            : {
     215                 :          3 :   if ( isEmpty() || ( mNumberSides != 3 ) )
     216                 :            :   {
     217                 :          2 :     return QgsTriangle();
     218                 :            :   }
     219                 :            : 
     220                 :          1 :   QgsPointSequence pts;
     221                 :          1 :   pts = points();
     222                 :            : 
     223                 :          1 :   return QgsTriangle( pts.at( 0 ), pts.at( 1 ), pts.at( 2 ) );
     224                 :          3 : }
     225                 :            : 
     226                 :          2 : QVector<QgsTriangle> QgsRegularPolygon::triangulate() const
     227                 :            : {
     228                 :         25 :   QVector<QgsTriangle> l_tri;
     229                 :         25 :   if ( isEmpty() )
     230                 :            :   {
     231                 :          1 :     return l_tri;
     232                 :            :   }
     233                 :            : 
     234                 :          1 :   QgsPointSequence pts;
     235                 :          1 :   pts = points();
     236                 :            : 
     237                 :          1 :   unsigned int n = 0;
     238                 :          4 :   while ( n < mNumberSides - 1 )
     239                 :            :   {
     240                 :          3 :     l_tri.append( QgsTriangle( pts.at( n ), pts.at( n + 1 ), mCenter ) );
     241                 :          3 :     n++;
     242                 :            :   }
     243                 :          1 :   l_tri.append( QgsTriangle( pts.at( n ), pts.at( 0 ), mCenter ) );
     244                 :            : 
     245                 :          1 :   return l_tri;
     246                 :          2 : }
     247                 :            : 
     248                 :          1 : QgsCircle QgsRegularPolygon::inscribedCircle() const
     249                 :            : {
     250                 :            :   // TODO: inclined circle
     251                 :          1 :   return QgsCircle( mCenter, apothem() );
     252                 :            : }
     253                 :            : 
     254                 :          2 : QgsCircle QgsRegularPolygon::circumscribedCircle() const
     255                 :            : {
     256                 :            :   // TODO: inclined circle
     257                 :          2 :   return QgsCircle( mCenter, mRadius );
     258                 :            : }
     259                 :            : 
     260                 :          2 : QString QgsRegularPolygon::toString( int pointPrecision, int radiusPrecision, int anglePrecision ) const
     261                 :            : {
     262                 :          2 :   QString rep;
     263                 :          2 :   if ( isEmpty() )
     264                 :          2 :     rep = QStringLiteral( "Empty" );
     265                 :            :   else
     266                 :          3 :     rep = QStringLiteral( "RegularPolygon (Center: %1, First Vertex: %2, Radius: %3, Azimuth: %4)" )
     267                 :          1 :           .arg( mCenter.asWkt( pointPrecision ), 0, 's' )
     268                 :          1 :           .arg( mFirstVertex.asWkt( pointPrecision ), 0, 's' )
     269                 :          1 :           .arg( qgsDoubleToString( mRadius, radiusPrecision ), 0, 'f' )
     270                 :          1 :           .arg( qgsDoubleToString( mCenter.azimuth( mFirstVertex ), anglePrecision ), 0, 'f' );
     271                 :            :   // TODO: inclination
     272                 :            :   // .arg( qgsDoubleToString( mCenter.inclination(mFirstVertex), anglePrecision ), 0, 'f' );
     273                 :            : 
     274                 :          2 :   return rep;
     275                 :          2 : }
     276                 :            : 
     277                 :          6 : double QgsRegularPolygon::area() const
     278                 :            : {
     279                 :          6 :   if ( isEmpty() )
     280                 :            :   {
     281                 :          2 :     return 0.0;
     282                 :            :   }
     283                 :            : 
     284                 :          4 :   return ( mRadius * mRadius * mNumberSides * std::sin( centralAngle() * M_PI / 180.0 ) ) / 2;
     285                 :          6 : }
     286                 :            : 
     287                 :          5 : double QgsRegularPolygon::perimeter() const
     288                 :            : {
     289                 :          5 :   if ( isEmpty() )
     290                 :            :   {
     291                 :          2 :     return 0.0;
     292                 :            :   }
     293                 :            : 
     294                 :          3 :   return length() * mNumberSides;
     295                 :          5 : }
     296                 :            : 
     297                 :          8 : double QgsRegularPolygon::length() const
     298                 :            : {
     299                 :          8 :   if ( isEmpty() )
     300                 :            :   {
     301                 :          2 :     return 0.0;
     302                 :            :   }
     303                 :            : 
     304                 :          6 :   return mRadius * 2 * std::sin( M_PI / mNumberSides );
     305                 :          8 : }
     306                 :            : 
     307                 :          5 : double QgsRegularPolygon::apothemToRadius( const double apothem, const unsigned int numSides ) const
     308                 :            : {
     309                 :          5 :   return apothem / std::cos( M_PI / numSides );
     310                 :            : }
     311                 :            : 
     312                 :          4 : double QgsRegularPolygon::interiorAngle( const unsigned int nbSides ) const
     313                 :            : {
     314                 :          4 :   return ( nbSides - 2 ) * 180 / nbSides;
     315                 :            : }
     316                 :            : 
     317                 :         18 : double QgsRegularPolygon::centralAngle( const unsigned int nbSides ) const
     318                 :            : {
     319                 :         18 :   return 360.0 / nbSides;
     320                 :            : }
     321                 :            : 
     322                 :          4 : double QgsRegularPolygon::interiorAngle() const
     323                 :            : {
     324                 :          4 :   return interiorAngle( mNumberSides );
     325                 :            : }
     326                 :            : 
     327                 :         13 : double QgsRegularPolygon::centralAngle() const
     328                 :            : {
     329                 :         13 :   return centralAngle( mNumberSides );
     330                 :            : }

Generated by: LCOV version 1.14