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

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                          qgscurve.cpp
       3                 :            :                          --------------
       4                 :            :     begin                : November 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                 :            : #include <memory>
      19                 :            : 
      20                 :            : #include "qgscurve.h"
      21                 :            : #include "qgslinestring.h"
      22                 :            : #include "qgspoint.h"
      23                 :            : #include "qgsmultipoint.h"
      24                 :            : #include "qgsgeos.h"
      25                 :            : 
      26                 :        310 : bool QgsCurve::operator==( const QgsAbstractGeometry &other ) const
      27                 :            : {
      28                 :        310 :   const QgsCurve *otherCurve = qgsgeometry_cast< const QgsCurve * >( &other );
      29                 :        310 :   if ( !otherCurve )
      30                 :          2 :     return false;
      31                 :            : 
      32                 :        308 :   return equals( *otherCurve );
      33                 :        310 : }
      34                 :            : 
      35                 :        175 : bool QgsCurve::operator!=( const QgsAbstractGeometry &other ) const
      36                 :            : {
      37                 :        175 :   return !operator==( other );
      38                 :            : }
      39                 :            : 
      40                 :         45 : bool QgsCurve::isClosed() const
      41                 :            : {
      42                 :         45 :   if ( numPoints() == 0 )
      43                 :          4 :     return false;
      44                 :            : 
      45                 :            :   //don't consider M-coordinates when testing closedness
      46                 :         41 :   QgsPoint start = startPoint();
      47                 :         41 :   QgsPoint end = endPoint();
      48                 :            : 
      49                 :         61 :   bool closed = qgsDoubleNear( start.x(), end.x() ) &&
      50                 :         20 :                 qgsDoubleNear( start.y(), end.y() );
      51                 :         41 :   if ( is3D() && closed )
      52                 :          0 :     closed &= qgsDoubleNear( start.z(), end.z() ) || ( std::isnan( start.z() ) && std::isnan( end.z() ) );
      53                 :         41 :   return closed;
      54                 :         45 : }
      55                 :            : 
      56                 :        230 : bool QgsCurve::isRing() const
      57                 :            : {
      58                 :        230 :   return ( isClosed() && numPoints() >= 4 );
      59                 :            : }
      60                 :            : 
      61                 :          0 : QPainterPath QgsCurve::asQPainterPath() const
      62                 :            : {
      63                 :          0 :   QPainterPath p;
      64                 :          0 :   addToPainterPath( p );
      65                 :          0 :   return p;
      66                 :          0 : }
      67                 :            : 
      68                 :         62 : QgsCoordinateSequence QgsCurve::coordinateSequence() const
      69                 :            : {
      70                 :         62 :   QgsCoordinateSequence sequence;
      71                 :         62 :   sequence.append( QgsRingSequence() );
      72                 :         62 :   sequence.back().append( QgsPointSequence() );
      73                 :         62 :   points( sequence.back().back() );
      74                 :            : 
      75                 :         62 :   return sequence;
      76                 :         62 : }
      77                 :            : 
      78                 :        686 : bool QgsCurve::nextVertex( QgsVertexId &id, QgsPoint &vertex ) const
      79                 :            : {
      80                 :        686 :   if ( id.vertex < 0 )
      81                 :            :   {
      82                 :        132 :     id.vertex = 0;
      83                 :        132 :     if ( id.part < 0 )
      84                 :            :     {
      85                 :         27 :       id.part = 0;
      86                 :         27 :     }
      87                 :        132 :     if ( id.ring < 0 )
      88                 :            :     {
      89                 :         27 :       id.ring = 0;
      90                 :         27 :     }
      91                 :        132 :   }
      92                 :            :   else
      93                 :            :   {
      94                 :        554 :     if ( id.vertex + 1 >= numPoints() )
      95                 :            :     {
      96                 :         86 :       return false;
      97                 :            :     }
      98                 :        468 :     ++id.vertex;
      99                 :            :   }
     100                 :        600 :   return pointAt( id.vertex, vertex, id.type );
     101                 :        686 : }
     102                 :            : 
     103                 :         12 : void QgsCurve::adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex ) const
     104                 :            : {
     105                 :         12 :   int n = numPoints();
     106                 :         12 :   if ( vertex.vertex < 0 || vertex.vertex >= n )
     107                 :            :   {
     108                 :          2 :     previousVertex = QgsVertexId();
     109                 :          2 :     nextVertex = QgsVertexId();
     110                 :          2 :     return;
     111                 :            :   }
     112                 :            : 
     113                 :         10 :   if ( vertex.vertex == 0 )
     114                 :            :   {
     115                 :          3 :     previousVertex = QgsVertexId();
     116                 :          3 :   }
     117                 :            :   else
     118                 :            :   {
     119                 :          7 :     previousVertex = QgsVertexId( vertex.part, vertex.ring, vertex.vertex - 1 );
     120                 :            :   }
     121                 :         10 :   if ( vertex.vertex == n - 1 )
     122                 :            :   {
     123                 :          2 :     nextVertex = QgsVertexId();
     124                 :          2 :   }
     125                 :            :   else
     126                 :            :   {
     127                 :          8 :     nextVertex = QgsVertexId( vertex.part, vertex.ring, vertex.vertex + 1 );
     128                 :            :   }
     129                 :         12 : }
     130                 :            : 
     131                 :         76 : int QgsCurve::vertexNumberFromVertexId( QgsVertexId id ) const
     132                 :            : {
     133                 :         76 :   if ( id.part != 0 || id.ring != 0 )
     134                 :          9 :     return -1;
     135                 :         67 :   if ( id.vertex < 0 || id.vertex >= numPoints() )
     136                 :         18 :     return -1;
     137                 :         49 :   return id.vertex;
     138                 :         76 : }
     139                 :            : 
     140                 :         12 : QgsAbstractGeometry *QgsCurve::boundary() const
     141                 :            : {
     142                 :         12 :   if ( isEmpty() )
     143                 :          3 :     return nullptr;
     144                 :            : 
     145                 :          9 :   if ( isClosed() )
     146                 :          3 :     return nullptr;
     147                 :            : 
     148                 :          6 :   QgsMultiPoint *multiPoint = new QgsMultiPoint();
     149                 :          6 :   multiPoint->reserve( 2 );
     150                 :          6 :   multiPoint->addGeometry( new QgsPoint( startPoint() ) );
     151                 :          6 :   multiPoint->addGeometry( new QgsPoint( endPoint() ) );
     152                 :          6 :   return multiPoint;
     153                 :         12 : }
     154                 :            : 
     155                 :         10 : QString QgsCurve::asKml( int precision ) const
     156                 :            : {
     157                 :         10 :   std::unique_ptr<QgsLineString> lineString( curveToLine() );
     158                 :         10 :   if ( !lineString )
     159                 :            :   {
     160                 :          0 :     return QString();
     161                 :            :   }
     162                 :         10 :   QString kml = lineString->asKml( precision );
     163                 :         10 :   return kml;
     164                 :         10 : }
     165                 :            : 
     166                 :         16 : QgsCurve *QgsCurve::segmentize( double tolerance, SegmentationToleranceType toleranceType ) const
     167                 :            : {
     168                 :         16 :   return curveToLine( tolerance, toleranceType );
     169                 :            : }
     170                 :            : 
     171                 :        981 : int QgsCurve::vertexCount( int part, int ring ) const
     172                 :            : {
     173                 :            :   Q_UNUSED( part )
     174                 :            :   Q_UNUSED( ring )
     175                 :        981 :   return numPoints();
     176                 :            : }
     177                 :            : 
     178                 :        286 : int QgsCurve::ringCount( int part ) const
     179                 :            : {
     180                 :            :   Q_UNUSED( part )
     181                 :        286 :   return numPoints() > 0 ? 1 : 0;
     182                 :            : }
     183                 :            : 
     184                 :        222 : int QgsCurve::partCount() const
     185                 :            : {
     186                 :        222 :   return numPoints() > 0 ? 1 : 0;
     187                 :            : }
     188                 :            : 
     189                 :      12615 : QgsPoint QgsCurve::vertexAt( QgsVertexId id ) const
     190                 :            : {
     191                 :      12615 :   QgsPoint v;
     192                 :            :   QgsVertexId::VertexType type;
     193                 :      12615 :   pointAt( id.vertex, v, type );
     194                 :      12615 :   return v;
     195                 :      12615 : }
     196                 :            : 
     197                 :          3 : QgsCurve *QgsCurve::toCurveType() const
     198                 :            : {
     199                 :          3 :   return clone();
     200                 :            : }
     201                 :            : 
     202                 :       1510 : QgsRectangle QgsCurve::boundingBox() const
     203                 :            : {
     204                 :       1510 :   if ( mBoundingBox.isNull() )
     205                 :            :   {
     206                 :       1270 :     mBoundingBox = calculateBoundingBox();
     207                 :       1270 :   }
     208                 :       1510 :   return mBoundingBox;
     209                 :            : }
     210                 :            : 
     211                 :         11 : bool QgsCurve::isValid( QString &error, int flags ) const
     212                 :            : {
     213                 :         11 :   if ( flags == 0 && mHasCachedValidity )
     214                 :            :   {
     215                 :            :     // use cached validity results
     216                 :          5 :     error = mValidityFailureReason;
     217                 :          5 :     return error.isEmpty();
     218                 :            :   }
     219                 :            : 
     220                 :          6 :   QgsGeos geos( this );
     221                 :          6 :   bool res = geos.isValid( &error, flags & QgsGeometry::FlagAllowSelfTouchingHoles, nullptr );
     222                 :          6 :   if ( flags == 0 )
     223                 :            :   {
     224                 :          6 :     mValidityFailureReason = !res ? error : QString();
     225                 :          6 :     mHasCachedValidity = true;
     226                 :          6 :   }
     227                 :          6 :   return res;
     228                 :         11 : }
     229                 :            : 
     230                 :          2 : QPolygonF QgsCurve::asQPolygonF() const
     231                 :            : {
     232                 :          2 :   std::unique_ptr< QgsLineString > segmentized( curveToLine() );
     233                 :          2 :   return segmentized->asQPolygonF();
     234                 :          2 : }
     235                 :            : 
     236                 :          0 : double QgsCurve::straightDistance2d() const
     237                 :            : {
     238                 :          0 :   return startPoint().distance( endPoint() );
     239                 :          0 : }
     240                 :            : 
     241                 :          0 : double QgsCurve::sinuosity() const
     242                 :            : {
     243                 :          0 :   double d = straightDistance2d();
     244                 :          0 :   if ( qgsDoubleNear( d, 0.0 ) )
     245                 :          0 :     return std::numeric_limits<double>::quiet_NaN();
     246                 :            : 
     247                 :          0 :   return length() / d;
     248                 :          0 : }
     249                 :            : 
     250                 :         17 : QgsCurve::Orientation QgsCurve::orientation() const
     251                 :            : {
     252                 :         17 :   double a = 0;
     253                 :         17 :   sumUpArea( a );
     254                 :         17 :   return a < 0 ? Clockwise : CounterClockwise;
     255                 :            : }
     256                 :            : 
     257                 :       4975 : void QgsCurve::clearCache() const
     258                 :            : {
     259                 :       4975 :   mBoundingBox = QgsRectangle();
     260                 :       4975 :   mHasCachedValidity = false;
     261                 :       4975 :   mValidityFailureReason.clear();
     262                 :       4975 :   QgsAbstractGeometry::clearCache();
     263                 :       4975 : }
     264                 :            : 
     265                 :        239 : int QgsCurve::childCount() const
     266                 :            : {
     267                 :        239 :   return numPoints();
     268                 :            : }
     269                 :            : 
     270                 :        227 : QgsPoint QgsCurve::childPoint( int index ) const
     271                 :            : {
     272                 :        227 :   QgsPoint point;
     273                 :            :   QgsVertexId::VertexType type;
     274                 :        227 :   bool res = pointAt( index, point, type );
     275                 :            :   Q_ASSERT( res );
     276                 :            :   Q_UNUSED( res )
     277                 :        227 :   return point;
     278                 :        227 : }
     279                 :            : 
     280                 :         28 : bool QgsCurve::snapToGridPrivate( double hSpacing, double vSpacing, double dSpacing, double mSpacing,
     281                 :            :                                   const QVector<double> &srcX, const QVector<double> &srcY, const QVector<double> &srcZ, const QVector<double> &srcM,
     282                 :            :                                   QVector<double> &outX, QVector<double> &outY, QVector<double> &outZ, QVector<double> &outM ) const
     283                 :            : {
     284                 :         28 :   int length = numPoints();
     285                 :            : 
     286                 :         28 :   if ( length <= 0 )
     287                 :          0 :     return false;
     288                 :            : 
     289                 :         28 :   bool hasZ = is3D();
     290                 :         28 :   bool hasM = isMeasure();
     291                 :            : 
     292                 :            :   // helper functions
     293                 :        123 :   auto roundVertex = [hSpacing, vSpacing, dSpacing, mSpacing, hasZ, hasM, &srcX, &srcY, &srcZ, &srcM]( QgsPoint & out, int i )
     294                 :            :   {
     295                 :         95 :     if ( hSpacing > 0 )
     296                 :         89 :       out.setX( std::round( srcX.at( i ) / hSpacing ) * hSpacing );
     297                 :            :     else
     298                 :          6 :       out.setX( srcX.at( i ) );
     299                 :            : 
     300                 :         95 :     if ( vSpacing > 0 )
     301                 :         89 :       out.setY( std::round( srcY.at( i ) / vSpacing ) * vSpacing );
     302                 :            :     else
     303                 :          6 :       out.setY( srcY.at( i ) );
     304                 :            : 
     305                 :         95 :     if ( hasZ )
     306                 :            :     {
     307                 :         18 :       if ( dSpacing > 0 )
     308                 :         12 :         out.setZ( std::round( srcZ.at( i ) / dSpacing ) * dSpacing );
     309                 :            :       else
     310                 :          6 :         out.setZ( srcZ.at( i ) );
     311                 :         18 :     }
     312                 :            : 
     313                 :         95 :     if ( hasM )
     314                 :            :     {
     315                 :         18 :       if ( mSpacing > 0 )
     316                 :         12 :         out.setM( std::round( srcM.at( i ) / mSpacing ) * mSpacing );
     317                 :            :       else
     318                 :          6 :         out.setM( srcM.at( i ) );
     319                 :         18 :     }
     320                 :         95 :   };
     321                 :            : 
     322                 :            : 
     323                 :        116 :   auto append = [hasZ, hasM, &outX, &outY, &outM, &outZ]( QgsPoint const & point )
     324                 :            :   {
     325                 :         88 :     outX.append( point.x() );
     326                 :            : 
     327                 :         88 :     outY.append( point.y() );
     328                 :            : 
     329                 :         88 :     if ( hasZ )
     330                 :         18 :       outZ.append( point.z() );
     331                 :            : 
     332                 :         88 :     if ( hasM )
     333                 :         18 :       outM.append( point.m() );
     334                 :         88 :   };
     335                 :            : 
     336                 :         95 :   auto isPointEqual = [dSpacing, mSpacing, hasZ, hasM]( const QgsPoint & a, const QgsPoint & b )
     337                 :            :   {
     338                 :        101 :     return ( a.x() == b.x() )
     339                 :         67 :            && ( a.y() == b.y() )
     340                 :         34 :            && ( !hasZ || dSpacing <= 0 || a.z() == b.z() )
     341                 :          7 :            && ( !hasM || mSpacing <= 0 || a.m() == b.m() );
     342                 :            :   };
     343                 :            : 
     344                 :            :   // temporary values
     345                 :         28 :   QgsWkbTypes::Type pointType = QgsWkbTypes::zmType( QgsWkbTypes::Point, hasZ, hasM );
     346                 :         28 :   QgsPoint last( pointType );
     347                 :         28 :   QgsPoint current( pointType );
     348                 :            : 
     349                 :            :   // Actual code (what does all the work)
     350                 :         28 :   roundVertex( last, 0 );
     351                 :         28 :   append( last );
     352                 :            : 
     353                 :         95 :   for ( int i = 1; i < length; ++i )
     354                 :            :   {
     355                 :         67 :     roundVertex( current, i );
     356                 :         67 :     if ( !isPointEqual( current, last ) )
     357                 :            :     {
     358                 :         60 :       append( current );
     359                 :         60 :       last = current;
     360                 :         60 :     }
     361                 :         67 :   }
     362                 :            : 
     363                 :            :   // if it's not closed, with 2 points you get a correct line
     364                 :            :   // if it is, you need at least 4 (3 + the vertex that closes)
     365                 :         28 :   if ( outX.length() < 2 || ( isClosed() && outX.length() < 4 ) )
     366                 :          3 :     return false;
     367                 :            : 
     368                 :         25 :   return true;
     369                 :         28 : }

Generated by: LCOV version 1.14