Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsalgorithmexplode.cpp 3 : : --------------------- 4 : : begin : April 2018 5 : : copyright : (C) 2018 by Nyall Dawson 6 : : email : nyall dot dawson at gmail dot com 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 "qgsalgorithmexplode.h" 19 : : #include "qgscurve.h" 20 : : #include "qgslinestring.h" 21 : : #include "qgscircularstring.h" 22 : : #include "qgscompoundcurve.h" 23 : : #include "qgsgeometrycollection.h" 24 : : 25 : : ///@cond PRIVATE 26 : : 27 : 0 : QString QgsExplodeAlgorithm::name() const 28 : : { 29 : 0 : return QStringLiteral( "explodelines" ); 30 : : } 31 : : 32 : 0 : QString QgsExplodeAlgorithm::displayName() const 33 : : { 34 : 0 : return QObject::tr( "Explode lines" ); 35 : : } 36 : : 37 : 0 : QStringList QgsExplodeAlgorithm::tags() const 38 : : { 39 : 0 : return QObject::tr( "segments,parts" ).split( ',' ); 40 : 0 : } 41 : : 42 : 0 : QString QgsExplodeAlgorithm::group() const 43 : : { 44 : 0 : return QObject::tr( "Vector geometry" ); 45 : : } 46 : : 47 : 0 : QString QgsExplodeAlgorithm::groupId() const 48 : : { 49 : 0 : return QStringLiteral( "vectorgeometry" ); 50 : : } 51 : : 52 : 0 : QString QgsExplodeAlgorithm::shortHelpString() const 53 : : { 54 : 0 : return QObject::tr( "This algorithm takes a lines layer and creates a new one in which each line is replaced by a set of " 55 : : "lines representing the segments in the original line. Each line in the resulting layer contains only a " 56 : : "start and an end point, with no intermediate nodes between them.\n\n" 57 : : "If the input layer consists of CircularStrings or CompoundCurves, the output layer will be of the " 58 : : "same type and contain only single curve segments." ); 59 : : } 60 : : 61 : 0 : QList<int> QgsExplodeAlgorithm::inputLayerTypes() const 62 : : { 63 : 0 : return QList<int>() << QgsProcessing::TypeVectorLine; 64 : 0 : } 65 : : 66 : 0 : QgsProcessing::SourceType QgsExplodeAlgorithm::outputLayerType() const 67 : : { 68 : 0 : return QgsProcessing::TypeVectorLine; 69 : : } 70 : : 71 : 0 : QgsExplodeAlgorithm *QgsExplodeAlgorithm::createInstance() const 72 : : { 73 : 0 : return new QgsExplodeAlgorithm(); 74 : : } 75 : : 76 : 0 : QString QgsExplodeAlgorithm::outputName() const 77 : : { 78 : 0 : return QObject::tr( "Exploded" ); 79 : : } 80 : : 81 : 0 : QgsWkbTypes::Type QgsExplodeAlgorithm::outputWkbType( QgsWkbTypes::Type inputWkbType ) const 82 : : { 83 : 0 : return QgsWkbTypes::singleType( inputWkbType ); 84 : : } 85 : : 86 : 0 : QgsFeatureList QgsExplodeAlgorithm::processFeature( const QgsFeature &f, QgsProcessingContext &, QgsProcessingFeedback * ) 87 : : { 88 : 0 : if ( !f.hasGeometry() ) 89 : : { 90 : 0 : return QgsFeatureList() << f; 91 : : } 92 : : else 93 : : { 94 : 0 : const std::vector<QgsGeometry> parts = extractAsParts( f.geometry() ); 95 : 0 : QgsFeature outputFeature; 96 : 0 : QgsFeatureList features; 97 : 0 : features.reserve( parts.size() ); 98 : 0 : for ( const QgsGeometry &part : parts ) 99 : : { 100 : 0 : outputFeature.setAttributes( f.attributes() ); 101 : 0 : outputFeature.setGeometry( part ); 102 : 0 : features << outputFeature; 103 : : } 104 : 0 : return features; 105 : 0 : } 106 : 0 : } 107 : : 108 : 0 : QgsFeatureSink::SinkFlags QgsExplodeAlgorithm::sinkFlags() const 109 : : { 110 : 0 : return QgsFeatureSink::RegeneratePrimaryKey; 111 : : } 112 : : 113 : 0 : std::vector<QgsGeometry> QgsExplodeAlgorithm::extractAsParts( const QgsGeometry &geometry ) const 114 : : { 115 : 0 : if ( geometry.isMultipart() ) 116 : : { 117 : 0 : std::vector<QgsGeometry> parts; 118 : 0 : const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geometry.constGet() ); 119 : 0 : for ( int part = 0; part < collection->numGeometries(); ++part ) 120 : : { 121 : 0 : std::vector<QgsGeometry> segments = curveAsSingleSegments( qgsgeometry_cast< const QgsCurve * >( collection->geometryN( part ) ) ); 122 : 0 : parts.reserve( parts.size() + segments.size() ); 123 : 0 : std::move( std::begin( segments ), std::end( segments ), std::back_inserter( parts ) ); 124 : 0 : } 125 : 0 : return parts; 126 : 0 : } 127 : : else 128 : : { 129 : 0 : return curveAsSingleSegments( qgsgeometry_cast< const QgsCurve * >( geometry.constGet() ) ); 130 : : } 131 : 0 : } 132 : : 133 : 0 : std::vector<QgsGeometry> QgsExplodeAlgorithm::curveAsSingleSegments( const QgsCurve *curve, bool useCompoundCurves ) const 134 : : { 135 : 0 : std::vector<QgsGeometry> parts; 136 : 0 : if ( !curve ) 137 : 0 : return parts; 138 : 0 : switch ( QgsWkbTypes::flatType( curve->wkbType() ) ) 139 : : { 140 : : case QgsWkbTypes::LineString: 141 : : { 142 : 0 : const QgsLineString *line = qgsgeometry_cast< const QgsLineString * >( curve ); 143 : 0 : for ( int i = 0; i < line->numPoints() - 1; ++i ) 144 : : { 145 : 0 : QgsPoint ptA = line->pointN( i ); 146 : 0 : QgsPoint ptB = line->pointN( i + 1 ); 147 : 0 : std::unique_ptr< QgsLineString > ls = std::make_unique< QgsLineString >( QVector< QgsPoint >() << ptA << ptB ); 148 : 0 : if ( !useCompoundCurves ) 149 : : { 150 : 0 : parts.emplace_back( QgsGeometry( std::move( ls ) ) ); 151 : 0 : } 152 : : else 153 : : { 154 : 0 : std::unique_ptr< QgsCompoundCurve > cc = std::make_unique< QgsCompoundCurve >(); 155 : 0 : cc->addCurve( ls.release() ); 156 : 0 : parts.emplace_back( QgsGeometry( std::move( cc ) ) ); 157 : 0 : } 158 : 0 : } 159 : 0 : break; 160 : : } 161 : : 162 : : case QgsWkbTypes::CircularString: 163 : : { 164 : 0 : const QgsCircularString *string = qgsgeometry_cast< const QgsCircularString * >( curve ); 165 : 0 : for ( int i = 0; i < string->numPoints() - 2; i += 2 ) 166 : : { 167 : 0 : QgsPoint ptA = string->pointN( i ); 168 : 0 : QgsPoint ptB = string->pointN( i + 1 ); 169 : 0 : QgsPoint ptC = string->pointN( i + 2 ); 170 : 0 : std::unique_ptr< QgsCircularString > cs = std::make_unique< QgsCircularString >(); 171 : 0 : cs->setPoints( QgsPointSequence() << ptA << ptB << ptC ); 172 : 0 : if ( !useCompoundCurves ) 173 : : { 174 : 0 : parts.emplace_back( QgsGeometry( std::move( cs ) ) ); 175 : 0 : } 176 : : else 177 : : { 178 : 0 : std::unique_ptr< QgsCompoundCurve > cc = std::make_unique< QgsCompoundCurve >(); 179 : 0 : cc->addCurve( cs.release() ); 180 : 0 : parts.emplace_back( QgsGeometry( std::move( cc ) ) ); 181 : 0 : } 182 : 0 : } 183 : 0 : break; 184 : : } 185 : : 186 : : case QgsWkbTypes::CompoundCurve: 187 : : { 188 : 0 : const QgsCompoundCurve *compoundCurve = qgsgeometry_cast< QgsCompoundCurve * >( curve ); 189 : 0 : for ( int i = 0; i < compoundCurve->nCurves(); ++i ) 190 : : { 191 : 0 : std::vector<QgsGeometry> segments = curveAsSingleSegments( compoundCurve->curveAt( i ), true ); 192 : 0 : parts.reserve( parts.size() + segments.size() ); 193 : 0 : std::move( std::begin( segments ), std::end( segments ), std::back_inserter( parts ) ); 194 : 0 : } 195 : 0 : break; 196 : : } 197 : : 198 : : default: 199 : 0 : break; 200 : : 201 : : } 202 : 0 : return parts; 203 : 0 : } 204 : : 205 : : ///@endcond 206 : : 207 : : 208 : :