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

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                          qgspointv2.cpp
       3                 :            :                          --------------
       4                 :            :     begin                : September 2014
       5                 :            :     copyright            : (C) 2014 by Marco Hugentobler
       6                 :            :     email                : marco at sourcepole dot ch
       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                 :            : 
      19                 :            : #include "qgspoint.h"
      20                 :            : #include "qgsapplication.h"
      21                 :            : #include "qgscoordinatetransform.h"
      22                 :            : #include "qgsgeometryutils.h"
      23                 :            : #include "qgsmaptopixel.h"
      24                 :            : #include "qgswkbptr.h"
      25                 :            : #include "qgsgeometrytransformer.h"
      26                 :            : 
      27                 :            : #include <cmath>
      28                 :            : #include <QPainter>
      29                 :            : #include <QPainterPath>
      30                 :            : #include <QRegularExpression>
      31                 :            : #include <QJsonObject>
      32                 :            : #include <QJsonArray>
      33                 :            : #include <nlohmann/json.hpp>
      34                 :            : 
      35                 :            : /***************************************************************************
      36                 :            :  * This class is considered CRITICAL and any change MUST be accompanied with
      37                 :            :  * full unit tests.
      38                 :            :  * See details in QEP #17
      39                 :            :  ****************************************************************************/
      40                 :            : 
      41                 :      54763 : QgsPoint::QgsPoint( double x, double y, double z, double m, QgsWkbTypes::Type wkbType )
      42                 :      54763 :   : mX( x )
      43                 :      54763 :   , mY( y )
      44                 :      54763 :   , mZ( z )
      45                 :      54763 :   , mM( m )
      46                 :     109526 : {
      47                 :      54763 :   if ( wkbType != QgsWkbTypes::Unknown )
      48                 :            :   {
      49                 :            :     Q_ASSERT( QgsWkbTypes::flatType( wkbType ) == QgsWkbTypes::Point );
      50                 :        763 :     mWkbType = wkbType;
      51                 :        763 :   }
      52                 :      54000 :   else if ( std::isnan( z ) )
      53                 :            :   {
      54                 :      53512 :     if ( std::isnan( m ) )
      55                 :      53510 :       mWkbType = QgsWkbTypes::Point;
      56                 :            :     else
      57                 :          2 :       mWkbType = QgsWkbTypes::PointM;
      58                 :      53512 :   }
      59                 :        488 :   else if ( std::isnan( m ) )
      60                 :        266 :     mWkbType = QgsWkbTypes::PointZ;
      61                 :            :   else
      62                 :        222 :     mWkbType = QgsWkbTypes::PointZM;
      63                 :      54763 : }
      64                 :            : 
      65                 :        161 : QgsPoint::QgsPoint( const QgsPointXY &p )
      66                 :        161 :   : mX( p.x() )
      67                 :        161 :   , mY( p.y() )
      68                 :        161 :   , mZ( std::numeric_limits<double>::quiet_NaN() )
      69                 :        161 :   , mM( std::numeric_limits<double>::quiet_NaN() )
      70                 :        322 : {
      71                 :        161 :   mWkbType = QgsWkbTypes::Point;
      72                 :        161 :   if ( p.isEmpty() )
      73                 :            :   {
      74                 :          0 :     mX = std::numeric_limits<double>::quiet_NaN();
      75                 :          0 :     mY = std::numeric_limits<double>::quiet_NaN();
      76                 :          0 :   }
      77                 :        161 : }
      78                 :            : 
      79                 :          1 : QgsPoint::QgsPoint( QPointF p )
      80                 :          1 :   : mX( p.x() )
      81                 :          1 :   , mY( p.y() )
      82                 :          1 :   , mZ( std::numeric_limits<double>::quiet_NaN() )
      83                 :          1 :   , mM( std::numeric_limits<double>::quiet_NaN() )
      84                 :          2 : {
      85                 :          1 :   mWkbType = QgsWkbTypes::Point;
      86                 :          1 : }
      87                 :            : 
      88                 :     263600 : QgsPoint::QgsPoint( QgsWkbTypes::Type wkbType, double x, double y, double z, double m )
      89                 :     263600 :   : mX( x )
      90                 :     263600 :   , mY( y )
      91                 :     263600 :   , mZ( QgsWkbTypes::hasZ( wkbType ) ? z : std::numeric_limits<double>::quiet_NaN() )
      92                 :     263600 :   , mM( QgsWkbTypes::hasM( wkbType ) ? m : std::numeric_limits<double>::quiet_NaN() )
      93                 :     527200 : {
      94                 :            :   Q_ASSERT( QgsWkbTypes::flatType( wkbType ) == QgsWkbTypes::Point );
      95                 :     263600 :   mWkbType = wkbType;
      96                 :     263600 : }
      97                 :            : 
      98                 :            : /***************************************************************************
      99                 :            :  * This class is considered CRITICAL and any change MUST be accompanied with
     100                 :            :  * full unit tests.
     101                 :            :  * See details in QEP #17
     102                 :            :  ****************************************************************************/
     103                 :            : 
     104                 :        140 : QgsPoint *QgsPoint::clone() const
     105                 :            : {
     106                 :        140 :   return new QgsPoint( *this );
     107                 :          0 : }
     108                 :            : 
     109                 :         10 : QgsPoint *QgsPoint::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
     110                 :            : {
     111                 :            :   // helper function
     112                 :         40 :   auto gridifyValue = []( double value, double spacing, bool extraCondition = true ) -> double
     113                 :            :   {
     114                 :         40 :     if ( spacing > 0 && extraCondition )
     115                 :         19 :       return  std::round( value / spacing ) * spacing;
     116                 :            :     else
     117                 :         21 :       return value;
     118                 :         40 :   };
     119                 :            : 
     120                 :            :   // Get the new values
     121                 :         10 :   auto x = gridifyValue( mX, hSpacing );
     122                 :         10 :   auto y = gridifyValue( mY, vSpacing );
     123                 :         10 :   auto z = gridifyValue( mZ, dSpacing, QgsWkbTypes::hasZ( mWkbType ) );
     124                 :         10 :   auto m = gridifyValue( mM, mSpacing, QgsWkbTypes::hasM( mWkbType ) );
     125                 :            : 
     126                 :            :   // return the new object
     127                 :         10 :   return new QgsPoint( mWkbType, x, y, z, m );
     128                 :          0 : }
     129                 :            : 
     130                 :          3 : bool QgsPoint::removeDuplicateNodes( double, bool )
     131                 :            : {
     132                 :          3 :   return false;
     133                 :            : }
     134                 :            : 
     135                 :         13 : bool QgsPoint::fromWkb( QgsConstWkbPtr &wkbPtr )
     136                 :            : {
     137                 :         13 :   QgsWkbTypes::Type type = wkbPtr.readHeader();
     138                 :         13 :   if ( QgsWkbTypes::flatType( type ) != QgsWkbTypes::Point )
     139                 :            :   {
     140                 :          2 :     clear();
     141                 :          2 :     return false;
     142                 :            :   }
     143                 :         11 :   mWkbType = type;
     144                 :            : 
     145                 :         11 :   wkbPtr >> mX;
     146                 :         11 :   wkbPtr >> mY;
     147                 :         11 :   if ( is3D() )
     148                 :          5 :     wkbPtr >> mZ;
     149                 :         11 :   if ( isMeasure() )
     150                 :          5 :     wkbPtr >> mM;
     151                 :            : 
     152                 :         11 :   clearCache();
     153                 :            : 
     154                 :         11 :   return true;
     155                 :         13 : }
     156                 :            : 
     157                 :            : /***************************************************************************
     158                 :            :  * This class is considered CRITICAL and any change MUST be accompanied with
     159                 :            :  * full unit tests.
     160                 :            :  * See details in QEP #17
     161                 :            :  ****************************************************************************/
     162                 :            : 
     163                 :        509 : bool QgsPoint::fromWkt( const QString &wkt )
     164                 :            : {
     165                 :        509 :   clear();
     166                 :            : 
     167                 :        509 :   QPair<QgsWkbTypes::Type, QString> parts = QgsGeometryUtils::wktReadBlock( wkt );
     168                 :            : 
     169                 :        509 :   if ( QgsWkbTypes::flatType( parts.first ) != QgsWkbTypes::Point )
     170                 :          1 :     return false;
     171                 :        508 :   mWkbType = parts.first;
     172                 :            : 
     173                 :        508 :   QString secondWithoutParentheses = parts.second;
     174                 :        508 :   secondWithoutParentheses = secondWithoutParentheses.remove( '(' ).remove( ')' ).simplified().remove( ' ' );
     175                 :        508 :   parts.second = parts.second.remove( '(' ).remove( ')' );
     176                 :        615 :   if ( ( parts.second.compare( QLatin1String( "EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
     177                 :        107 :        secondWithoutParentheses.isEmpty() )
     178                 :        402 :     return true;
     179                 :            : 
     180                 :        212 :   QRegularExpression rx( QStringLiteral( "\\s" ) );
     181                 :            : #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
     182                 :            :   QStringList coordinates = parts.second.split( rx, QString::SkipEmptyParts );
     183                 :            : #else
     184                 :        106 :   QStringList coordinates = parts.second.split( rx, Qt::SkipEmptyParts );
     185                 :            : #endif
     186                 :            : 
     187                 :            :   // So far the parser hasn't looked at the coordinates. We'll avoid having anything but numbers and return NULL instead of 0 as a coordinate.
     188                 :            :   // Without this check, "POINT (a, b)" or "POINT (( 4, 3 ))" returned "POINT (0 ,0)"
     189                 :            :   // And some strange conversion...
     190                 :            :   // .. python:
     191                 :            :   // p = QgsPoint()
     192                 :            :   // p.fromWkt("POINT (-3.12, -4.2")
     193                 :            :   // False
     194                 :            :   // p.fromWkt( "POINT (-5.1234, -1.4321)" )
     195                 :            :   // True
     196                 :            :   // p.asWkt()
     197                 :            :   // 'Point (0 -1.43209999999999993)'
     198                 :        212 :   QRegularExpression rxIsNumber( QStringLiteral( "^[+-]?(\\d\\.?\\d*[Ee][+\\-]?\\d+|(\\d+\\.\\d*|\\d*\\.\\d+)|\\d+)$" ) );
     199                 :        106 :   if ( coordinates.filter( rxIsNumber ).size() != coordinates.size() )
     200                 :         11 :     return false;
     201                 :            : 
     202                 :         95 :   if ( coordinates.size() < 2 )
     203                 :            :   {
     204                 :          1 :     clear();
     205                 :          1 :     return false;
     206                 :            :   }
     207                 :         94 :   else if ( coordinates.size() == 3 && !is3D() && !isMeasure() )
     208                 :            :   {
     209                 :            :     // 3 dimensional coordinates, but not specifically marked as such. We allow this
     210                 :            :     // anyway and upgrade geometry to have Z dimension
     211                 :          0 :     mWkbType = QgsWkbTypes::addZ( mWkbType );
     212                 :          0 :   }
     213                 :         94 :   else if ( coordinates.size() >= 4 && ( !is3D() || !isMeasure() ) )
     214                 :            :   {
     215                 :            :     // 4 (or more) dimensional coordinates, but not specifically marked as such. We allow this
     216                 :            :     // anyway and upgrade geometry to have Z&M dimensions
     217                 :          0 :     mWkbType = QgsWkbTypes::addZ( mWkbType );
     218                 :          0 :     mWkbType = QgsWkbTypes::addM( mWkbType );
     219                 :          0 :   }
     220                 :            : 
     221                 :         94 :   int idx = 0;
     222                 :         94 :   mX = coordinates[idx++].toDouble();
     223                 :         94 :   mY = coordinates[idx++].toDouble();
     224                 :         94 :   if ( is3D() && coordinates.length() > 2 )
     225                 :          5 :     mZ = coordinates[idx++].toDouble();
     226                 :         94 :   if ( isMeasure() && coordinates.length() > 2 + is3D() )
     227                 :          6 :     mM = coordinates[idx++].toDouble();
     228                 :            : 
     229                 :         94 :   return true;
     230                 :        509 : }
     231                 :            : 
     232                 :            : /***************************************************************************
     233                 :            :  * This class is considered CRITICAL and any change MUST be accompanied with
     234                 :            :  * full unit tests.
     235                 :            :  * See details in QEP #17
     236                 :            :  ****************************************************************************/
     237                 :            : 
     238                 :         31 : int QgsPoint::wkbSize( WkbFlags ) const
     239                 :            : {
     240                 :         31 :   int binarySize = sizeof( char ) + sizeof( quint32 );
     241                 :         31 :   binarySize += ( 2 + is3D() + isMeasure() ) * sizeof( double );
     242                 :         31 :   return binarySize;
     243                 :            : }
     244                 :            : 
     245                 :         22 : QByteArray QgsPoint::asWkb( WkbFlags flags ) const
     246                 :            : {
     247                 :         22 :   QByteArray wkbArray;
     248                 :         22 :   wkbArray.resize( QgsPoint::wkbSize( flags ) );
     249                 :         22 :   QgsWkbPtr wkb( wkbArray );
     250                 :         22 :   wkb << static_cast<char>( QgsApplication::endian() );
     251                 :         22 :   wkb << static_cast<quint32>( wkbType() );
     252                 :         22 :   wkb << mX << mY;
     253                 :         22 :   if ( is3D() )
     254                 :            :   {
     255                 :          5 :     wkb << mZ;
     256                 :          5 :   }
     257                 :         22 :   if ( isMeasure() )
     258                 :            :   {
     259                 :          5 :     wkb << mM;
     260                 :          5 :   }
     261                 :         22 :   return wkbArray;
     262                 :         22 : }
     263                 :            : 
     264                 :        511 : QString QgsPoint::asWkt( int precision ) const
     265                 :            : {
     266                 :        511 :   QString wkt = wktTypeStr();
     267                 :            : 
     268                 :        511 :   if ( isEmpty() )
     269                 :        404 :     wkt += QLatin1String( " EMPTY" );
     270                 :            :   else
     271                 :            :   {
     272                 :        107 :     wkt += QLatin1String( " (" );
     273                 :        107 :     wkt += qgsDoubleToString( mX, precision ) + ' ' + qgsDoubleToString( mY, precision );
     274                 :        107 :     if ( is3D() )
     275                 :         37 :       wkt += ' ' + qgsDoubleToString( mZ, precision );
     276                 :        107 :     if ( isMeasure() )
     277                 :         25 :       wkt += ' ' + qgsDoubleToString( mM, precision );
     278                 :        107 :     wkt += ')';
     279                 :            :   }
     280                 :        511 :   return wkt;
     281                 :        511 : }
     282                 :            : 
     283                 :          8 : QDomElement QgsPoint::asGml2( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
     284                 :            : {
     285                 :         16 :   QDomElement elemPoint = doc.createElementNS( ns, QStringLiteral( "Point" ) );
     286                 :         16 :   QDomElement elemCoordinates = doc.createElementNS( ns, QStringLiteral( "coordinates" ) );
     287                 :            : 
     288                 :            :   // coordinate separator
     289                 :         16 :   QString cs = QStringLiteral( "," );
     290                 :            :   // tuple separator
     291                 :         16 :   QString ts = QStringLiteral( " " );
     292                 :            : 
     293                 :         16 :   elemCoordinates.setAttribute( QStringLiteral( "cs" ), cs );
     294                 :         16 :   elemCoordinates.setAttribute( QStringLiteral( "ts" ), ts );
     295                 :            : 
     296                 :          8 :   QString strCoordinates;
     297                 :          8 :   if ( axisOrder == QgsAbstractGeometry::AxisOrder::XY )
     298                 :          6 :     strCoordinates = qgsDoubleToString( mX, precision ) + cs + qgsDoubleToString( mY, precision );
     299                 :            :   else
     300                 :          2 :     strCoordinates = qgsDoubleToString( mY, precision ) + cs + qgsDoubleToString( mX, precision );
     301                 :          8 :   elemCoordinates.appendChild( doc.createTextNode( strCoordinates ) );
     302                 :          8 :   elemPoint.appendChild( elemCoordinates );
     303                 :          8 :   return elemPoint;
     304                 :          8 : }
     305                 :            : 
     306                 :         10 : QDomElement QgsPoint::asGml3( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
     307                 :            : {
     308                 :         20 :   QDomElement elemPoint = doc.createElementNS( ns, QStringLiteral( "Point" ) );
     309                 :         20 :   QDomElement elemPosList = doc.createElementNS( ns, QStringLiteral( "pos" ) );
     310                 :         20 :   elemPosList.setAttribute( QStringLiteral( "srsDimension" ), is3D() ? 3 : 2 );
     311                 :         10 :   QString strCoordinates;
     312                 :         10 :   if ( axisOrder == QgsAbstractGeometry::AxisOrder::XY )
     313                 :          7 :     strCoordinates = qgsDoubleToString( mX, precision ) + ' ' + qgsDoubleToString( mY, precision );
     314                 :            :   else
     315                 :          3 :     strCoordinates = qgsDoubleToString( mY, precision ) + ' ' + qgsDoubleToString( mX, precision );
     316                 :         10 :   if ( is3D() )
     317                 :          2 :     strCoordinates += ' ' + qgsDoubleToString( mZ, precision );
     318                 :            : 
     319                 :         10 :   elemPosList.appendChild( doc.createTextNode( strCoordinates ) );
     320                 :         10 :   elemPoint.appendChild( elemPosList );
     321                 :         10 :   return elemPoint;
     322                 :         10 : }
     323                 :            : 
     324                 :            : 
     325                 :          4 : json QgsPoint::asJsonObject( int precision ) const
     326                 :            : {
     327                 :         20 :   json j
     328                 :         12 :   {
     329                 :          4 :     { "type", "Point" },
     330                 :          4 :     { "coordinates", json::array() },
     331                 :            :   };
     332                 :          4 :   if ( ! isEmpty() )
     333                 :            :   {
     334                 :          3 :     j["coordinates"].push_back( qgsRound( mX, precision ) );
     335                 :          3 :     j["coordinates"].push_back( qgsRound( mY, precision ) );
     336                 :          3 :     if ( is3D() )
     337                 :            :     {
     338                 :          0 :       j["coordinates"].push_back( qgsRound( mZ, precision ) );
     339                 :          0 :     }
     340                 :          3 :   }
     341                 :          4 :   return j;
     342                 :          4 : }
     343                 :            : 
     344                 :          6 : QString QgsPoint::asKml( int precision ) const
     345                 :            : {
     346                 :         12 :   return QStringLiteral( "<Point><coordinates>%1,%2</coordinates></Point>" ).arg( qgsDoubleToString( mX, precision ), qgsDoubleToString( mY, precision ) );
     347                 :          0 : }
     348                 :            : 
     349                 :          0 : void QgsPoint::draw( QPainter &p ) const
     350                 :            : {
     351                 :          0 :   p.drawRect( QRectF( mX - 2, mY - 2, 4, 4 ) );
     352                 :          0 : }
     353                 :            : 
     354                 :          0 : QPainterPath QgsPoint::asQPainterPath() const
     355                 :            : {
     356                 :          0 :   return QPainterPath();
     357                 :            : }
     358                 :            : 
     359                 :      22181 : void QgsPoint::clear()
     360                 :            : {
     361                 :      22181 :   mX = mY = std::numeric_limits<double>::quiet_NaN();
     362                 :      22181 :   if ( is3D() )
     363                 :        882 :     mZ = 0.;
     364                 :            :   else
     365                 :      21299 :     mZ = std::numeric_limits<double>::quiet_NaN();
     366                 :            : 
     367                 :      22181 :   if ( isMeasure() )
     368                 :        876 :     mM = 0.;
     369                 :            :   else
     370                 :      21305 :     mM = std::numeric_limits<double>::quiet_NaN();
     371                 :            : 
     372                 :      22181 :   clearCache();
     373                 :      22181 : }
     374                 :            : 
     375                 :            : 
     376                 :            : /***************************************************************************
     377                 :            :  * This class is considered CRITICAL and any change MUST be accompanied with
     378                 :            :  * full unit tests.
     379                 :            :  * See details in QEP #17
     380                 :            :  ****************************************************************************/
     381                 :            : 
     382                 :          2 : void QgsPoint::transform( const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d, bool transformZ )
     383                 :            : {
     384                 :          2 :   clearCache();
     385                 :          2 :   if ( transformZ )
     386                 :            :   {
     387                 :          0 :     ct.transformInPlace( mX, mY, mZ, d );
     388                 :          0 :   }
     389                 :            :   else
     390                 :            :   {
     391                 :          2 :     double z = 0.0;
     392                 :          2 :     ct.transformInPlace( mX, mY, z, d );
     393                 :            :   }
     394                 :          2 : }
     395                 :            : 
     396                 :          3 : QgsCoordinateSequence QgsPoint::coordinateSequence() const
     397                 :            : {
     398                 :          3 :   QgsCoordinateSequence cs;
     399                 :            : 
     400                 :          3 :   cs.append( QgsRingSequence() );
     401                 :          3 :   cs.back().append( QgsPointSequence() << QgsPoint( *this ) );
     402                 :            : 
     403                 :          3 :   return cs;
     404                 :          3 : }
     405                 :            : 
     406                 :          0 : int QgsPoint::nCoordinates() const
     407                 :            : {
     408                 :          0 :   return 1;
     409                 :            : }
     410                 :            : 
     411                 :          3 : int QgsPoint::vertexNumberFromVertexId( QgsVertexId id ) const
     412                 :            : {
     413                 :          3 :   if ( id.vertex != 0 )
     414                 :          2 :     return -1;
     415                 :            :   else
     416                 :          1 :     return 0;
     417                 :          3 : }
     418                 :            : 
     419                 :          1 : QgsAbstractGeometry *QgsPoint::boundary() const
     420                 :            : {
     421                 :          1 :   return nullptr;
     422                 :            : }
     423                 :            : 
     424                 :          1 : bool QgsPoint::isValid( QString &, int ) const
     425                 :            : {
     426                 :          1 :   return true;
     427                 :            : }
     428                 :            : 
     429                 :          1 : bool QgsPoint::insertVertex( QgsVertexId position, const QgsPoint &vertex )
     430                 :            : {
     431                 :            :   Q_UNUSED( position )
     432                 :          1 :   Q_UNUSED( vertex )
     433                 :          1 :   return false;
     434                 :            : }
     435                 :            : 
     436                 :            : /***************************************************************************
     437                 :            :  * This class is considered CRITICAL and any change MUST be accompanied with
     438                 :            :  * full unit tests.
     439                 :            :  * See details in QEP #17
     440                 :            :  ****************************************************************************/
     441                 :            : 
     442                 :         15 : bool QgsPoint::moveVertex( QgsVertexId position, const QgsPoint &newPos )
     443                 :            : {
     444                 :            :   Q_UNUSED( position )
     445                 :         15 :   clearCache();
     446                 :         15 :   mX = newPos.mX;
     447                 :         15 :   mY = newPos.mY;
     448                 :         15 :   if ( is3D() && newPos.is3D() )
     449                 :            :   {
     450                 :          3 :     mZ = newPos.mZ;
     451                 :          3 :   }
     452                 :         15 :   if ( isMeasure() && newPos.isMeasure() )
     453                 :            :   {
     454                 :          3 :     mM = newPos.mM;
     455                 :          3 :   }
     456                 :         15 :   return true;
     457                 :            : }
     458                 :            : 
     459                 :          1 : bool QgsPoint::deleteVertex( QgsVertexId position )
     460                 :            : {
     461                 :            :   Q_UNUSED( position )
     462                 :          1 :   return false;
     463                 :            : }
     464                 :            : 
     465                 :          3 : double QgsPoint::closestSegment( const QgsPoint &pt, QgsPoint &segmentPt,  QgsVertexId &vertexAfter, int *leftOf, double epsilon ) const
     466                 :            : {
     467                 :          3 :   Q_UNUSED( pt )
     468                 :          3 :   Q_UNUSED( segmentPt )
     469                 :          3 :   Q_UNUSED( vertexAfter )
     470                 :          3 :   if ( leftOf )
     471                 :          0 :     *leftOf = 0;
     472                 :            :   Q_UNUSED( epsilon )
     473                 :          3 :   return -1;  // no segments - return error
     474                 :            : }
     475                 :            : 
     476                 :          9 : bool QgsPoint::nextVertex( QgsVertexId &id, QgsPoint &vertex ) const
     477                 :            : {
     478                 :          9 :   if ( id.vertex < 0 )
     479                 :            :   {
     480                 :          6 :     id.vertex = 0;
     481                 :          6 :     if ( id.part < 0 )
     482                 :            :     {
     483                 :          3 :       id.part = 0;
     484                 :          3 :     }
     485                 :          6 :     if ( id.ring < 0 )
     486                 :            :     {
     487                 :          3 :       id.ring = 0;
     488                 :          3 :     }
     489                 :          6 :     vertex = *this;
     490                 :          6 :     return true;
     491                 :            :   }
     492                 :            :   else
     493                 :            :   {
     494                 :          3 :     return false;
     495                 :            :   }
     496                 :          9 : }
     497                 :            : 
     498                 :          3 : void QgsPoint::adjacentVertices( QgsVertexId, QgsVertexId &previousVertex, QgsVertexId &nextVertex ) const
     499                 :            : {
     500                 :          3 :   previousVertex = QgsVertexId();
     501                 :          3 :   nextVertex = QgsVertexId();
     502                 :          3 : }
     503                 :            : 
     504                 :          1 : double QgsPoint::vertexAngle( QgsVertexId vertex ) const
     505                 :            : {
     506                 :            :   Q_UNUSED( vertex )
     507                 :          1 :   return 0.0;
     508                 :            : }
     509                 :            : 
     510                 :         57 : int QgsPoint::vertexCount( int, int ) const
     511                 :            : {
     512                 :         57 :   return 1;
     513                 :            : }
     514                 :            : 
     515                 :         40 : int QgsPoint::ringCount( int ) const
     516                 :            : {
     517                 :         40 :   return 1;
     518                 :            : }
     519                 :            : 
     520                 :         58 : int QgsPoint::partCount() const
     521                 :            : {
     522                 :         58 :   return 1;
     523                 :            : }
     524                 :            : 
     525                 :        110 : QgsPoint QgsPoint::vertexAt( QgsVertexId ) const
     526                 :            : {
     527                 :        110 :   return *this;
     528                 :            : }
     529                 :            : 
     530                 :          1 : QgsPoint *QgsPoint::toCurveType() const
     531                 :            : {
     532                 :          1 :   return clone();
     533                 :            : }
     534                 :            : 
     535                 :          6 : double QgsPoint::segmentLength( QgsVertexId ) const
     536                 :            : {
     537                 :          6 :   return 0.0;
     538                 :            : }
     539                 :            : 
     540                 :          3 : bool QgsPoint::boundingBoxIntersects( const QgsRectangle &rectangle ) const
     541                 :            : {
     542                 :          3 :   return rectangle.contains( mX, mY );
     543                 :            : }
     544                 :            : 
     545                 :            : /***************************************************************************
     546                 :            :  * This class is considered CRITICAL and any change MUST be accompanied with
     547                 :            :  * full unit tests.
     548                 :            :  * See details in QEP #17
     549                 :            :  ****************************************************************************/
     550                 :            : 
     551                 :         11 : bool QgsPoint::addZValue( double zValue )
     552                 :            : {
     553                 :         11 :   if ( QgsWkbTypes::hasZ( mWkbType ) )
     554                 :          1 :     return false;
     555                 :            : 
     556                 :         10 :   mWkbType = QgsWkbTypes::addZ( mWkbType );
     557                 :         10 :   mZ = zValue;
     558                 :         10 :   clearCache();
     559                 :         10 :   return true;
     560                 :         11 : }
     561                 :            : 
     562                 :          9 : bool QgsPoint::addMValue( double mValue )
     563                 :            : {
     564                 :          9 :   if ( QgsWkbTypes::hasM( mWkbType ) )
     565                 :          1 :     return false;
     566                 :            : 
     567                 :          8 :   mWkbType = QgsWkbTypes::addM( mWkbType );
     568                 :          8 :   mM = mValue;
     569                 :          8 :   clearCache();
     570                 :          8 :   return true;
     571                 :          9 : }
     572                 :            : 
     573                 :          8 : void QgsPoint::transform( const QTransform &t, double zTranslate, double zScale, double mTranslate, double mScale )
     574                 :            : {
     575                 :          8 :   clearCache();
     576                 :            :   qreal x, y;
     577                 :          8 :   t.map( mX, mY, &x, &y );
     578                 :          8 :   mX = x;
     579                 :          8 :   mY = y;
     580                 :            : 
     581                 :          8 :   if ( is3D() )
     582                 :            :   {
     583                 :          2 :     mZ = mZ * zScale + zTranslate;
     584                 :          2 :   }
     585                 :          8 :   if ( isMeasure() )
     586                 :            :   {
     587                 :          2 :     mM = mM * mScale + mTranslate;
     588                 :          2 :   }
     589                 :          8 : }
     590                 :            : 
     591                 :            : 
     592                 :         17 : bool QgsPoint::dropZValue()
     593                 :            : {
     594                 :         17 :   if ( !is3D() )
     595                 :         11 :     return false;
     596                 :            : 
     597                 :          6 :   mWkbType = QgsWkbTypes::dropZ( mWkbType );
     598                 :          6 :   mZ = std::numeric_limits<double>::quiet_NaN();
     599                 :          6 :   clearCache();
     600                 :          6 :   return true;
     601                 :         17 : }
     602                 :            : 
     603                 :          6 : bool QgsPoint::dropMValue()
     604                 :            : {
     605                 :          6 :   if ( !isMeasure() )
     606                 :          2 :     return false;
     607                 :            : 
     608                 :          4 :   mWkbType = QgsWkbTypes::dropM( mWkbType );
     609                 :          4 :   mM = std::numeric_limits<double>::quiet_NaN();
     610                 :          4 :   clearCache();
     611                 :          4 :   return true;
     612                 :          6 : }
     613                 :            : 
     614                 :          1 : void QgsPoint::swapXy()
     615                 :            : {
     616                 :          1 :   std::swap( mX, mY );
     617                 :          1 :   clearCache();
     618                 :          1 : }
     619                 :            : 
     620                 :         13 : bool QgsPoint::convertTo( QgsWkbTypes::Type type )
     621                 :            : {
     622                 :         13 :   if ( type == mWkbType )
     623                 :          1 :     return true;
     624                 :            : 
     625                 :         12 :   clearCache();
     626                 :            : 
     627                 :         12 :   switch ( type )
     628                 :            :   {
     629                 :            :     case QgsWkbTypes::Point:
     630                 :          4 :       mZ = std::numeric_limits<double>::quiet_NaN();
     631                 :          4 :       mM = std::numeric_limits<double>::quiet_NaN();
     632                 :          4 :       mWkbType = type;
     633                 :          4 :       return true;
     634                 :            :     case QgsWkbTypes::PointZ:
     635                 :            :     case QgsWkbTypes::Point25D:
     636                 :          5 :       mM = std::numeric_limits<double>::quiet_NaN();
     637                 :          5 :       mWkbType = type;
     638                 :          5 :       return true;
     639                 :            :     case QgsWkbTypes::PointM:
     640                 :          1 :       mZ = std::numeric_limits<double>::quiet_NaN();
     641                 :          1 :       mWkbType = type;
     642                 :          1 :       return true;
     643                 :            :     case QgsWkbTypes::PointZM:
     644                 :          1 :       mWkbType = type;
     645                 :          1 :       return true;
     646                 :            :     default:
     647                 :          1 :       break;
     648                 :            :   }
     649                 :            : 
     650                 :          1 :   return false;
     651                 :         13 : }
     652                 :            : 
     653                 :          2 : bool QgsPoint::transform( QgsAbstractGeometryTransformer *transformer, QgsFeedback * )
     654                 :            : {
     655                 :          2 :   if ( !transformer )
     656                 :          0 :     return false;
     657                 :            : 
     658                 :          2 :   const bool res = transformer->transformPoint( mX, mY, mZ, mM );
     659                 :          2 :   clearCache();
     660                 :          2 :   return res;
     661                 :          2 : }
     662                 :            : 
     663                 :          1 : void QgsPoint::filterVertices( const std::function<bool ( const QgsPoint & )> & )
     664                 :            : {
     665                 :            :   // no meaning for points
     666                 :          1 : }
     667                 :            : 
     668                 :          3 : void QgsPoint::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
     669                 :            : {
     670                 :          3 :   QgsPoint res = transform( *this );
     671                 :          3 :   mX = res.x();
     672                 :          3 :   mY = res.y();
     673                 :          3 :   if ( is3D() )
     674                 :          2 :     mZ = res.z();
     675                 :          3 :   if ( isMeasure() )
     676                 :          2 :     mM = res.m();
     677                 :          3 :   clearCache();
     678                 :          3 : }
     679                 :            : 
     680                 :          3 : double QgsPoint::distance3D( double x, double y, double z ) const
     681                 :            : {
     682                 :          3 :   double zDistSquared = 0.0;
     683                 :          3 :   if ( is3D() || !std::isnan( z ) )
     684                 :          3 :     zDistSquared = ( mZ - z ) * ( mZ - z );
     685                 :            : 
     686                 :          3 :   return std::sqrt( ( mX - x ) * ( mX - x ) + ( mY - y ) * ( mY - y ) + zDistSquared );
     687                 :            : }
     688                 :            : 
     689                 :         28 : double QgsPoint::distance3D( const QgsPoint &other ) const
     690                 :            : {
     691                 :         28 :   double zDistSquared = 0.0;
     692                 :         28 :   if ( is3D() || other.is3D() )
     693                 :         26 :     zDistSquared = ( mZ - other.z() ) * ( mZ - other.z() );
     694                 :            : 
     695                 :         28 :   return std::sqrt( ( mX - other.x() ) * ( mX - other.x() ) + ( mY - other.y() ) * ( mY - other.y() ) + zDistSquared );
     696                 :            : }
     697                 :            : 
     698                 :          5 : double QgsPoint::distanceSquared3D( double x, double y, double z ) const
     699                 :            : {
     700                 :          5 :   double zDistSquared = 0.0;
     701                 :          5 :   if ( is3D() || !std::isnan( z ) )
     702                 :          5 :     zDistSquared = ( mZ - z ) * ( mZ - z );
     703                 :            : 
     704                 :          5 :   return ( mX - x ) * ( mX - x ) + ( mY - y ) * ( mY - y ) + zDistSquared;
     705                 :            : }
     706                 :            : 
     707                 :          5 : double QgsPoint::distanceSquared3D( const QgsPoint &other ) const
     708                 :            : {
     709                 :          5 :   double zDistSquared = 0.0;
     710                 :          5 :   if ( is3D() || other.is3D() )
     711                 :          4 :     zDistSquared = ( mZ - other.z() ) * ( mZ - other.z() );
     712                 :            : 
     713                 :          5 :   return ( mX - other.x() ) * ( mX - other.x() ) + ( mY - other.y() ) * ( mY - other.y() ) + zDistSquared;
     714                 :            : }
     715                 :            : 
     716                 :         91 : double QgsPoint::azimuth( const QgsPoint &other ) const
     717                 :            : {
     718                 :         91 :   double dx = other.x() - mX;
     719                 :         91 :   double dy = other.y() - mY;
     720                 :         91 :   return ( std::atan2( dx, dy ) * 180.0 / M_PI );
     721                 :            : }
     722                 :            : 
     723                 :         17 : double QgsPoint::inclination( const QgsPoint &other ) const
     724                 :            : {
     725                 :         17 :   double distance = distance3D( other );
     726                 :         17 :   if ( qgsDoubleNear( distance, 0.0 ) )
     727                 :            :   {
     728                 :          2 :     return 90.0;
     729                 :            :   }
     730                 :         15 :   double dz = other.z() - mZ;
     731                 :            : 
     732                 :         15 :   return ( std::acos( dz / distance ) * 180.0 / M_PI );
     733                 :         17 : }
     734                 :            : 
     735                 :        588 : QgsPoint QgsPoint::project( double distance, double azimuth, double inclination ) const
     736                 :            : {
     737                 :        588 :   QgsWkbTypes::Type pType = mWkbType;
     738                 :        588 :   double radsXy = azimuth * M_PI / 180.0;
     739                 :        588 :   double dx = 0.0, dy = 0.0, dz = 0.0;
     740                 :            : 
     741                 :        588 :   inclination = std::fmod( inclination, 360.0 );
     742                 :            : 
     743                 :        588 :   if ( !qgsDoubleNear( inclination, 90.0 ) )
     744                 :         26 :     pType = QgsWkbTypes::addZ( pType );
     745                 :            : 
     746                 :        588 :   if ( !is3D() && qgsDoubleNear( inclination, 90.0 ) )
     747                 :            :   {
     748                 :        521 :     dx = distance * std::sin( radsXy );
     749                 :        521 :     dy = distance * std::cos( radsXy );
     750                 :        521 :   }
     751                 :            :   else
     752                 :            :   {
     753                 :         67 :     double radsZ = inclination * M_PI / 180.0;
     754                 :         67 :     dx = distance * std::sin( radsZ ) * std::sin( radsXy );
     755                 :         67 :     dy = distance * std::sin( radsZ ) * std::cos( radsXy );
     756                 :         67 :     dz = distance * std::cos( radsZ );
     757                 :            :   }
     758                 :            : 
     759                 :        588 :   return QgsPoint( mX + dx, mY + dy, mZ + dz, mM, pType );
     760                 :            : }
     761                 :            : 
     762                 :        923 : bool QgsPoint::isEmpty() const
     763                 :            : {
     764                 :        923 :   return std::isnan( mX ) || std::isnan( mY );
     765                 :            : }
     766                 :            : 
     767                 :        224 : QgsRectangle QgsPoint::boundingBox() const
     768                 :            : {
     769                 :        224 :   return QgsRectangle( mX, mY, mX, mY );
     770                 :            : }
     771                 :            : 
     772                 :        516 : QString QgsPoint::geometryType() const
     773                 :            : {
     774                 :       1032 :   return QStringLiteral( "Point" );
     775                 :            : }
     776                 :            : 
     777                 :         22 : int QgsPoint::dimension() const
     778                 :            : {
     779                 :         22 :   return 0;
     780                 :            : }
     781                 :            : 
     782                 :         10 : int QgsPoint::childCount() const
     783                 :            : {
     784                 :         10 :   return 1;
     785                 :            : }
     786                 :            : 
     787                 :          6 : QgsPoint QgsPoint::childPoint( int index ) const
     788                 :            : {
     789                 :            :   Q_ASSERT( index == 0 );
     790                 :          6 :   return *this;
     791                 :            : }
     792                 :            : 
     793                 :          1 : QgsPoint *QgsPoint::createEmptyWithSameType() const
     794                 :            : {
     795                 :          1 :   double nan = std::numeric_limits<double>::quiet_NaN();
     796                 :          1 :   return new QgsPoint( nan, nan, nan, nan, mWkbType );
     797                 :          0 : }

Generated by: LCOV version 1.14