QgsGeometry QgsTransectSample::closestMultilineElement( const QgsPoint& pt, const QgsGeometry& multiLine ) { if ( !multiLine || ( multiLine.wkbType() != QgsWkbTypes::MultiLineString && multiLine.wkbType() != QgsWkbTypes::MultiLineString25D ) ) { return QgsGeometry(); } double minDist = DBL_MAX; double currentDist = 0; QgsGeometry currentLine; QgsGeometry closestLine; QgsGeometry pointGeom = QgsGeometry::fromPoint( pt ); QgsMultiPolyline multiPolyline = multiLine.asMultiPolyline(); QgsMultiPolyline::const_iterator it = multiPolyline.constBegin(); for ( ; it != multiPolyline.constEnd(); ++it ) { currentLine = QgsGeometry::fromPolyline( *it ); currentDist = pointGeom.distance( currentLine ); if ( currentDist < minDist ) { minDist = currentDist; closestLine = currentLine; } } return closestLine; }
void TestQgsOgcUtils::testGeometryFromGML() { // Test GML2 QgsGeometry* geom = QgsOgcUtils::geometryFromGML( "<Point><coordinates>123,456</coordinates></Point>" ); QVERIFY( geom ); QVERIFY( geom->wkbType() == QGis::WKBPoint ); QVERIFY( geom->asPoint() == QgsPoint( 123, 456 ) ); QgsGeometry* geomBox = QgsOgcUtils::geometryFromGML( "<gml:Box srsName=\"foo\"><gml:coordinates>135.2239,34.4879 135.8578,34.8471</gml:coordinates></gml:Box>" ); QVERIFY( geomBox ); QVERIFY( geomBox->wkbType() == QGis::WKBPolygon ); // Test GML3 geom = QgsOgcUtils::geometryFromGML( "<Point><pos>123 456</pos></Point>" ); QVERIFY( geom ); QVERIFY( geom->wkbType() == QGis::WKBPoint ); QVERIFY( geom->asPoint() == QgsPoint( 123, 456 ) ); geomBox = QgsOgcUtils::geometryFromGML( "<gml:Envelope srsName=\"foo\"><gml:lowerCorner>135.2239 34.4879</gml:lowerCorner><gml:upperCorner>135.8578 34.8471</gml:upperCorner></gml:Envelope>" ); QVERIFY( geomBox ); QVERIFY( geomBox->wkbType() == QGis::WKBPolygon ); delete geom; delete geomBox; }
bool QgsOverlayUtils::sanitizeIntersectionResult( QgsGeometry &geom, QgsWkbTypes::GeometryType geometryType ) { if ( geom.isNull() ) { // TODO: not sure if this ever happens - if it does, that means GEOS failed badly - would be good to have a test for such situation throw QgsProcessingException( QStringLiteral( "%1\n\n%2" ).arg( QObject::tr( "GEOS geoprocessing error: intersection failed." ), geom.lastError() ) ); } // Intersection of geometries may give use also geometries we do not want in our results. // For example, two square polygons touching at the corner have a point as the intersection, but no area. // In other cases we may get a mixture of geometries in the output - we want to keep only the expected types. if ( QgsWkbTypes::flatType( geom.wkbType() ) == QgsWkbTypes::GeometryCollection ) { // try to filter out irrelevant parts with different geometry type than what we want geom.convertGeometryCollectionToSubclass( geometryType ); if ( geom.isEmpty() ) return false; } if ( QgsWkbTypes::geometryType( geom.wkbType() ) != geometryType ) { // we can't make use of this resulting geometry return false; } // some data providers are picky about the geometries we pass to them: we can't add single-part geometries // when we promised multi-part geometries, so ensure we have the right type geom.convertToMultiType(); return true; }
QgsGeometry QgsMapToolDeleteRing::ringUnderPoint( const QgsPoint &p, QgsFeatureId &fid, int &partNum, int &ringNum ) { //There is no clean way to find if we are inside the ring of a feature, //so we iterate over all the features visible in the canvas //If several rings are found at this position, the smallest one is chosen, //in order to be able to delete a ring inside another ring QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( toLayerCoordinates( vlayer, mCanvas->extent() ) ) ); QgsFeature f; QgsGeometry g; QgsGeometry ringGeom; QgsMultiPolygon pol; QgsPolygon tempPol; QgsGeometry tempGeom; double area = std::numeric_limits<double>::max(); while ( fit.nextFeature( f ) ) { g = f.geometry(); if ( g.isNull() ) continue; if ( g.wkbType() == QgsWkbTypes::Polygon || g.wkbType() == QgsWkbTypes::Polygon25D ) { pol = QgsMultiPolygon() << g.asPolygon(); } else { pol = g.asMultiPolygon(); } for ( int i = 0; i < pol.size() ; ++i ) { //for each part if ( pol[i].size() > 1 ) { for ( int j = 1; j < pol[i].size(); ++j ) { tempPol = QgsPolygon() << pol[i][j]; tempGeom = QgsGeometry::fromPolygon( tempPol ); if ( tempGeom.area() < area && tempGeom.contains( &p ) ) { fid = f.id(); partNum = i; ringNum = j; area = tempGeom.area(); ringGeom = tempGeom; } } } } } return ringGeom; }
int QgsInterpolator::addVerticesToCache( const QgsGeometry& geom, bool zCoord, double attributeValue ) { if ( geom.isEmpty() ) return 1; bool hasZValue = false; QByteArray wkb( geom.exportToWkb() ); QgsConstWkbPtr currentWkbPtr( wkb ); currentWkbPtr.readHeader(); vertexData theVertex; //the current vertex QgsWkbTypes::Type wkbType = geom.wkbType(); switch ( wkbType ) { case QgsWkbTypes::Point25D: hasZValue = true; //intentional fall-through FALLTHROUGH; case QgsWkbTypes::Point: { currentWkbPtr >> theVertex.x >> theVertex.y; if ( zCoord && hasZValue ) { currentWkbPtr >> theVertex.z; } else { theVertex.z = attributeValue; } mCachedBaseData.push_back( theVertex ); break; }
void QgsMapToolDeleteRing::deleteRing( QgsFeatureId fId, int beforeVertexNr, QgsVectorLayer* vlayer ) { QgsFeature f; vlayer->getFeatures( QgsFeatureRequest().setFilterFid( fId ) ).nextFeature( f ); QgsGeometry* g = f.geometry(); QGis::WkbType wkbtype = g->wkbType(); int ringNum, partNum = 0; if ( wkbtype == QGis::WKBPolygon || wkbtype == QGis::WKBPolygon25D ) { ringNum = ringNumInPolygon( g, beforeVertexNr ); } else if ( wkbtype == QGis::WKBMultiPolygon || wkbtype == QGis::WKBMultiPolygon25D ) { ringNum = ringNumInMultiPolygon( g, beforeVertexNr, partNum ); } else return; if ( g->deleteRing( ringNum, partNum ) ) { vlayer->beginEditCommand( tr( "Ring deleted" ) ); vlayer->changeGeometry( fId, g ); vlayer->endEditCommand(); mCanvas->refresh(); } }
QgsGeometry QgsGeometryAnalyzer::locateBetweenMeasures( double fromMeasure, double toMeasure, const QgsGeometry& lineGeom ) { if ( lineGeom.isEmpty() ) { return QgsGeometry(); } QgsMultiPolyline resultGeom; //need to go with WKB and z coordinate until QgsGeometry supports M values QByteArray wkb( lineGeom.exportToWkb() ); QgsConstWkbPtr wkbPtr( wkb ); wkbPtr.readHeader(); QgsWkbTypes::Type wkbType = lineGeom.wkbType(); if ( wkbType != QgsWkbTypes::LineString25D && wkbType != QgsWkbTypes::MultiLineString25D ) { return QgsGeometry(); } if ( wkbType == QgsWkbTypes::LineString25D ) { locateBetweenWkbString( wkbPtr, resultGeom, fromMeasure, toMeasure ); } else if ( wkbType == QgsWkbTypes::MultiLineString25D ) { int nLines; wkbPtr >> nLines; for ( int i = 0; i < nLines; ++i ) { wkbPtr.readHeader(); wkbPtr = locateBetweenWkbString( wkbPtr, resultGeom, fromMeasure, toMeasure ); } }
void QgsMapToolDeleteRing::deleteRing( QgsFeatureId fId, int beforeVertexNr, QgsVectorLayer *vlayer ) { QgsFeature f; vlayer->getFeatures( QgsFeatureRequest().setFilterFid( fId ) ).nextFeature( f ); const QgsGeometry g = f.geometry(); QgsWkbTypes::Type wkbtype = g.wkbType(); int ringNum, partNum = 0; if ( wkbtype == QgsWkbTypes::Polygon || wkbtype == QgsWkbTypes::Polygon25D ) { ringNum = ringNumInPolygon( g, beforeVertexNr ); } else if ( wkbtype == QgsWkbTypes::MultiPolygon || wkbtype == QgsWkbTypes::MultiPolygon25D ) { ringNum = ringNumInMultiPolygon( g, beforeVertexNr, partNum ); } else return; QgsGeometry editableGeom = f.geometry(); if ( editableGeom.deleteRing( ringNum, partNum ) ) { vlayer->beginEditCommand( tr( "Ring deleted" ) ); vlayer->changeGeometry( fId, editableGeom ); vlayer->endEditCommand(); vlayer->triggerRepaint(); } }
static QgsPointLocator::Match _findClosestSegmentIntersection( const QgsPoint& pt, const QgsPointLocator::MatchList& segments ) { if ( segments.isEmpty() ) return QgsPointLocator::Match(); QSet<QgsPoint> endpoints; // make a geometry QList<QgsGeometry*> geoms; Q_FOREACH ( const QgsPointLocator::Match& m, segments ) { if ( m.hasEdge() ) { QgsPolyline pl( 2 ); m.edgePoints( pl[0], pl[1] ); geoms << QgsGeometry::fromPolyline( pl ); endpoints << pl[0] << pl[1]; } } QgsGeometry* g = QgsGeometry::unaryUnion( geoms ); qDeleteAll( geoms ); // get intersection points QList<QgsPoint> newPoints; if ( g->wkbType() == QGis::WKBLineString ) { Q_FOREACH ( const QgsPoint& p, g->asPolyline() ) { if ( !endpoints.contains( p ) ) newPoints << p; } }
static QgsPointLocator::Match _findClosestSegmentIntersection( const QgsPointXY &pt, const QgsPointLocator::MatchList &segments ) { if ( segments.isEmpty() ) return QgsPointLocator::Match(); QSet<QgsPointXY> endpoints; // make a geometry QVector<QgsGeometry> geoms; Q_FOREACH ( const QgsPointLocator::Match &m, segments ) { if ( m.hasEdge() ) { QgsPolylineXY pl( 2 ); m.edgePoints( pl[0], pl[1] ); geoms << QgsGeometry::fromPolylineXY( pl ); endpoints << pl[0] << pl[1]; } } QgsGeometry g = QgsGeometry::unaryUnion( geoms ); // get intersection points QList<QgsPointXY> newPoints; if ( g.wkbType() == QgsWkbTypes::LineString ) { Q_FOREACH ( const QgsPointXY &p, g.asPolyline() ) { if ( !endpoints.contains( p ) ) newPoints << p; } }
bool QgsPointDisplacementRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker ) { Q_UNUSED( drawVertexMarker ); Q_UNUSED( context ); Q_UNUSED( layer ); //check, if there is already a point at that position if ( !feature.hasGeometry() ) return false; QgsSymbolV2* symbol = firstSymbolForFeature( mRenderer, feature, context ); //if the feature has no symbol (eg, no matching rule in a rule-based renderer), skip it if ( !symbol ) return false; //point position in screen coords QgsGeometry geom = feature.geometry(); QgsWkbTypes::Type geomType = geom.wkbType(); if ( QgsWkbTypes::flatType( geomType ) != QgsWkbTypes::Point ) { //can only render point type return false; } if ( selected ) mSelectedFeatures.insert( feature.id() ); double searchDistance = mTolerance * QgsSymbolLayerV2Utils::mapUnitScaleFactor( context, mToleranceUnit, mToleranceMapUnitScale ); QList<QgsFeatureId> intersectList = mSpatialIndex->intersects( searchRect( feature.geometry().asPoint(), searchDistance ) ); if ( intersectList.empty() ) { mSpatialIndex->insertFeature( feature ); // create new group DisplacementGroup newGroup; newGroup.insert( feature.id(), qMakePair( feature, symbol ) ); mDisplacementGroups.push_back( newGroup ); // add to group index mGroupIndex.insert( feature.id(), mDisplacementGroups.count() - 1 ); return true; } //go through all the displacement group maps and search an entry where the id equals the result of the spatial search QgsFeatureId existingEntry = intersectList.at( 0 ); int groupIdx = mGroupIndex[ existingEntry ]; DisplacementGroup& group = mDisplacementGroups[groupIdx]; // add to a group group.insert( feature.id(), qMakePair( feature, symbol ) ); // add to group index mGroupIndex.insert( feature.id(), groupIdx ); return true; }
//! Returns a simplified version the specified geometry (Removing duplicated points) when is applied the specified map2pixel context QgsGeometry QgsMapToPixelSimplifier::simplify( const QgsGeometry& geometry ) const { if ( geometry.isEmpty() ) { return QgsGeometry(); } if ( mSimplifyFlags == QgsMapToPixelSimplifier::NoFlags ) { return geometry; } // Check whether the geometry can be simplified using the map2pixel context const QgsWkbTypes::Type singleType = QgsWkbTypes::singleType( geometry.wkbType() ); const QgsWkbTypes::Type flatType = QgsWkbTypes::flatType( singleType ); if ( flatType == QgsWkbTypes::Point ) { return geometry; } const bool isaLinearRing = flatType == QgsWkbTypes::Polygon; const int numPoints = geometry.geometry()->nCoordinates(); if ( numPoints <= ( isaLinearRing ? 6 : 3 ) ) { // No simplify simple geometries return geometry; } const QgsRectangle envelope = geometry.boundingBox(); if ( qMax( envelope.width(), envelope.height() ) / numPoints > mTolerance * 2.0 ) { //points are in average too far apart to lead to any significant simplification return geometry; } return simplifyGeometry( mSimplifyFlags, mSimplifyAlgorithm, geometry.wkbType(), *geometry.geometry(), envelope, mTolerance, false ); }
QgsFeature QgsFixGeometriesAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback ) { if ( !feature.hasGeometry() ) return feature; QgsFeature outputFeature = feature; QgsGeometry outputGeometry = outputFeature.geometry().makeValid(); if ( !outputGeometry ) { feedback->pushInfo( QObject::tr( "makeValid failed for feature %1 " ).arg( feature.id() ) ); outputFeature.clearGeometry(); return outputFeature; } if ( outputGeometry.wkbType() == QgsWkbTypes::Unknown || QgsWkbTypes::flatType( outputGeometry.wkbType() ) == QgsWkbTypes::GeometryCollection ) { // keep only the parts of the geometry collection with correct type const QVector< QgsGeometry > tmpGeometries = outputGeometry.asGeometryCollection(); QVector< QgsGeometry > matchingParts; for ( const QgsGeometry &g : tmpGeometries ) { if ( g.type() == feature.geometry().type() ) matchingParts << g; } if ( !matchingParts.empty() ) outputGeometry = QgsGeometry::collectGeometry( matchingParts ); else outputGeometry = QgsGeometry(); } outputGeometry.convertToMultiType(); outputFeature.setGeometry( outputGeometry ); return outputFeature; }
bool QgsPointDisplacementRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker ) { Q_UNUSED( drawVertexMarker ); Q_UNUSED( context ); Q_UNUSED( layer ); //check, if there is already a point at that position if ( !feature.geometry() ) return false; //point position in screen coords QgsGeometry* geom = feature.geometry(); QGis::WkbType geomType = geom->wkbType(); if ( geomType != QGis::WKBPoint && geomType != QGis::WKBPoint25D ) { //can only render point type return false; } if ( selected ) mSelectedFeatures.insert( feature.id() ); QList<QgsFeatureId> intersectList = mSpatialIndex->intersects( searchRect( feature.geometry()->asPoint() ) ); if ( intersectList.empty() ) { mSpatialIndex->insertFeature( feature ); // create new group DisplacementGroup newGroup; newGroup.insert( feature.id(), feature ); mDisplacementGroups.push_back( newGroup ); // add to group index mGroupIndex.insert( feature.id(), mDisplacementGroups.count() - 1 ); return true; } //go through all the displacement group maps and search an entry where the id equals the result of the spatial search QgsFeatureId existingEntry = intersectList.at( 0 ); int groupIdx = mGroupIndex[ existingEntry ]; DisplacementGroup& group = mDisplacementGroups[groupIdx]; // add to a group group.insert( feature.id(), feature ); // add to group index mGroupIndex.insert( feature.id(), groupIdx ); return true; }
void QgsLabel::labelPoint( std::vector<labelpoint>& points, QgsFeature & feature ) { QgsGeometry *geometry = feature.geometry(); const unsigned char *geom = geometry->asWkb(); size_t geomlen = geometry->wkbSize(); QGis::WkbType wkbType = geometry->wkbType(); labelpoint point; switch ( wkbType ) { case QGis::WKBPoint25D: case QGis::WKBPoint: case QGis::WKBLineString25D: case QGis::WKBLineString: case QGis::WKBPolygon25D: case QGis::WKBPolygon: { labelPoint( point, geom, geomlen ); points.push_back( point ); } break; case QGis::WKBMultiPoint25D: case QGis::WKBMultiPoint: case QGis::WKBMultiLineString25D: case QGis::WKBMultiLineString: case QGis::WKBMultiPolygon25D: case QGis::WKBMultiPolygon: // Return a position for each individual in the multi-feature { Q_ASSERT( 1 + sizeof( wkbType ) + sizeof( int ) <= geomlen ); geom += 1 + sizeof( wkbType ); int nFeatures = *( unsigned int * )geom; geom += sizeof( int ); const unsigned char *feature = geom; for ( int i = 0; i < nFeatures && feature; ++i ) { feature = labelPoint( point, feature, geom + geomlen - feature ); points.push_back( point ); } } break; default: QgsDebugMsg( "Unknown geometry type of " + QString::number( wkbType ) ); } }
QList<double> QgsGeometryAnalyzer::simpleMeasure( QgsGeometry& mpGeometry ) { QList<double> list; double perim; if ( mpGeometry.wkbType() == QgsWkbTypes::Point ) { QgsPoint pt = mpGeometry.asPoint(); list.append( pt.x() ); list.append( pt.y() ); } else { QgsDistanceArea measure; list.append( measure.measureArea( mpGeometry ) ); if ( mpGeometry.type() == QgsWkbTypes::PolygonGeometry ) { perim = perimeterMeasure( mpGeometry, measure ); list.append( perim ); } } return list; }
QVariantMap QgsClipAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { std::unique_ptr< QgsFeatureSource > featureSource( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); if ( !featureSource ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) ); std::unique_ptr< QgsFeatureSource > maskSource( parameterAsSource( parameters, QStringLiteral( "OVERLAY" ), context ) ); if ( !maskSource ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "OVERLAY" ) ) ); QString dest; QgsWkbTypes::GeometryType sinkType = QgsWkbTypes::geometryType( featureSource->wkbType() ); std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, featureSource->fields(), QgsWkbTypes::multiType( featureSource->wkbType() ), featureSource->sourceCrs() ) ); if ( !sink ) throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); // first build up a list of clip geometries QVector< QgsGeometry > clipGeoms; QgsFeatureIterator it = maskSource->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QList< int >() ).setDestinationCrs( featureSource->sourceCrs(), context.transformContext() ) ); QgsFeature f; while ( it.nextFeature( f ) ) { if ( f.hasGeometry() ) clipGeoms << f.geometry(); } QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), dest ); if ( clipGeoms.isEmpty() ) return outputs; // are we clipping against a single feature? if so, we can show finer progress reports bool singleClipFeature = false; QgsGeometry combinedClipGeom; if ( clipGeoms.length() > 1 ) { combinedClipGeom = QgsGeometry::unaryUnion( clipGeoms ); if ( combinedClipGeom.isEmpty() ) { throw QgsProcessingException( QObject::tr( "Could not create the combined clip geometry: %1" ).arg( combinedClipGeom.lastError() ) ); } singleClipFeature = false; } else { combinedClipGeom = clipGeoms.at( 0 ); singleClipFeature = true; } // use prepared geometries for faster intersection tests std::unique_ptr< QgsGeometryEngine > engine( QgsGeometry::createGeometryEngine( combinedClipGeom.constGet() ) ); engine->prepareGeometry(); QgsFeatureIds testedFeatureIds; int i = -1; Q_FOREACH ( const QgsGeometry &clipGeom, clipGeoms ) { i++; if ( feedback->isCanceled() ) { break; } QgsFeatureIterator inputIt = featureSource->getFeatures( QgsFeatureRequest().setFilterRect( clipGeom.boundingBox() ) ); QgsFeatureList inputFeatures; QgsFeature f; while ( inputIt.nextFeature( f ) ) inputFeatures << f; if ( inputFeatures.isEmpty() ) continue; double step = 0; if ( singleClipFeature ) step = 100.0 / inputFeatures.length(); int current = 0; Q_FOREACH ( const QgsFeature &inputFeature, inputFeatures ) { if ( feedback->isCanceled() ) { break; } if ( !inputFeature.hasGeometry() ) continue; if ( testedFeatureIds.contains( inputFeature.id() ) ) { // don't retest a feature we have already checked continue; } testedFeatureIds.insert( inputFeature.id() ); if ( !engine->intersects( inputFeature.geometry().constGet() ) ) continue; QgsGeometry newGeometry; if ( !engine->contains( inputFeature.geometry().constGet() ) ) { QgsGeometry currentGeometry = inputFeature.geometry(); newGeometry = combinedClipGeom.intersection( currentGeometry ); if ( newGeometry.wkbType() == QgsWkbTypes::Unknown || QgsWkbTypes::flatType( newGeometry.wkbType() ) == QgsWkbTypes::GeometryCollection ) { QgsGeometry intCom = inputFeature.geometry().combine( newGeometry ); QgsGeometry intSym = inputFeature.geometry().symDifference( newGeometry ); newGeometry = intCom.difference( intSym ); } } else { // clip geometry totally contains feature geometry, so no need to perform intersection newGeometry = inputFeature.geometry(); } if ( !QgsOverlayUtils::sanitizeIntersectionResult( newGeometry, sinkType ) ) continue; QgsFeature outputFeature; outputFeature.setGeometry( newGeometry ); outputFeature.setAttributes( inputFeature.attributes() ); sink->addFeature( outputFeature, QgsFeatureSink::FastInsert ); if ( singleClipFeature ) feedback->setProgress( current * step ); } if ( !singleClipFeature ) { // coarse progress report for multiple clip geometries feedback->setProgress( 100.0 * static_cast< double >( i ) / clipGeoms.length() ); } }
QgsDelimitedTextProvider::QgsDelimitedTextProvider( QString uri ) : QgsVectorDataProvider( uri ) , mDelimiter( "," ) , mDelimiterType( "plain" ) , mFieldCount( 0 ) , mXFieldIndex( -1 ) , mYFieldIndex( -1 ) , mWktFieldIndex( -1 ) , mWktHasZM( false ) , mWktZMRegexp( "\\s+(?:z|m|zm)(?=\\s*\\()", Qt::CaseInsensitive ) , mWktCrdRegexp( "(\\-?\\d+(?:\\.\\d*)?\\s+\\-?\\d+(?:\\.\\d*)?)\\s[\\s\\d\\.\\-]+" ) , mFile( 0 ) , mStream( 0 ) , mSkipLines( 0 ) , mFirstDataLine( 0 ) , mShowInvalidLines( false ) , mCrs() , mWkbType( QGis::WKBUnknown ) { QUrl url = QUrl::fromEncoded( uri.toAscii() ); // Extract the provider definition from the url mFileName = url.toLocalFile(); QString wktField; QString xField; QString yField; if ( url.hasQueryItem( "delimiter" ) ) mDelimiter = url.queryItemValue( "delimiter" ); if ( url.hasQueryItem( "delimiterType" ) ) mDelimiterType = url.queryItemValue( "delimiterType" ); if ( url.hasQueryItem( "wktField" ) ) wktField = url.queryItemValue( "wktField" ); if ( url.hasQueryItem( "xField" ) ) xField = url.queryItemValue( "xField" ); if ( url.hasQueryItem( "yField" ) ) yField = url.queryItemValue( "yField" ); if ( url.hasQueryItem( "skipLines" ) ) mSkipLines = url.queryItemValue( "skipLines" ).toInt(); if ( url.hasQueryItem( "crs" ) ) mCrs.createFromString( url.queryItemValue( "crs" ) ); if ( url.hasQueryItem( "decimalPoint" ) ) mDecimalPoint = url.queryItemValue( "decimalPoint" ); QgsDebugMsg( "Data source uri is " + uri ); QgsDebugMsg( "Delimited text file is: " + mFileName ); QgsDebugMsg( "Delimiter is: " + mDelimiter ); QgsDebugMsg( "Delimiter type is: " + mDelimiterType ); QgsDebugMsg( "wktField is: " + wktField ); QgsDebugMsg( "xField is: " + xField ); QgsDebugMsg( "yField is: " + yField ); QgsDebugMsg( "skipLines is: " + QString::number( mSkipLines ) ); // if delimiter contains some special characters, convert them if ( mDelimiterType != "regexp" ) mDelimiter.replace( "\\t", "\t" ); // replace "\t" with a real tabulator // Set the selection rectangle to null mSelectionRectangle = QgsRectangle(); // assume the layer is invalid until proven otherwise mValid = false; if ( mFileName.isEmpty() || mDelimiter.isEmpty() ) { // uri is invalid so the layer must be too... QgsDebugMsg( "Data source is invalid" ); return; } // check to see that the file exists and perform some sanity checks if ( !QFile::exists( mFileName ) ) { QgsDebugMsg( "Data source " + dataSourceUri() + " doesn't exist" ); return; } // Open the file and get number of rows, etc. We assume that the // file has a header row and process accordingly. Caller should make // sure that the delimited file is properly formed. mFile = new QFile( mFileName ); if ( !mFile->open( QIODevice::ReadOnly ) ) { QgsDebugMsg( "Data source " + dataSourceUri() + " could not be opened" ); delete mFile; mFile = 0; return; } // now we have the file opened and ready for parsing // set the initial extent mExtent = QgsRectangle(); QMap<int, bool> couldBeInt; QMap<int, bool> couldBeDouble; mStream = new QTextStream( mFile ); QString line; mNumberFeatures = 0; int lineNumber = 0; bool hasFields = false; while ( !mStream->atEnd() ) { lineNumber++; line = readLine( mStream ); // line of text excluding '\n', default local 8 bit encoding. if ( lineNumber < mSkipLines + 1 ) continue; if ( line.isEmpty() ) continue; if ( !hasFields ) { // Get the fields from the header row and store them in the // fields vector QStringList fieldList = splitLine( line ); mFieldCount = fieldList.count(); // We don't know anything about a text based field other // than its name. All fields are assumed to be text int fieldPos = 0; for ( int column = 0; column < mFieldCount; column++ ) { QString field = fieldList[column]; if (( field.left( 1 ) == "'" || field.left( 1 ) == "\"" ) && field.left( 1 ) == field.right( 1 ) ) // eat quotes field = field.mid( 1, field.length() - 2 ); if ( field.length() == 0 ) // skip empty field names continue; // check to see if this field matches either the x or y field if ( !wktField.isEmpty() && wktField == field ) { QgsDebugMsg( "Found wkt field: " + ( field ) ); mWktFieldIndex = column; } else if ( !xField.isEmpty() && xField == field ) { QgsDebugMsg( "Found x field: " + ( field ) ); mXFieldIndex = column; } else if ( !yField.isEmpty() && yField == field ) { QgsDebugMsg( "Found y field: " + ( field ) ); mYFieldIndex = column; } // WKT geometry field won't be displayed in attribute tables if ( column == mWktFieldIndex ) continue; QgsDebugMsg( "Adding field: " + ( field ) ); // assume that the field could be integer or double // for now, let's set field type as text attributeColumns.append( column ); attributeFields[fieldPos] = QgsField( field, QVariant::String, "Text" ); couldBeInt.insert( fieldPos, true ); couldBeDouble.insert( fieldPos, true ); fieldPos++; } if ( mWktFieldIndex >= 0 ) { mXFieldIndex = -1; mYFieldIndex = -1; } QgsDebugMsg( "wktfield index: " + QString::number( mWktFieldIndex ) ); QgsDebugMsg( "xfield index: " + QString::number( mXFieldIndex ) ); QgsDebugMsg( "yfield index: " + QString::number( mYFieldIndex ) ); QgsDebugMsg( "Field count for the delimited text file is " + QString::number( attributeFields.size() ) ); hasFields = true; } else // hasFields == true - field names already read { if ( mFirstDataLine == 0 ) mFirstDataLine = lineNumber; // split the line on the delimiter QStringList parts = splitLine( line ); // Ensure that the input has at least the required number of fields (mainly to tolerate // missed blank strings at end of row) while ( parts.size() < mFieldCount ) parts.append( QString::null ); if ( mWktFieldIndex >= 0 ) { // Get the wkt - confirm it is valid, get the type, and // if compatible with the rest of file, add to the extents QString sWkt = parts[mWktFieldIndex]; QgsGeometry *geom = 0; try { if ( !mWktHasZM && sWkt.indexOf( mWktZMRegexp ) >= 0 ) mWktHasZM = true; if ( mWktHasZM ) { sWkt.remove( mWktZMRegexp ).replace( mWktCrdRegexp, "\\1" ); } geom = QgsGeometry::fromWkt( sWkt ); } catch ( ... ) { mInvalidLines << line; geom = 0; } if ( geom ) { QGis::WkbType type = geom->wkbType(); if ( type != QGis::WKBNoGeometry ) { if ( mNumberFeatures == 0 ) { mNumberFeatures++; mWkbType = type; mExtent = geom->boundingBox(); } else if ( type == mWkbType ) { mNumberFeatures++; QgsRectangle bbox( geom->boundingBox() ); mExtent.combineExtentWith( &bbox ); } } delete geom; } } else if ( mWktFieldIndex == -1 && mXFieldIndex >= 0 && mYFieldIndex >= 0 ) { // Get the x and y values, first checking to make sure they // aren't null. QString sX = parts[mXFieldIndex]; QString sY = parts[mYFieldIndex]; if ( !mDecimalPoint.isEmpty() ) { sX.replace( mDecimalPoint, "." ); sY.replace( mDecimalPoint, "." ); } bool xOk = false; bool yOk = false; double x = sX.toDouble( &xOk ); double y = sY.toDouble( &yOk ); if ( xOk && yOk ) { if ( mNumberFeatures > 0 ) { mExtent.combineExtentWith( x, y ); } else { // Extent for the first point is just the first point mExtent.set( x, y, x, y ); mWkbType = QGis::WKBPoint; } mNumberFeatures++; } else { mInvalidLines << line; } } else { mWkbType = QGis::WKBNoGeometry; mNumberFeatures++; } for ( int i = 0; i < attributeFields.size(); i++ ) { QString &value = parts[attributeColumns[i]]; if ( value.isEmpty() ) continue; // try to convert attribute values to integer and double if ( couldBeInt[i] ) { value.toInt( &couldBeInt[i] ); } if ( couldBeDouble[i] ) { value.toDouble( &couldBeDouble[i] ); } } } } QgsDebugMsg( "geometry type is: " + QString::number( mWkbType ) ); QgsDebugMsg( "feature count is: " + QString::number( mNumberFeatures ) ); // now it's time to decide the types for the fields for ( QgsFieldMap::iterator it = attributeFields.begin(); it != attributeFields.end(); ++it ) { if ( couldBeInt[it.key()] ) { it->setType( QVariant::Int ); it->setTypeName( "integer" ); } else if ( couldBeDouble[it.key()] ) { it->setType( QVariant::Double ); it->setTypeName( "double" ); } } mValid = mWkbType != QGis::WKBUnknown; }
bool QgsDelimitedTextProvider::nextFeature( QgsFeature& feature ) { // before we do anything else, assume that there's something wrong with // the feature feature.setValid( false ); while ( !mStream->atEnd() ) { QString line = readLine( mStream ); // Default local 8 bit encoding if ( line.isEmpty() ) continue; // lex the tokens from the current data line QStringList tokens = splitLine( line ); while ( tokens.size() < mFieldCount ) tokens.append( QString::null ); QgsGeometry *geom = 0; if ( mWktFieldIndex >= 0 ) { try { QString &sWkt = tokens[mWktFieldIndex]; // Remove Z and M coordinates if present, as currently fromWkt doesn't // support these. if ( mWktHasZM ) { sWkt.remove( mWktZMRegexp ).replace( mWktCrdRegexp, "\\1" ); } geom = QgsGeometry::fromWkt( sWkt ); } catch ( ... ) { geom = 0; } if ( geom && geom->wkbType() != mWkbType ) { delete geom; geom = 0; } mFid++; if ( geom && !boundsCheck( geom ) ) { delete geom; geom = 0; } } else if ( mXFieldIndex >= 0 && mYFieldIndex >= 0 ) { QString sX = tokens[mXFieldIndex]; QString sY = tokens[mYFieldIndex]; if ( !mDecimalPoint.isEmpty() ) { sX.replace( mDecimalPoint, "." ); sY.replace( mDecimalPoint, "." ); } bool xOk, yOk; double x = sX.toDouble( &xOk ); double y = sY.toDouble( &yOk ); if ( xOk && yOk ) { mFid++; if ( boundsCheck( x, y ) ) { geom = QgsGeometry::fromPoint( QgsPoint( x, y ) ); } } } if ( !geom && mWkbType != QGis::WKBNoGeometry ) { mInvalidLines << line; continue; } // At this point the current feature values are valid feature.setValid( true ); feature.setFeatureId( mFid ); if ( geom ) feature.setGeometry( geom ); for ( QgsAttributeList::const_iterator i = mAttributesToFetch.begin(); i != mAttributesToFetch.end(); ++i ) { int fieldIdx = *i; if ( fieldIdx < 0 || fieldIdx >= attributeColumns.count() ) continue; // ignore non-existant fields QString &value = tokens[attributeColumns[fieldIdx]]; QVariant val; switch ( attributeFields[fieldIdx].type() ) { case QVariant::Int: if ( !value.isEmpty() ) val = QVariant( value ); else val = QVariant( attributeFields[fieldIdx].type() ); break; case QVariant::Double: if ( !value.isEmpty() ) val = QVariant( value.toDouble() ); else val = QVariant( attributeFields[fieldIdx].type() ); break; default: val = QVariant( value ); break; } feature.addAttribute( fieldIdx, val ); } // We have a good line, so return return true; } // !mStream->atEnd() // End of the file. If there are any lines that couldn't be // loaded, display them now. if ( mShowInvalidLines && !mInvalidLines.isEmpty() ) { mShowInvalidLines = false; QgsMessageOutput* output = QgsMessageOutput::createMessageOutput(); output->setTitle( tr( "Error" ) ); output->setMessage( tr( "Note: the following lines were not loaded because QGIS was " "unable to determine values for the x and y coordinates:\n" ), QgsMessageOutput::MessageText ); output->appendMessage( "Start of invalid lines." ); for ( int i = 0; i < mInvalidLines.size(); ++i ) output->appendMessage( mInvalidLines.at( i ) ); output->appendMessage( "End of invalid lines." ); output->showMessage(); // We no longer need these lines. mInvalidLines.clear(); } return false; } // nextFeature
void QgsRubberBand::addGeometry( const QgsGeometry& geom, QgsVectorLayer* layer ) { if ( geom.isEmpty() ) { return; } //maprender object of canvas const QgsMapSettings& ms = mMapCanvas->mapSettings(); int idx = mPoints.size(); switch ( geom.wkbType() ) { case QgsWkbTypes::Point: case QgsWkbTypes::Point25D: { QgsPoint pt; if ( layer ) { pt = ms.layerToMapCoordinates( layer, geom.asPoint() ); } else { pt = geom.asPoint(); } addPoint( pt, false, idx ); removeLastPoint( idx, false ); } break; case QgsWkbTypes::MultiPoint: case QgsWkbTypes::MultiPoint25D: { QgsMultiPoint mpt = geom.asMultiPoint(); for ( int i = 0; i < mpt.size(); ++i, ++idx ) { QgsPoint pt = mpt[i]; if ( layer ) { addPoint( ms.layerToMapCoordinates( layer, pt ), false, idx ); removeLastPoint( idx, false ); } else { addPoint( pt, false, idx ); removeLastPoint( idx, false ); } } } break; case QgsWkbTypes::LineString: case QgsWkbTypes::LineString25D: { QgsPolyline line = geom.asPolyline(); for ( int i = 0; i < line.count(); i++ ) { if ( layer ) { addPoint( ms.layerToMapCoordinates( layer, line[i] ), false, idx ); } else { addPoint( line[i], false, idx ); } } } break; case QgsWkbTypes::MultiLineString: case QgsWkbTypes::MultiLineString25D: { QgsMultiPolyline mline = geom.asMultiPolyline(); for ( int i = 0; i < mline.size(); ++i, ++idx ) { QgsPolyline line = mline[i]; if ( line.isEmpty() ) { --idx; } for ( int j = 0; j < line.size(); ++j ) { if ( layer ) { addPoint( ms.layerToMapCoordinates( layer, line[j] ), false, idx ); } else { addPoint( line[j], false, idx ); } } } } break; case QgsWkbTypes::Polygon: case QgsWkbTypes::Polygon25D: { QgsPolygon poly = geom.asPolygon(); QgsPolyline line = poly[0]; for ( int i = 0; i < line.count(); i++ ) { if ( layer ) { addPoint( ms.layerToMapCoordinates( layer, line[i] ), false, idx ); } else { addPoint( line[i], false, idx ); } } } break; case QgsWkbTypes::MultiPolygon: case QgsWkbTypes::MultiPolygon25D: { QgsMultiPolygon multipoly = geom.asMultiPolygon(); for ( int i = 0; i < multipoly.size(); ++i, ++idx ) { QgsPolygon poly = multipoly[i]; QgsPolyline line = poly[0]; for ( int j = 0; j < line.count(); ++j ) { if ( layer ) { addPoint( ms.layerToMapCoordinates( layer, line[j] ), false, idx ); } else { addPoint( line[j], false, idx ); } } } } break; case QgsWkbTypes::Unknown: default: return; } setVisible( true ); updateRect(); update(); }
bool QgsTransectSample::closestSegmentPoints( const QgsGeometry& g1, const QgsGeometry& g2, double& dist, QgsPoint& pt1, QgsPoint& pt2 ) { QgsWkbTypes::Type t1 = g1.wkbType(); if ( t1 != QgsWkbTypes::LineString && t1 != QgsWkbTypes::LineString25D ) { return false; } QgsWkbTypes::Type t2 = g2.wkbType(); if ( t2 != QgsWkbTypes::LineString && t2 != QgsWkbTypes::LineString25D ) { return false; } QgsPolyline pl1 = g1.asPolyline(); QgsPolyline pl2 = g2.asPolyline(); if ( pl1.size() < 2 || pl2.size() < 2 ) { return false; } QgsPoint p11 = pl1.at( 0 ); QgsPoint p12 = pl1.at( 1 ); QgsPoint p21 = pl2.at( 0 ); QgsPoint p22 = pl2.at( 1 ); double p1x = p11.x(); double p1y = p11.y(); double v1x = p12.x() - p11.x(); double v1y = p12.y() - p11.y(); double p2x = p21.x(); double p2y = p21.y(); double v2x = p22.x() - p21.x(); double v2y = p22.y() - p21.y(); double denominatorU = v2x * v1y - v2y * v1x; double denominatorT = v1x * v2y - v1y * v2x; if ( qgsDoubleNear( denominatorU, 0 ) || qgsDoubleNear( denominatorT, 0 ) ) { //lines are parallel //project all points on the other segment and take the one with the smallest distance QgsPoint minDistPoint1; double d1 = p11.sqrDistToSegment( p21.x(), p21.y(), p22.x(), p22.y(), minDistPoint1 ); QgsPoint minDistPoint2; double d2 = p12.sqrDistToSegment( p21.x(), p21.y(), p22.x(), p22.y(), minDistPoint2 ); QgsPoint minDistPoint3; double d3 = p21.sqrDistToSegment( p11.x(), p11.y(), p12.x(), p12.y(), minDistPoint3 ); QgsPoint minDistPoint4; double d4 = p22.sqrDistToSegment( p11.x(), p11.y(), p12.x(), p12.y(), minDistPoint4 ); if ( d1 <= d2 && d1 <= d3 && d1 <= d4 ) { dist = sqrt( d1 ); pt1 = p11; pt2 = minDistPoint1; return true; } else if ( d2 <= d1 && d2 <= d3 && d2 <= d4 ) { dist = sqrt( d2 ); pt1 = p12; pt2 = minDistPoint2; return true; } else if ( d3 <= d1 && d3 <= d2 && d3 <= d4 ) { dist = sqrt( d3 ); pt1 = p21; pt2 = minDistPoint3; return true; } else { dist = sqrt( d4 ); pt1 = p21; pt2 = minDistPoint4; return true; } } double u = ( p1x * v1y - p1y * v1x - p2x * v1y + p2y * v1x ) / denominatorU; double t = ( p2x * v2y - p2y * v2x - p1x * v2y + p1y * v2x ) / denominatorT; if ( u >= 0 && u <= 1.0 && t >= 0 && t <= 1.0 ) { dist = 0; pt1.setX( p2x + u * v2x ); pt1.setY( p2y + u * v2y ); pt2 = pt1; dist = 0; return true; } if ( t > 1.0 ) { pt1.setX( p12.x() ); pt1.setY( p12.y() ); } else if ( t < 0.0 ) { pt1.setX( p11.x() ); pt1.setY( p11.y() ); } if ( u > 1.0 ) { pt2.setX( p22.x() ); pt2.setY( p22.y() ); } if ( u < 0.0 ) { pt2.setX( p21.x() ); pt2.setY( p21.y() ); } if ( t >= 0.0 && t <= 1.0 ) { //project pt2 onto g1 pt2.sqrDistToSegment( p11.x(), p11.y(), p12.x(), p12.y(), pt1 ); } if ( u >= 0.0 && u <= 1.0 ) { //project pt1 onto g2 pt1.sqrDistToSegment( p21.x(), p21.y(), p22.x(), p22.y(), pt2 ); } dist = sqrt( pt1.sqrDist( pt2 ) ); return true; }
int QgsTINInterpolator::insertData( QgsFeature* f, bool zCoord, int attr, InputType type ) { if ( !f ) { return 1; } QgsGeometry* g = f->geometry(); { if ( !g ) { return 2; } } //check attribute value double attributeValue = 0; bool attributeConversionOk = false; if ( !zCoord ) { QVariant attributeVariant = f->attribute( attr ); if ( !attributeVariant.isValid() ) //attribute not found, something must be wrong (e.g. NULL value) { return 3; } attributeValue = attributeVariant.toDouble( &attributeConversionOk ); if ( !attributeConversionOk || qIsNaN( attributeValue ) ) //don't consider vertices with attributes like 'nan' for the interpolation { return 4; } } //parse WKB. It is ugly, but we cannot use the methods with QgsPoint because they don't contain z-values for 25D types bool hasZValue = false; double x, y, z; unsigned char* currentWkbPtr = g->asWkb(); //maybe a structure or break line Line3D* line = 0; QGis::WkbType wkbType = g->wkbType(); switch ( wkbType ) { case QGis::WKBPoint25D: hasZValue = true; case QGis::WKBPoint: { currentWkbPtr += ( 1 + sizeof( int ) ); x = *(( double * )( currentWkbPtr ) ); currentWkbPtr += sizeof( double ); y = *(( double * )( currentWkbPtr ) ); if ( zCoord && hasZValue ) { currentWkbPtr += sizeof( double ); z = *(( double * )( currentWkbPtr ) ); } else { z = attributeValue; } Point3D* thePoint = new Point3D( x, y, z ); if ( mTriangulation->addPoint( thePoint ) == -100 ) { return -1; } break; } case QGis::WKBMultiPoint25D: hasZValue = true; case QGis::WKBMultiPoint: { currentWkbPtr += ( 1 + sizeof( int ) ); int* npoints = ( int* )currentWkbPtr; currentWkbPtr += sizeof( int ); for ( int index = 0; index < *npoints; ++index ) { currentWkbPtr += ( 1 + sizeof( int ) ); //skip endian and point type x = *(( double* )currentWkbPtr ); currentWkbPtr += sizeof( double ); y = *(( double* )currentWkbPtr ); currentWkbPtr += sizeof( double ); if ( hasZValue ) //skip z-coordinate for 25D geometries { z = *(( double* )currentWkbPtr ); currentWkbPtr += sizeof( double ); } else { z = attributeValue; } } break; } case QGis::WKBLineString25D: hasZValue = true; case QGis::WKBLineString: { if ( type != POINTS ) { line = new Line3D(); } currentWkbPtr += ( 1 + sizeof( int ) ); int* npoints = ( int* )currentWkbPtr; currentWkbPtr += sizeof( int ); for ( int index = 0; index < *npoints; ++index ) { x = *(( double * )( currentWkbPtr ) ); currentWkbPtr += sizeof( double ); y = *(( double * )( currentWkbPtr ) ); currentWkbPtr += sizeof( double ); if ( zCoord && hasZValue ) //skip z-coordinate for 25D geometries { z = *(( double * )( currentWkbPtr ) ); } else { z = attributeValue; } if ( hasZValue ) { currentWkbPtr += sizeof( double ); } if ( type == POINTS ) { //todo: handle error code -100 mTriangulation->addPoint( new Point3D( x, y, z ) ); } else { line->insertPoint( new Point3D( x, y, z ) ); } } if ( type != POINTS ) { mTriangulation->addLine( line, type == BREAK_LINES ); } break; } case QGis::WKBMultiLineString25D: hasZValue = true; case QGis::WKBMultiLineString: { currentWkbPtr += ( 1 + sizeof( int ) ); int* nlines = ( int* )currentWkbPtr; int* npoints = 0; currentWkbPtr += sizeof( int ); for ( int index = 0; index < *nlines; ++index ) { if ( type != POINTS ) { line = new Line3D(); } currentWkbPtr += ( sizeof( int ) + 1 ); npoints = ( int* )currentWkbPtr; currentWkbPtr += sizeof( int ); for ( int index2 = 0; index2 < *npoints; ++index2 ) { x = *(( double* )currentWkbPtr ); currentWkbPtr += sizeof( double ); y = *(( double* )currentWkbPtr ); currentWkbPtr += sizeof( double ); if ( hasZValue ) //skip z-coordinate for 25D geometries { z = *(( double* ) currentWkbPtr ); currentWkbPtr += sizeof( double ); } else { z = attributeValue; } if ( type == POINTS ) { //todo: handle error code -100 mTriangulation->addPoint( new Point3D( x, y, z ) ); } else { line->insertPoint( new Point3D( x, y, z ) ); } } if ( type != POINTS ) { mTriangulation->addLine( line, type == BREAK_LINES ); } } break; } case QGis::WKBPolygon25D: hasZValue = true; case QGis::WKBPolygon: { currentWkbPtr += ( 1 + sizeof( int ) ); int* nrings = ( int* )currentWkbPtr; currentWkbPtr += sizeof( int ); int* npoints; for ( int index = 0; index < *nrings; ++index ) { if ( type != POINTS ) { line = new Line3D(); } npoints = ( int* )currentWkbPtr; currentWkbPtr += sizeof( int ); for ( int index2 = 0; index2 < *npoints; ++index2 ) { x = *(( double* )currentWkbPtr ); currentWkbPtr += sizeof( double ); y = *(( double* )currentWkbPtr ); currentWkbPtr += sizeof( double ); if ( hasZValue ) //skip z-coordinate for 25D geometries { z = *(( double* )currentWkbPtr );; currentWkbPtr += sizeof( double ); } else { z = attributeValue; } if ( type == POINTS ) { //todo: handle error code -100 mTriangulation->addPoint( new Point3D( x, y, z ) ); } else { line->insertPoint( new Point3D( x, y, z ) ); } } if ( type != POINTS ) { mTriangulation->addLine( line, type == BREAK_LINES ); } } break; } case QGis::WKBMultiPolygon25D: hasZValue = true; case QGis::WKBMultiPolygon: { currentWkbPtr += ( 1 + sizeof( int ) ); int* npolys = ( int* )currentWkbPtr; int* nrings; int* npoints; currentWkbPtr += sizeof( int ); for ( int index = 0; index < *npolys; ++index ) { currentWkbPtr += ( 1 + sizeof( int ) ); //skip endian and polygon type nrings = ( int* )currentWkbPtr; currentWkbPtr += sizeof( int ); for ( int index2 = 0; index2 < *nrings; ++index2 ) { if ( type != POINTS ) { line = new Line3D(); } npoints = ( int* )currentWkbPtr; currentWkbPtr += sizeof( int ); for ( int index3 = 0; index3 < *npoints; ++index3 ) { x = *(( double* )currentWkbPtr ); currentWkbPtr += sizeof( double ); y = *(( double* )currentWkbPtr ); currentWkbPtr += sizeof( double ); if ( hasZValue ) //skip z-coordinate for 25D geometries { z = *(( double* )currentWkbPtr ); currentWkbPtr += sizeof( double ); } else { z = attributeValue; } if ( type == POINTS ) { //todo: handle error code -100 mTriangulation->addPoint( new Point3D( x, y, z ) ); } else { line->insertPoint( new Point3D( x, y, z ) ); } } if ( type != POINTS ) { mTriangulation->addLine( line, type == BREAK_LINES ); } } } break; } default: //should not happen... break; } return 0; }
QVariantMap QgsLineIntersectionAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { std::unique_ptr< QgsFeatureSource > sourceA( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); if ( !sourceA ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) ); std::unique_ptr< QgsFeatureSource > sourceB( parameterAsSource( parameters, QStringLiteral( "INTERSECT" ), context ) ); if ( !sourceB ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INTERSECT" ) ) ); const QStringList fieldsA = parameterAsFields( parameters, QStringLiteral( "INPUT_FIELDS" ), context ); const QStringList fieldsB = parameterAsFields( parameters, QStringLiteral( "INTERSECT_FIELDS" ), context ); QgsAttributeList fieldIndicesA = QgsProcessingUtils::fieldNamesToIndices( fieldsA, sourceA->fields() ); QgsAttributeList fieldIndicesB = QgsProcessingUtils::fieldNamesToIndices( fieldsB, sourceB->fields() ); QString intersectFieldsPrefix = parameterAsString( parameters, QStringLiteral( "INTERSECT_FIELDS_PREFIX" ), context ); QgsFields outFields = QgsProcessingUtils::combineFields( QgsProcessingUtils::indicesToFields( fieldIndicesA, sourceA->fields() ), QgsProcessingUtils::indicesToFields( fieldIndicesB, sourceB->fields() ), intersectFieldsPrefix ); QString dest; std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, outFields, QgsWkbTypes::Point, sourceA->sourceCrs(), QgsFeatureSink::RegeneratePrimaryKey ) ); if ( !sink ) throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); QgsSpatialIndex spatialIndex( sourceB->getFeatures( QgsFeatureRequest().setNoAttributes().setDestinationCrs( sourceA->sourceCrs(), context.transformContext() ) ), feedback ); QgsFeature outFeature; QgsFeatureIterator features = sourceA->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( fieldIndicesA ) ); double step = sourceA->featureCount() > 0 ? 100.0 / sourceA->featureCount() : 1; int i = 0; QgsFeature inFeatureA; while ( features.nextFeature( inFeatureA ) ) { i++; if ( feedback->isCanceled() ) { break; } if ( !inFeatureA.hasGeometry() ) continue; QgsGeometry inGeom = inFeatureA.geometry(); QgsFeatureIds lines = spatialIndex.intersects( inGeom.boundingBox() ).toSet(); if ( !lines.empty() ) { // use prepared geometries for faster intersection tests std::unique_ptr< QgsGeometryEngine > engine( QgsGeometry::createGeometryEngine( inGeom.constGet() ) ); engine->prepareGeometry(); QgsFeatureRequest request = QgsFeatureRequest().setFilterFids( lines ); request.setDestinationCrs( sourceA->sourceCrs(), context.transformContext() ); request.setSubsetOfAttributes( fieldIndicesB ); QgsFeature inFeatureB; QgsFeatureIterator featuresB = sourceB->getFeatures( request ); while ( featuresB.nextFeature( inFeatureB ) ) { if ( feedback->isCanceled() ) { break; } QgsGeometry tmpGeom = inFeatureB.geometry(); if ( engine->intersects( tmpGeom.constGet() ) ) { QgsMultiPointXY points; QgsGeometry intersectGeom = inGeom.intersection( tmpGeom ); QgsAttributes outAttributes; for ( int a : qgis::as_const( fieldIndicesA ) ) { outAttributes.append( inFeatureA.attribute( a ) ); } for ( int b : qgis::as_const( fieldIndicesB ) ) { outAttributes.append( inFeatureB.attribute( b ) ); } if ( QgsWkbTypes::flatType( intersectGeom.wkbType() ) == QgsWkbTypes::GeometryCollection ) { const QVector<QgsGeometry> geomCollection = intersectGeom.asGeometryCollection(); for ( const QgsGeometry &part : geomCollection ) { if ( part.type() == QgsWkbTypes::PointGeometry ) { if ( part.isMultipart() ) { points = part.asMultiPoint(); } else { points.append( part.asPoint() ); } } } } else if ( intersectGeom.type() == QgsWkbTypes::PointGeometry ) { if ( intersectGeom.isMultipart() ) { points = intersectGeom.asMultiPoint(); } else { points.append( intersectGeom.asPoint() ); } } for ( const QgsPointXY &j : qgis::as_const( points ) ) { outFeature.setGeometry( QgsGeometry::fromPointXY( j ) ); outFeature.setAttributes( outAttributes ); sink->addFeature( outFeature, QgsFeatureSink::FastInsert ); } } } } feedback->setProgress( i * step ); } QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), dest ); return outputs; }
bool QgsPointDistanceRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker ) { Q_UNUSED( drawVertexMarker ); Q_UNUSED( context ); Q_UNUSED( layer ); //check if there is already a point at that position if ( !feature.hasGeometry() ) return false; QgsMarkerSymbol* symbol = firstSymbolForFeature( feature, context ); //if the feature has no symbol (eg, no matching rule in a rule-based renderer), skip it if ( !symbol ) return false; //point position in screen coords QgsGeometry geom = feature.geometry(); QgsWkbTypes::Type geomType = geom.wkbType(); if ( QgsWkbTypes::flatType( geomType ) != QgsWkbTypes::Point ) { //can only render point type return false; } QString label; if ( mDrawLabels ) { label = getLabel( feature ); } QgsCoordinateTransform xform = context.coordinateTransform(); QgsFeature transformedFeature = feature; if ( xform.isValid() ) { geom.transform( xform ); transformedFeature.setGeometry( geom ); } double searchDistance = mTolerance * QgsSymbolLayerUtils::mapUnitScaleFactor( context, mToleranceUnit, mToleranceMapUnitScale ); QgsPoint point = transformedFeature.geometry().asPoint(); QList<QgsFeatureId> intersectList = mSpatialIndex->intersects( searchRect( point, searchDistance ) ); if ( intersectList.empty() ) { mSpatialIndex->insertFeature( transformedFeature ); // create new group ClusteredGroup newGroup; newGroup << GroupedFeature( transformedFeature, symbol, selected, label ); mClusteredGroups.push_back( newGroup ); // add to group index mGroupIndex.insert( transformedFeature.id(), mClusteredGroups.count() - 1 ); mGroupLocations.insert( transformedFeature.id(), point ); } else { // find group with closest location to this point (may be more than one within search tolerance) QgsFeatureId minDistFeatureId = intersectList.at( 0 ); double minDist = mGroupLocations.value( minDistFeatureId ).distance( point ); for ( int i = 1; i < intersectList.count(); ++i ) { QgsFeatureId candidateId = intersectList.at( i ); double newDist = mGroupLocations.value( candidateId ).distance( point ); if ( newDist < minDist ) { minDist = newDist; minDistFeatureId = candidateId; } } int groupIdx = mGroupIndex[ minDistFeatureId ]; ClusteredGroup& group = mClusteredGroups[groupIdx]; // calculate new centroid of group QgsPoint oldCenter = mGroupLocations.value( minDistFeatureId ); mGroupLocations[ minDistFeatureId ] = QgsPoint(( oldCenter.x() * group.size() + point.x() ) / ( group.size() + 1.0 ), ( oldCenter.y() * group.size() + point.y() ) / ( group.size() + 1.0 ) ); // add to a group group << GroupedFeature( transformedFeature, symbol, selected, label ); // add to group index mGroupIndex.insert( transformedFeature.id(), groupIdx ); } return true; }
QgsGeometry* QgsMapToolDeletePart::partUnderPoint( QPoint point, int& fid, int& partNum ) { QgsFeature f; QgsGeometry* geomPart = new QgsGeometry(); switch ( vlayer->geometryType() ) { case QGis::Point: case QGis::Line: { if ( mSnapper.snapToCurrentLayer( point, mRecentSnappingResults, QgsSnapper::SnapToVertexAndSegment ) == 0 ) { if ( mRecentSnappingResults.length() > 0 ) { QgsSnappingResult sr = mRecentSnappingResults.first(); int snapVertex = sr.snappedVertexNr; if ( snapVertex == -1 ) snapVertex = sr.beforeVertexNr; vlayer->getFeatures( QgsFeatureRequest().setFilterFid( sr.snappedAtGeometry ) ).nextFeature( f ); QgsGeometry* g = f.geometry(); if ( !g->isMultipart() ) return geomPart; if ( g->wkbType() == QGis::WKBMultiPoint || g->wkbType() == QGis::WKBMultiPoint25D ) { fid = sr.snappedAtGeometry; partNum = snapVertex; return QgsGeometry::fromPoint( sr.snappedVertex ); } if ( g->wkbType() == QGis::WKBMultiLineString || g->wkbType() == QGis::WKBMultiLineString25D ) { QgsMultiPolyline mline = g->asMultiPolyline(); for ( int part = 0; part < mline.count(); part++ ) { if ( snapVertex < mline[part].count() ) { fid = sr.snappedAtGeometry; partNum = part; return QgsGeometry::fromPolyline( mline[part] ); } snapVertex -= mline[part].count(); } } } } break; } case QGis::Polygon: { QgsPoint layerCoords = toLayerCoordinates( vlayer, point ); double searchRadius = QgsTolerance::vertexSearchRadius( mCanvas->currentLayer(), mCanvas->mapSettings() ); QgsRectangle selectRect( layerCoords.x() - searchRadius, layerCoords.y() - searchRadius, layerCoords.x() + searchRadius, layerCoords.y() + searchRadius ); QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectRect ) ); fit.nextFeature( f ); QgsGeometry* g = f.geometry(); if ( !g ) return geomPart; if ( !g->isMultipart() ) return geomPart; QgsMultiPolygon mpolygon = g->asMultiPolygon(); for ( int part = 0; part < mpolygon.count(); part++ ) // go through the polygons { const QgsPolygon& polygon = mpolygon[part]; QgsGeometry* partGeo = QgsGeometry::fromPolygon( polygon ); if ( partGeo->contains( &layerCoords ) ) { fid = f.id(); partNum = part; return partGeo; } } break; } default: { break; } } return geomPart; }
void QgsDelimitedTextProvider::scanFile( bool buildIndexes ) { QStringList messages; // assume the layer is invalid until proven otherwise mLayerValid = false; mValid = false; mRescanRequired = false; clearInvalidLines(); // Initiallize indexes resetIndexes(); bool buildSpatialIndex = buildIndexes && mSpatialIndex != 0; // No point building a subset index if there is no geometry, as all // records will be included. bool buildSubsetIndex = buildIndexes && mBuildSubsetIndex && mGeomRep != GeomNone; if ( ! mFile->isValid() ) { // uri is invalid so the layer must be too... messages.append( tr( "File cannot be opened or delimiter parameters are not valid" ) ); reportErrors( messages ); QgsDebugMsg( "Delimited text source invalid - filename or delimiter parameters" ); return; } // Open the file and get number of rows, etc. We assume that the // file has a header row and process accordingly. Caller should make // sure that the delimited file is properly formed. if ( mGeomRep == GeomAsWkt ) { mWktFieldIndex = mFile->fieldIndex( mWktFieldName ); if ( mWktFieldIndex < 0 ) { messages.append( tr( "%0 field %1 is not defined in delimited text file" ).arg( "Wkt", mWktFieldName ) ); } } else if ( mGeomRep == GeomAsXy ) { mXFieldIndex = mFile->fieldIndex( mXFieldName ); mYFieldIndex = mFile->fieldIndex( mYFieldName ); if ( mXFieldIndex < 0 ) { messages.append( tr( "%0 field %1 is not defined in delimited text file" ).arg( "X", mWktFieldName ) ); } if ( mYFieldIndex < 0 ) { messages.append( tr( "%0 field %1 is not defined in delimited text file" ).arg( "Y", mWktFieldName ) ); } } if ( messages.size() > 0 ) { reportErrors( messages ); QgsDebugMsg( "Delimited text source invalid - missing geometry fields" ); return; } // Scan the entire file to determine // 1) the number of fields (this is handled by QgsDelimitedTextFile mFile // 2) the number of valid features. Note that the selection of valid features // should match the code in QgsDelimitedTextFeatureIterator // 3) the geometric extents of the layer // 4) the type of each field // // Also build subset and spatial indexes. QStringList parts; long nEmptyRecords = 0; long nBadFormatRecords = 0; long nIncompatibleGeometry = 0; long nInvalidGeometry = 0; long nEmptyGeometry = 0; mNumberFeatures = 0; mExtent = QgsRectangle(); QList<bool> isEmpty; QList<bool> couldBeInt; QList<bool> couldBeLongLong; QList<bool> couldBeDouble; while ( true ) { QgsDelimitedTextFile::Status status = mFile->nextRecord( parts ); if ( status == QgsDelimitedTextFile::RecordEOF ) break; if ( status != QgsDelimitedTextFile::RecordOk ) { nBadFormatRecords++; recordInvalidLine( tr( "Invalid record format at line %1" ) ); continue; } // Skip over empty records if ( recordIsEmpty( parts ) ) { nEmptyRecords++; continue; } // Check geometries are valid bool geomValid = true; if ( mGeomRep == GeomAsWkt ) { if ( mWktFieldIndex >= parts.size() || parts[mWktFieldIndex].isEmpty() ) { nEmptyGeometry++; mNumberFeatures++; } else { // Get the wkt - confirm it is valid, get the type, and // if compatible with the rest of file, add to the extents QString sWkt = parts[mWktFieldIndex]; QgsGeometry *geom = 0; if ( !mWktHasPrefix && sWkt.indexOf( WktPrefixRegexp ) >= 0 ) mWktHasPrefix = true; if ( !mWktHasZM && sWkt.indexOf( WktZMRegexp ) >= 0 ) mWktHasZM = true; geom = geomFromWkt( sWkt, mWktHasPrefix, mWktHasZM ); if ( geom ) { QGis::WkbType type = geom->wkbType(); if ( type != QGis::WKBNoGeometry ) { if ( mGeometryType == QGis::UnknownGeometry || geom->type() == mGeometryType ) { mGeometryType = geom->type(); if ( mNumberFeatures == 0 ) { mNumberFeatures++; mWkbType = type; mExtent = geom->boundingBox(); } else { mNumberFeatures++; if ( geom->isMultipart() ) mWkbType = type; QgsRectangle bbox( geom->boundingBox() ); mExtent.combineExtentWith( &bbox ); } if ( buildSpatialIndex ) { QgsFeature f; f.setFeatureId( mFile->recordId() ); f.setGeometry( geom ); mSpatialIndex->insertFeature( f ); // Feature now has ownership of geometry, so set to null // here to avoid deleting twice. geom = 0; } } else { nIncompatibleGeometry++; geomValid = false; } } if ( geom ) delete geom; } else { geomValid = false; nInvalidGeometry++; recordInvalidLine( tr( "Invalid WKT at line %1" ) ); } } } else if ( mGeomRep == GeomAsXy ) { // Get the x and y values, first checking to make sure they // aren't null. QString sX = mXFieldIndex < parts.size() ? parts[mXFieldIndex] : QString(); QString sY = mYFieldIndex < parts.size() ? parts[mYFieldIndex] : QString(); if ( sX.isEmpty() && sY.isEmpty() ) { nEmptyGeometry++; mNumberFeatures++; } else { QgsPoint pt; bool ok = pointFromXY( sX, sY, pt, mDecimalPoint, mXyDms ); if ( ok ) { if ( mNumberFeatures > 0 ) { mExtent.combineExtentWith( pt.x(), pt.y() ); } else { // Extent for the first point is just the first point mExtent.set( pt.x(), pt.y(), pt.x(), pt.y() ); mWkbType = QGis::WKBPoint; mGeometryType = QGis::Point; } mNumberFeatures++; if ( buildSpatialIndex && qIsFinite( pt.x() ) && qIsFinite( pt.y() ) ) { QgsFeature f; f.setFeatureId( mFile->recordId() ); f.setGeometry( QgsGeometry::fromPoint( pt ) ); mSpatialIndex->insertFeature( f ); } } else { geomValid = false; nInvalidGeometry++; recordInvalidLine( tr( "Invalid X or Y fields at line %1" ) ); } } } else { mWkbType = QGis::WKBNoGeometry; mNumberFeatures++; } if ( ! geomValid ) continue; if ( buildSubsetIndex ) mSubsetIndex.append( mFile->recordId() ); // If we are going to use this record, then assess the potential types of each colum for ( int i = 0; i < parts.size(); i++ ) { QString &value = parts[i]; // Ignore empty fields - spreadsheet generated CSV files often // have random empty fields at the end of a row if ( value.isEmpty() ) continue; // Expand the columns to include this non empty field if necessary while ( couldBeInt.size() <= i ) { isEmpty.append( true ); couldBeInt.append( false ); couldBeLongLong.append( false ); couldBeDouble.append( false ); } // If this column has been empty so far then initiallize it // for possible types if ( isEmpty[i] ) { isEmpty[i] = false; couldBeInt[i] = true; couldBeLongLong[i] = true; couldBeDouble[i] = true; } // Now test for still valid possible types for the field // Types are possible until first record which cannot be parsed if ( couldBeInt[i] ) { value.toInt( &couldBeInt[i] ); } if ( couldBeLongLong[i] && ! couldBeInt[i] ) { value.toLongLong( &couldBeLongLong[i] ); } if ( couldBeDouble[i] && ! couldBeLongLong[i] ) { if ( ! mDecimalPoint.isEmpty() ) { value.replace( mDecimalPoint, "." ); } value.toDouble( &couldBeDouble[i] ); } } } // Now create the attribute fields. Field types are integer by preference, // failing that double, failing that text. QStringList fieldNames = mFile->fieldNames(); mFieldCount = fieldNames.size(); attributeColumns.clear(); attributeFields.clear(); QString csvtMessage; QStringList csvtTypes = readCsvtFieldTypes( mFile->fileName(), &csvtMessage ); for ( int i = 0; i < fieldNames.size(); i++ ) { // Skip over WKT field ... don't want to display in attribute table if ( i == mWktFieldIndex ) continue; // Add the field index lookup for the column attributeColumns.append( i ); QVariant::Type fieldType = QVariant::String; QString typeName = "text"; if ( i < csvtTypes.size() ) { if ( csvtTypes[i] == "integer" ) { fieldType = QVariant::Int; typeName = "integer"; } else if ( csvtTypes[i] == "long" || csvtTypes[i] == "longlong" || csvtTypes[i] == "int8" ) { fieldType = QVariant::LongLong; //QVariant doesn't support long typeName = "longlong"; } else if ( csvtTypes[i] == "real" || csvtTypes[i] == "double" ) { fieldType = QVariant::Double; typeName = "double"; } } else if ( i < couldBeInt.size() ) { if ( couldBeInt[i] ) { fieldType = QVariant::Int; typeName = "integer"; } else if ( couldBeLongLong[i] ) { fieldType = QVariant::LongLong; typeName = "longlong"; } else if ( couldBeDouble[i] ) { fieldType = QVariant::Double; typeName = "double"; } } attributeFields.append( QgsField( fieldNames[i], fieldType, typeName ) ); } QgsDebugMsg( "Field count for the delimited text file is " + QString::number( attributeFields.size() ) ); QgsDebugMsg( "geometry type is: " + QString::number( mWkbType ) ); QgsDebugMsg( "feature count is: " + QString::number( mNumberFeatures ) ); QStringList warnings; if ( ! csvtMessage.isEmpty() ) warnings.append( csvtMessage ); if ( nBadFormatRecords > 0 ) warnings.append( tr( "%1 records discarded due to invalid format" ).arg( nBadFormatRecords ) ); if ( nEmptyGeometry > 0 ) warnings.append( tr( "%1 records have missing geometry definitions" ).arg( nEmptyGeometry ) ); if ( nInvalidGeometry > 0 ) warnings.append( tr( "%1 records discarded due to invalid geometry definitions" ).arg( nInvalidGeometry ) ); if ( nIncompatibleGeometry > 0 ) warnings.append( tr( "%1 records discarded due to incompatible geometry types" ).arg( nIncompatibleGeometry ) ); reportErrors( warnings ); // Decide whether to use subset ids to index records rather than simple iteration through all // If more than 10% of records are being skipped, then use index. (Not based on any experimentation, // could do with some analysis?) if ( buildSubsetIndex ) { long recordCount = mFile->recordCount(); recordCount -= recordCount / SUBSET_ID_THRESHOLD_FACTOR; mUseSubsetIndex = mSubsetIndex.size() < recordCount; if ( ! mUseSubsetIndex ) mSubsetIndex = QList<quintptr>(); } mUseSpatialIndex = buildSpatialIndex; mValid = mGeometryType != QGis::UnknownGeometry; mLayerValid = mValid; // If it is valid, then watch for changes to the file connect( mFile, SIGNAL( fileUpdated() ), this, SLOT( onFileUpdated() ) ); }
QgsGeometry QgsMapToolDeletePart::partUnderPoint( QPoint point, QgsFeatureId &fid, int &partNum ) { QgsFeature f; QgsGeometry geomPart; switch ( vlayer->geometryType() ) { case QgsWkbTypes::PointGeometry: case QgsWkbTypes::LineGeometry: { QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToCurrentLayer( point, QgsPointLocator::Types( QgsPointLocator::Vertex | QgsPointLocator::Edge ) ); if ( !match.isValid() ) return geomPart; int snapVertex = match.vertexIndex(); vlayer->getFeatures( QgsFeatureRequest().setFilterFid( match.featureId() ) ).nextFeature( f ); QgsGeometry g = f.geometry(); if ( !g.isMultipart() ) { fid = match.featureId(); return QgsGeometry::fromPointXY( match.point() ); } else if ( QgsWkbTypes::geometryType( g.wkbType() ) == QgsWkbTypes::PointGeometry ) { fid = match.featureId(); partNum = snapVertex; return QgsGeometry::fromPointXY( match.point() ); } else if ( QgsWkbTypes::geometryType( g.wkbType() ) == QgsWkbTypes::LineGeometry ) { QgsMultiPolylineXY mline = g.asMultiPolyline(); for ( int part = 0; part < mline.count(); part++ ) { if ( snapVertex < mline[part].count() ) { fid = match.featureId(); partNum = part; return QgsGeometry::fromPolylineXY( mline[part] ); } snapVertex -= mline[part].count(); } } break; } case QgsWkbTypes::PolygonGeometry: { QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToCurrentLayer( point, QgsPointLocator::Area ); if ( !match.isValid() ) return geomPart; vlayer->getFeatures( QgsFeatureRequest().setFilterFid( match.featureId() ) ).nextFeature( f ); QgsGeometry g = f.geometry(); if ( g.isNull() ) return geomPart; QgsPointXY layerCoords = toLayerCoordinates( vlayer, point ); if ( !g.isMultipart() ) { fid = f.id(); return geomPart; } QgsMultiPolygonXY mpolygon = g.asMultiPolygon(); for ( int part = 0; part < mpolygon.count(); part++ ) // go through the polygons { const QgsPolygonXY &polygon = mpolygon[part]; QgsGeometry partGeo = QgsGeometry::fromPolygonXY( polygon ); if ( partGeo.contains( &layerCoords ) ) { fid = f.id(); partNum = part; return partGeo; } } break; } default: { break; } } return geomPart; }
int QgsTINInterpolator::insertData( QgsFeature* f, bool zCoord, int attr, InputType type ) { if ( !f ) { return 1; } QgsGeometry g = f->geometry(); { if ( g.isNull() ) { return 2; } } //check attribute value double attributeValue = 0; bool attributeConversionOk = false; if ( !zCoord ) { QVariant attributeVariant = f->attribute( attr ); if ( !attributeVariant.isValid() ) //attribute not found, something must be wrong (e.g. NULL value) { return 3; } attributeValue = attributeVariant.toDouble( &attributeConversionOk ); if ( !attributeConversionOk || qIsNaN( attributeValue ) ) //don't consider vertices with attributes like 'nan' for the interpolation { return 4; } } //parse WKB. It is ugly, but we cannot use the methods with QgsPoint because they don't contain z-values for 25D types bool hasZValue = false; double x, y, z; QByteArray wkb( g.exportToWkb() ); QgsConstWkbPtr currentWkbPtr( wkb ); currentWkbPtr.readHeader(); //maybe a structure or break line Line3D* line = nullptr; QgsWkbTypes::Type wkbType = g.wkbType(); switch ( wkbType ) { case QgsWkbTypes::Point25D: hasZValue = true; FALLTHROUGH; case QgsWkbTypes::Point: { currentWkbPtr >> x >> y; if ( zCoord && hasZValue ) { currentWkbPtr >> z; } else { z = attributeValue; } Point3D* thePoint = new Point3D( x, y, z ); if ( mTriangulation->addPoint( thePoint ) == -100 ) { return -1; } break; }
bool QgsPointDisplacementRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker ) { Q_UNUSED( drawVertexMarker ); //point position in screen coords QgsGeometry* geom = feature.geometry(); QGis::WkbType geomType = geom->wkbType(); if ( geomType != QGis::WKBPoint && geomType != QGis::WKBPoint25D ) { //can only render point type return false; } QPointF pt; _getPoint( pt, context, geom->asWkb() ); //get list of labels and symbols QStringList labelAttributeList; QList<QgsMarkerSymbolV2*> symbolList; if ( mDisplacementIds.contains( feature.id() ) ) { //create the symbol for the whole display group if the id is the first entry in a display group QList<QMap<QgsFeatureId, QgsFeature> >::iterator it = mDisplacementGroups.begin(); for ( ; it != mDisplacementGroups.end(); ++it ) { //create the symbol for the whole display group if the id is the first entry in a display group if ( feature.id() == it->begin().key() ) { QMap<QgsFeatureId, QgsFeature>::iterator attIt = it->begin(); for ( ; attIt != it->end(); ++attIt ) { if ( mDrawLabels ) { labelAttributeList << getLabel( attIt.value() ); } else { labelAttributeList << QString(); } symbolList << dynamic_cast<QgsMarkerSymbolV2*>( firstSymbolForFeature( mRenderer, attIt.value() ) ); } } } } else //only one feature { symbolList << dynamic_cast<QgsMarkerSymbolV2*>( firstSymbolForFeature( mRenderer, feature ) ); if ( mDrawLabels ) { labelAttributeList << getLabel( feature ); } else { labelAttributeList << QString(); } } if ( symbolList.isEmpty() && labelAttributeList.isEmpty() ) { return true; //display all point symbols for one posi } //draw symbol double diagonal = 0; double currentWidthFactor; //scale symbol size to map unit and output resolution QList<QgsMarkerSymbolV2*>::const_iterator it = symbolList.constBegin(); for ( ; it != symbolList.constEnd(); ++it ) { if ( *it ) { currentWidthFactor = QgsSymbolLayerV2Utils::lineWidthScaleFactor( context, ( *it )->outputUnit() ); double currentDiagonal = sqrt( 2 * (( *it )->size() * ( *it )->size() ) ) * currentWidthFactor; if ( currentDiagonal > diagonal ) { diagonal = currentDiagonal; } } } QgsSymbolV2RenderContext symbolContext( context, QgsSymbolV2::MM, 1.0, selected ); double circleAdditionPainterUnits = symbolContext.outputLineWidth( mCircleRadiusAddition ); double radius = qMax(( diagonal / 2 ), labelAttributeList.size() * diagonal / 2 / M_PI ) + circleAdditionPainterUnits; //draw Circle drawCircle( radius, symbolContext, pt, symbolList.size() ); QList<QPointF> symbolPositions; QList<QPointF> labelPositions; calculateSymbolAndLabelPositions( pt, labelAttributeList.size(), radius, diagonal, symbolPositions, labelPositions ); //draw mid point if ( labelAttributeList.size() > 1 ) { if ( mCenterSymbol ) { mCenterSymbol->renderPoint( pt, &feature, context, layer, selected ); } else { context.painter()->drawRect( QRectF( pt.x() - symbolContext.outputLineWidth( 1 ), pt.y() - symbolContext.outputLineWidth( 1 ), symbolContext.outputLineWidth( 2 ), symbolContext.outputLineWidth( 2 ) ) ); } } //draw symbols on the circle drawSymbols( feature, context, symbolList, symbolPositions, selected ); //and also the labels drawLabels( pt, symbolContext, labelPositions, labelAttributeList ); return true; }
int QgsTransectSample::createSample( QProgressDialog* pd ) { Q_UNUSED( pd ); if ( !mStrataLayer || !mStrataLayer->isValid() ) { return 1; } if ( !mBaselineLayer || !mBaselineLayer->isValid() ) { return 2; } //stratum id is not necessarily an integer QVariant::Type stratumIdType = QVariant::Int; if ( !mStrataIdAttribute.isEmpty() ) { stratumIdType = mStrataLayer->pendingFields().field( mStrataIdAttribute ).type(); } //create vector file writers for output QgsFields outputPointFields; outputPointFields.append( QgsField( "id", stratumIdType ) ); outputPointFields.append( QgsField( "station_id", QVariant::Int ) ); outputPointFields.append( QgsField( "stratum_id", stratumIdType ) ); outputPointFields.append( QgsField( "station_code", QVariant::String ) ); outputPointFields.append( QgsField( "start_lat", QVariant::Double ) ); outputPointFields.append( QgsField( "start_long", QVariant::Double ) ); QgsVectorFileWriter outputPointWriter( mOutputPointLayer, "utf-8", outputPointFields, QGis::WKBPoint, &( mStrataLayer->crs() ) ); if ( outputPointWriter.hasError() != QgsVectorFileWriter::NoError ) { return 3; } outputPointFields.append( QgsField( "bearing", QVariant::Double ) ); //add bearing attribute for lines QgsVectorFileWriter outputLineWriter( mOutputLineLayer, "utf-8", outputPointFields, QGis::WKBLineString, &( mStrataLayer->crs() ) ); if ( outputLineWriter.hasError() != QgsVectorFileWriter::NoError ) { return 4; } QgsFields usedBaselineFields; usedBaselineFields.append( QgsField( "stratum_id", stratumIdType ) ); usedBaselineFields.append( QgsField( "ok", QVariant::String ) ); QgsVectorFileWriter usedBaselineWriter( mUsedBaselineLayer, "utf-8", usedBaselineFields, QGis::WKBLineString, &( mStrataLayer->crs() ) ); if ( usedBaselineWriter.hasError() != QgsVectorFileWriter::NoError ) { return 5; } //debug: write clipped buffer bounds with stratum id to same directory as out_point QFileInfo outputPointInfo( mOutputPointLayer ); QString bufferClipLineOutput = outputPointInfo.absolutePath() + "/out_buffer_clip_line.shp"; QgsFields bufferClipLineFields; bufferClipLineFields.append( QgsField( "id", stratumIdType ) ); QgsVectorFileWriter bufferClipLineWriter( bufferClipLineOutput, "utf-8", bufferClipLineFields, QGis::WKBLineString, &( mStrataLayer->crs() ) ); //configure distanceArea depending on minDistance units and output CRS QgsDistanceArea distanceArea; distanceArea.setSourceCrs( mStrataLayer->crs().srsid() ); if ( mMinDistanceUnits == Meters ) { distanceArea.setEllipsoidalMode( true ); } else { distanceArea.setEllipsoidalMode( false ); } //possibility to transform output points to lat/long QgsCoordinateTransform toLatLongTransform( mStrataLayer->crs(), QgsCoordinateReferenceSystem( 4326, QgsCoordinateReferenceSystem::EpsgCrsId ) ); //init random number generator mt_srand( QTime::currentTime().msec() ); QgsFeatureRequest fr; fr.setSubsetOfAttributes( QStringList() << mStrataIdAttribute << mMinDistanceAttribute << mNPointsAttribute, mStrataLayer->pendingFields() ); QgsFeatureIterator strataIt = mStrataLayer->getFeatures( fr ); QgsFeature fet; int nTotalTransects = 0; int nFeatures = 0; if ( pd ) { pd->setMaximum( mStrataLayer->featureCount() ); } while ( strataIt.nextFeature( fet ) ) { if ( pd ) { pd->setValue( nFeatures ); } if ( pd && pd->wasCanceled() ) { break; } if ( !fet.constGeometry() ) { continue; } const QgsGeometry* strataGeom = fet.constGeometry(); //find baseline for strata QVariant strataId = fet.attribute( mStrataIdAttribute ); QgsGeometry* baselineGeom = findBaselineGeometry( strataId.isValid() ? strataId : -1 ); if ( !baselineGeom ) { continue; } double minDistance = fet.attribute( mMinDistanceAttribute ).toDouble(); double minDistanceLayerUnits = minDistance; //if minDistance is in meters and the data in degrees, we need to apply a rough conversion for the buffer distance double bufferDist = bufferDistance( minDistance ); if ( mMinDistanceUnits == Meters && mStrataLayer->crs().mapUnits() == QGis::DecimalDegrees ) { minDistanceLayerUnits = minDistance / 111319.9; } QgsGeometry* clippedBaseline = strataGeom->intersection( baselineGeom ); if ( !clippedBaseline || clippedBaseline->wkbType() == QGis::WKBUnknown ) { delete clippedBaseline; continue; } QgsGeometry* bufferLineClipped = clipBufferLine( strataGeom, clippedBaseline, bufferDist ); if ( !bufferLineClipped ) { delete clippedBaseline; continue; } //save clipped baseline to file QgsFeature blFeature; blFeature.setGeometry( *clippedBaseline ); blFeature.setAttribute( "stratum_id", strataId ); blFeature.setAttribute( "ok", "f" ); usedBaselineWriter.addFeature( blFeature ); //start loop to create random points along the baseline int nTransects = fet.attribute( mNPointsAttribute ).toInt(); int nCreatedTransects = 0; int nIterations = 0; int nMaxIterations = nTransects * 50; QgsSpatialIndex sIndex; //to check minimum distance QMap< QgsFeatureId, QgsGeometry* > lineFeatureMap; while ( nCreatedTransects < nTransects && nIterations < nMaxIterations ) { double randomPosition = (( double )mt_rand() / MD_RAND_MAX ) * clippedBaseline->length(); QgsGeometry* samplePoint = clippedBaseline->interpolate( randomPosition ); ++nIterations; if ( !samplePoint ) { continue; } QgsPoint sampleQgsPoint = samplePoint->asPoint(); QgsPoint latLongSamplePoint = toLatLongTransform.transform( sampleQgsPoint ); QgsFeature samplePointFeature; samplePointFeature.setGeometry( samplePoint ); samplePointFeature.setAttribute( "id", nTotalTransects + 1 ); samplePointFeature.setAttribute( "station_id", nCreatedTransects + 1 ); samplePointFeature.setAttribute( "stratum_id", strataId ); samplePointFeature.setAttribute( "station_code", strataId.toString() + "_" + QString::number( nCreatedTransects + 1 ) ); samplePointFeature.setAttribute( "start_lat", latLongSamplePoint.y() ); samplePointFeature.setAttribute( "start_long", latLongSamplePoint.x() ); //find closest point on clipped buffer line QgsPoint minDistPoint; int afterVertex; if ( bufferLineClipped->closestSegmentWithContext( sampleQgsPoint, minDistPoint, afterVertex ) < 0 ) { continue; } //bearing between sample point and min dist point (transect direction) double bearing = distanceArea.bearing( sampleQgsPoint, minDistPoint ) / M_PI * 180.0; QgsPolyline sampleLinePolyline; QgsPoint ptFarAway( sampleQgsPoint.x() + ( minDistPoint.x() - sampleQgsPoint.x() ) * 1000000, sampleQgsPoint.y() + ( minDistPoint.y() - sampleQgsPoint.y() ) * 1000000 ); QgsPolyline lineFarAway; lineFarAway << sampleQgsPoint << ptFarAway; QgsGeometry* lineFarAwayGeom = QgsGeometry::fromPolyline( lineFarAway ); QgsGeometry* lineClipStratum = lineFarAwayGeom->intersection( strataGeom ); if ( !lineClipStratum ) { delete lineFarAwayGeom; delete lineClipStratum; continue; } //cancel if distance between sample point and line is too large (line does not start at point if ( lineClipStratum->distance( *samplePoint ) > 0.000001 ) { delete lineFarAwayGeom; delete lineClipStratum; continue; } //if lineClipStratum is a multiline, take the part line closest to sampleQgsPoint if ( lineClipStratum->wkbType() == QGis::WKBMultiLineString || lineClipStratum->wkbType() == QGis::WKBMultiLineString25D ) { QgsGeometry* singleLine = closestMultilineElement( sampleQgsPoint, lineClipStratum ); if ( singleLine ) { delete lineClipStratum; lineClipStratum = singleLine; } } //cancel if length of lineClipStratum is too small double transectLength = distanceArea.measure( lineClipStratum ); if ( transectLength < mMinTransectLength ) { delete lineFarAwayGeom; delete lineClipStratum; continue; } //search closest existing profile. Cancel if dist < minDist if ( otherTransectWithinDistance( lineClipStratum, minDistanceLayerUnits, minDistance, sIndex, lineFeatureMap, distanceArea ) ) { delete lineFarAwayGeom; delete lineClipStratum; continue; } QgsFeatureId fid( nCreatedTransects ); QgsFeature sampleLineFeature( fid ); sampleLineFeature.setGeometry( lineClipStratum ); sampleLineFeature.setAttribute( "id", nTotalTransects + 1 ); sampleLineFeature.setAttribute( "station_id", nCreatedTransects + 1 ); sampleLineFeature.setAttribute( "stratum_id", strataId ); sampleLineFeature.setAttribute( "station_code", strataId.toString() + "_" + QString::number( nCreatedTransects + 1 ) ); sampleLineFeature.setAttribute( "start_lat", latLongSamplePoint.y() ); sampleLineFeature.setAttribute( "start_long", latLongSamplePoint.x() ); sampleLineFeature.setAttribute( "bearing", bearing ); outputLineWriter.addFeature( sampleLineFeature ); //add point to file writer here. //It can only be written if the corresponding transect has been as well outputPointWriter.addFeature( samplePointFeature ); sIndex.insertFeature( sampleLineFeature ); Q_NOWARN_DEPRECATED_PUSH lineFeatureMap.insert( fid, sampleLineFeature.geometryAndOwnership() ); Q_NOWARN_DEPRECATED_POP delete lineFarAwayGeom; ++nTotalTransects; ++nCreatedTransects; } delete clippedBaseline; QgsFeature bufferClipFeature; bufferClipFeature.setGeometry( bufferLineClipped ); bufferClipFeature.setAttribute( "id", strataId ); bufferClipLineWriter.addFeature( bufferClipFeature ); //delete bufferLineClipped; //delete all line geometries in spatial index QMap< QgsFeatureId, QgsGeometry* >::iterator featureMapIt = lineFeatureMap.begin(); for ( ; featureMapIt != lineFeatureMap.end(); ++featureMapIt ) { delete( featureMapIt.value() ); } lineFeatureMap.clear(); delete baselineGeom; ++nFeatures; } if ( pd ) { pd->setValue( mStrataLayer->featureCount() ); } return 0; }