QgsProperty QgsProperty::fromValue( const QVariant &value, bool isActive ) { QgsProperty p; p.setStaticValue( value ); p.setActive( isActive ); return p; }
void QgsPropertyOverrideButton::setToProperty( const QgsProperty &property ) { if ( property ) { switch ( property.propertyType() ) { case QgsProperty::StaticProperty: case QgsProperty::InvalidProperty: break; case QgsProperty::FieldBasedProperty: { mFieldName = property.field(); break; } case QgsProperty::ExpressionBasedProperty: { mExpressionString = property.expressionString(); break; } } } else { mFieldName.clear(); mExpressionString.clear(); } mProperty = property; setActive( mProperty && mProperty.isActive() ); updateSiblingWidgets( isActive() ); updateGui(); }
QgsProperty QgsProperty::fromExpression( const QString &expression, bool isActive ) { QgsProperty p; p.setExpressionString( expression ); p.setActive( isActive ); return p; }
QgsProperty QgsProperty::fromField( const QString &fieldName, bool isActive ) { QgsProperty p; p.setField( fieldName ); p.setActive( isActive ); return p; }
QStringList QgsProject::readListEntry( QString const & scope, const QString & key, bool * ok ) const { QgsProperty * property = findKey_( scope, key, imp_->properties_ ); QVariant value; if ( property ) { value = property->value(); } bool valid = QVariant::StringList == value.type(); if ( ok ) { *ok = valid; } if ( valid ) { return value.toStringList(); } return QStringList(); } // QgsProject::readListEntry
bool QgsProject::readBoolEntry( QString const &scope, const QString & key, bool def, bool * ok ) const { QgsProperty * property = findKey_( scope, key, imp_->properties_ ); QVariant value; if ( property ) { value = property->value(); } bool valid = value.canConvert( QVariant::Bool ); if ( ok ) { *ok = valid; } if ( valid ) { return value.toBool(); } return def; } // QgsProject::readBoolEntry
QString QgsProcessingAlgorithm::invalidSinkError( const QVariantMap ¶meters, const QString &name ) { if ( !parameters.contains( name ) ) return QObject::tr( "Could not create destination layer for %1: no value specified for parameter" ).arg( name ); else { QVariant var = parameters.value( name ); if ( var.canConvert<QgsProcessingOutputLayerDefinition>() ) { QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( var ); var = fromVar.sink; } if ( var.canConvert<QgsProperty>() ) { QgsProperty p = var.value< QgsProperty >(); if ( p.propertyType() == QgsProperty::StaticProperty ) { var = p.staticValue(); } } if ( !var.toString().isEmpty() ) return QObject::tr( "Could not create destination layer for %1: %2" ).arg( name, var.toString() ); else return QObject::tr( "Could not create destination layer for %1: invalid value" ).arg( name ); } }
void QgsEllipseSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const { // <Graphic> QDomElement graphicElem = doc.createElement( QStringLiteral( "se:Graphic" ) ); element.appendChild( graphicElem ); double strokeWidth = QgsSymbolLayerUtils::rescaleUom( mStrokeWidth, mStrokeWidthUnit, props ); double symbolWidth = QgsSymbolLayerUtils::rescaleUom( mSymbolWidth, mSymbolWidthUnit, props ); QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, mSymbolName, mColor, mStrokeColor, mStrokeStyle, strokeWidth, symbolWidth ); // <Rotation> QgsProperty ddRotation = mDataDefinedProperties.property( QgsSymbolLayer::PropertyAngle ); QString angleFunc = props.value( QStringLiteral( "angle" ), QLatin1String( "" ) ); if ( angleFunc.isEmpty() ) // symbol has no angle set { if ( ddRotation && ddRotation.isActive() ) { angleFunc = ddRotation.asExpression(); } else if ( !qgsDoubleNear( mAngle, 0.0 ) ) angleFunc = QString::number( mAngle ); } else if ( ddRotation && ddRotation.isActive() ) { // the symbol has an angle and the symbol layer have a rotation // property set angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc, ddRotation.asExpression() ); } else if ( !qgsDoubleNear( mAngle, 0.0 ) ) { // both the symbol and the symbol layer have angle value set bool ok; double angle = angleFunc.toDouble( &ok ); if ( !ok ) { // its a string (probably a property name or a function) angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc ).arg( mAngle ); } else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) ) { // it's a double value angleFunc = QString::number( angle + mAngle ); } } QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc ); // <Displacement> QPointF offset = QgsSymbolLayerUtils::rescaleUom( mOffset, mOffsetUnit, props ); QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, offset ); // store w/h factor in a <VendorOption> double widthHeightFactor = mSymbolWidth / mSymbolHeight; QDomElement factorElem = QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "widthHeightFactor" ), QString::number( widthHeightFactor ) ); graphicElem.appendChild( factorElem ); }
void QgsSymbolsListWidget::createAuxiliaryField() { // try to create an auxiliary layer if not yet created if ( !mLayer->auxiliaryLayer() ) { QgsNewAuxiliaryLayerDialog dlg( mLayer, this ); dlg.exec(); } // return if still not exists if ( !mLayer->auxiliaryLayer() ) return; QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() ); QgsSymbolLayer::Property key = static_cast< QgsSymbolLayer::Property >( button->propertyKey() ); const QgsPropertyDefinition def = QgsSymbolLayer::propertyDefinitions()[key]; // create property in auxiliary storage if necessary if ( !mLayer->auxiliaryLayer()->exists( def ) ) mLayer->auxiliaryLayer()->addAuxiliaryField( def ); // update property with join field name from auxiliary storage QgsProperty property = button->toProperty(); property.setField( QgsAuxiliaryLayer::nameFromProperty( def, true ) ); property.setActive( true ); button->updateFieldLists(); button->setToProperty( property ); QgsMarkerSymbol *markerSymbol = static_cast<QgsMarkerSymbol *>( mSymbol ); QgsLineSymbol *lineSymbol = static_cast<QgsLineSymbol *>( mSymbol ); switch ( key ) { case QgsSymbolLayer::PropertyAngle: if ( markerSymbol ) markerSymbol->setDataDefinedAngle( button->toProperty() ); break; case QgsSymbolLayer::PropertySize: if ( markerSymbol ) { markerSymbol->setDataDefinedSize( button->toProperty() ); markerSymbol->setScaleMethod( QgsSymbol::ScaleDiameter ); } break; case QgsSymbolLayer::PropertyStrokeWidth: if ( lineSymbol ) lineSymbol->setDataDefinedWidth( button->toProperty() ); break; default: break; } emit changed(); }
QString QgsMapToolLabel::dataDefinedColumnName( QgsPalLayerSettings::Property p, const QgsPalLayerSettings &labelSettings ) const { if ( !labelSettings.dataDefinedProperties().isActive( p ) ) return QString(); QgsProperty prop = labelSettings.dataDefinedProperties().property( p ); if ( prop.propertyType() != QgsProperty::FieldBasedProperty ) return QString(); return prop.field(); }
void QgsLabelPropertyDialog::insertChangedValue( QgsPalLayerSettings::Property p, const QVariant &value ) { if ( mDataDefinedProperties.isActive( p ) ) { QgsProperty prop = mDataDefinedProperties.property( p ); if ( prop.propertyType() == QgsProperty::FieldBasedProperty ) { mChangedProperties.insert( mCurLabelFeat.fieldNameIndex( prop.field() ), value ); } } }
QVariant QgsPropertyKey::value() const { QgsProperty *foundQgsProperty = mProperties.value( name() ); if ( !foundQgsProperty ) { QgsDebugMsg( "key has null child" ); return QVariant(); // just return an QVariant::Invalid } return foundQgsProperty->value(); } // QVariant QgsPropertyKey::value()
QVariant QgsPropertyKey::value() const { QgsProperty * foundQgsProperty; if ( 0 == ( foundQgsProperty = mProperties.value( name() ) ) ) { // recurse down to next key return foundQgsProperty->value(); } else { QgsDebugMsg( "key has null child" ); return QVariant(); // just return an QVariant::Invalid } } // QVariant QgsPropertyKey::value()
void QgsDataDefinedSizeLegend::updateFromSymbolAndProperty( const QgsMarkerSymbol *symbol, const QgsProperty &ddSize ) { mSymbol.reset( symbol->clone() ); mSymbol->setDataDefinedSize( QgsProperty() ); // original symbol may have had data-defined size associated const QgsSizeScaleTransformer *sizeTransformer = dynamic_cast< const QgsSizeScaleTransformer * >( ddSize.transformer() ); mSizeScaleTransformer.reset( sizeTransformer ? sizeTransformer->clone() : nullptr ); if ( mTitleLabel.isEmpty() ) mTitleLabel = ddSize.propertyType() == QgsProperty::ExpressionBasedProperty ? ddSize.expressionString() : ddSize.field(); // automatically generate classes if no classes are defined if ( sizeTransformer && mSizeClasses.isEmpty() ) { mSizeClasses.clear(); Q_FOREACH ( double v, QgsSymbolLayerUtils::prettyBreaks( sizeTransformer->minValue(), sizeTransformer->maxValue(), 4 ) ) { mSizeClasses << SizeClass( v, QString::number( v ) ); } }
bool QgsMapToolLabel::createAuxiliaryFields( LabelDetails &details, QgsPalIndexes &indexes ) const { bool newAuxiliaryLayer = false; QgsVectorLayer *vlayer = details.layer; QString providerId = details.pos.providerID; if ( !vlayer || !vlayer->labelsEnabled() ) return false; if ( !vlayer->auxiliaryLayer() ) { QgsNewAuxiliaryLayerDialog dlg( vlayer ); dlg.exec(); newAuxiliaryLayer = true; } if ( !vlayer->auxiliaryLayer() ) return false; for ( const QgsPalLayerSettings::Property &p : qgis::as_const( mPalProperties ) ) { int index = -1; // always use the default activated property QgsProperty prop = details.settings.dataDefinedProperties().property( p ); if ( prop.propertyType() == QgsProperty::FieldBasedProperty && prop.isActive() ) { index = vlayer->fields().lookupField( prop.field() ); } else { index = QgsAuxiliaryLayer::createProperty( p, vlayer ); } indexes[p] = index; } details.settings = vlayer->labeling()->settings( providerId ); return newAuxiliaryLayer; }
QString QgsProcessingAlgorithm::invalidRasterError( const QVariantMap ¶meters, const QString &name ) { if ( !parameters.contains( name ) ) return QObject::tr( "Could not load source layer for %1: no value specified for parameter" ).arg( name ); else { QVariant var = parameters.value( name ); if ( var.canConvert<QgsProperty>() ) { QgsProperty p = var.value< QgsProperty >(); if ( p.propertyType() == QgsProperty::StaticProperty ) { var = p.staticValue(); } } if ( !var.toString().isEmpty() ) return QObject::tr( "Could not load source layer for %1: %2 not found" ).arg( name, var.toString() ); else return QObject::tr( "Could not load source layer for %1: invalid value" ).arg( name ); } }
bool QgsMapToolLabel::createAuxiliaryFields( LabelDetails &details, QgsDiagramIndexes &indexes ) { bool newAuxiliaryLayer = false; QgsVectorLayer *vlayer = details.layer; if ( !vlayer ) return newAuxiliaryLayer; if ( !vlayer->auxiliaryLayer() ) { QgsNewAuxiliaryLayerDialog dlg( vlayer ); dlg.exec(); newAuxiliaryLayer = true; } if ( !vlayer->auxiliaryLayer() ) return false; for ( const QgsDiagramLayerSettings::Property &p : qgis::as_const( mDiagramProperties ) ) { int index = -1; // always use the default activated property QgsProperty prop = vlayer->diagramLayerSettings()->dataDefinedProperties().property( p ); if ( prop.propertyType() == QgsProperty::FieldBasedProperty && prop.isActive() ) { index = vlayer->fields().lookupField( prop.field() ); } else { index = QgsAuxiliaryLayer::createProperty( p, vlayer ); } indexes[p] = index; } return newAuxiliaryLayer; }
/** return the property that matches the given key sequence, if any @param scope scope of key @param key keyname @param rootProperty is likely to be the top level QgsPropertyKey in QgsProject:e:Imp. @return null if not found, otherwise located Property */ static QgsProperty * findKey_( QString const & scope, QString const & key, QgsPropertyKey & rootProperty ) { QgsPropertyKey * currentProperty = &rootProperty; QgsProperty * nextProperty; // link to next property down hiearchy QStringList keySequence = makeKeyTokens_( scope, key ); while ( ! keySequence.isEmpty() ) { // if the current head of the sequence list matches the property name, // then traverse down the property hierarchy if ( keySequence.first() == currentProperty->name() ) { // remove front key since we're traversing down a level keySequence.pop_front(); // if we have only one key name left, then return the key found if ( 1 == keySequence.count() ) { return currentProperty->find( keySequence.front() ); } // if we're out of keys then the current property is the one we // want; i.e., we're in the rate case of being at the top-most // property node else if ( keySequence.isEmpty() ) { return currentProperty; } else if (( nextProperty = currentProperty->find( keySequence.first() ) ) ) { if ( nextProperty->isKey() ) { currentProperty = dynamic_cast<QgsPropertyKey*>( nextProperty ); } // it may be that this may be one of several property value // nodes keyed by QDict string; if this is the last remaining // key token and the next property is a value node, then // that's the situation, so return the currentProperty else if ( nextProperty->isValue() && ( 1 == keySequence.count() ) ) { return currentProperty; } else // QgsPropertyValue not Key, so return null { return 0x0; } } else // if the next key down isn't found { // then the overall key sequence doesn't exist return 0x0; } } else { return 0x0; } } return 0x0; } // findKey_
QVariant QgsXmlUtils::readVariant( const QDomElement &element ) { QString type = element.attribute( QStringLiteral( "type" ) ); if ( type == QLatin1String( "invalid" ) ) { return QVariant(); } else if ( type == QLatin1String( "int" ) ) { return element.attribute( QStringLiteral( "value" ) ).toInt(); } else if ( type == QLatin1String( "uint" ) ) { return element.attribute( QStringLiteral( "value" ) ).toUInt(); } else if ( type == QLatin1String( "qlonglong" ) ) { return element.attribute( QStringLiteral( "value" ) ).toLongLong(); } else if ( type == QLatin1String( "qulonglong" ) ) { return element.attribute( QStringLiteral( "value" ) ).toULongLong(); } else if ( type == QLatin1String( "double" ) ) { return element.attribute( QStringLiteral( "value" ) ).toDouble(); } else if ( type == QLatin1String( "QString" ) ) { return element.attribute( QStringLiteral( "value" ) ); } else if ( type == QLatin1String( "bool" ) ) { return element.attribute( QStringLiteral( "value" ) ) == QLatin1String( "true" ); } else if ( type == QLatin1String( "Map" ) ) { QVariantMap map; QDomNodeList options = element.childNodes(); for ( int i = 0; i < options.count(); ++i ) { QDomElement elem = options.at( i ).toElement(); if ( elem.tagName() == QLatin1String( "Option" ) ) map.insert( elem.attribute( QStringLiteral( "name" ) ), readVariant( elem ) ); } return map; } else if ( type == QLatin1String( "List" ) ) { QVariantList list; QDomNodeList values = element.childNodes(); for ( int i = 0; i < values.count(); ++i ) { QDomElement elem = values.at( i ).toElement(); list.append( readVariant( elem ) ); } return list; } else if ( type == QLatin1String( "StringList" ) ) { QStringList list; QDomNodeList values = element.childNodes(); for ( int i = 0; i < values.count(); ++i ) { QDomElement elem = values.at( i ).toElement(); list.append( readVariant( elem ).toString() ); } return list; } else if ( type == QLatin1String( "QgsProperty" ) ) { const QDomNodeList values = element.childNodes(); if ( values.isEmpty() ) return QVariant(); QgsProperty p; if ( p.loadVariant( QgsXmlUtils::readVariant( values.at( 0 ).toElement() ) ) ) return p; return QVariant(); } else if ( type == QLatin1String( "QgsCoordinateReferenceSystem" ) ) { QgsCoordinateReferenceSystem crs; crs.readXml( element ); return crs; } else if ( type == QLatin1String( "QgsGeometry" ) ) { return QgsGeometry::fromWkt( element.attribute( "value" ) ); } else { return QVariant(); } }
void QgsLabelPropertyDialog::enableDataDefinedWidgets( QgsVectorLayer *vlayer ) { //loop through data defined properties, this time setting whether or not the widgets are enabled //this can only be done for properties which are assigned to fields Q_FOREACH ( int key, mDataDefinedProperties.propertyKeys() ) { QgsProperty prop = mDataDefinedProperties.property( key ); if ( !prop || !prop.isActive() || prop.propertyType() != QgsProperty::FieldBasedProperty ) { continue; // can only modify attributes with an active data definition of a mapped field } QString ddField = prop.field(); if ( ddField.isEmpty() ) { continue; } int ddIndx = vlayer->fields().lookupField( ddField ); if ( ddIndx == -1 ) { continue; } QgsDebugMsg( QStringLiteral( "ddField: %1" ).arg( ddField ) ); switch ( key ) { case QgsPalLayerSettings::Show: mShowLabelChkbx->setEnabled( true ); break; case QgsPalLayerSettings::AlwaysShow: mAlwaysShowChkbx->setEnabled( true ); break; case QgsPalLayerSettings::MinimumScale: mMinScaleWidget->setEnabled( true ); break; case QgsPalLayerSettings::MaximumScale: mMaxScaleWidget->setEnabled( true ); break; case QgsPalLayerSettings::BufferSize: mBufferSizeSpinBox->setEnabled( true ); break; case QgsPalLayerSettings::PositionX: mXCoordSpinBox->setEnabled( true ); break; case QgsPalLayerSettings::PositionY: mYCoordSpinBox->setEnabled( true ); break; case QgsPalLayerSettings::LabelDistance: mLabelDistanceSpinBox->setEnabled( true ); break; case QgsPalLayerSettings::Hali: mHaliComboBox->setEnabled( true ); break; case QgsPalLayerSettings::Vali: mValiComboBox->setEnabled( true ); break; case QgsPalLayerSettings::BufferColor: mBufferColorButton->setEnabled( true ); break; case QgsPalLayerSettings::Color: mFontColorButton->setEnabled( true ); break; case QgsPalLayerSettings::LabelRotation: mRotationSpinBox->setEnabled( true ); break; //font related properties case QgsPalLayerSettings::Family: mFontFamilyCmbBx->setEnabled( true ); break; case QgsPalLayerSettings::FontStyle: mFontStyleCmbBx->setEnabled( true ); break; case QgsPalLayerSettings::Underline: mFontUnderlineBtn->setEnabled( true ); break; case QgsPalLayerSettings::Strikeout: mFontStrikethroughBtn->setEnabled( true ); break; case QgsPalLayerSettings::Bold: mFontBoldBtn->setEnabled( true ); break; case QgsPalLayerSettings::Italic: mFontItalicBtn->setEnabled( true ); break; case QgsPalLayerSettings::Size: mFontSizeSpinBox->setEnabled( true ); break; default: break; } } }
QVariantMap QgsJoinWithLinesAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { if ( parameters.value( QStringLiteral( "SPOKES" ) ) == parameters.value( QStringLiteral( "HUBS" ) ) ) throw QgsProcessingException( QObject::tr( "Same layer given for both hubs and spokes" ) ); std::unique_ptr< QgsProcessingFeatureSource > hubSource( parameterAsSource( parameters, QStringLiteral( "HUBS" ), context ) ); if ( !hubSource ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "HUBS" ) ) ); std::unique_ptr< QgsProcessingFeatureSource > spokeSource( parameterAsSource( parameters, QStringLiteral( "SPOKES" ), context ) ); if ( !hubSource || !spokeSource ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "SPOKES" ) ) ); QString fieldHubName = parameterAsString( parameters, QStringLiteral( "HUB_FIELD" ), context ); int fieldHubIndex = hubSource->fields().lookupField( fieldHubName ); const QStringList hubFieldsToCopy = parameterAsFields( parameters, QStringLiteral( "HUB_FIELDS" ), context ); QString fieldSpokeName = parameterAsString( parameters, QStringLiteral( "SPOKE_FIELD" ), context ); int fieldSpokeIndex = spokeSource->fields().lookupField( fieldSpokeName ); const QStringList spokeFieldsToCopy = parameterAsFields( parameters, QStringLiteral( "SPOKE_FIELDS" ), context ); if ( fieldHubIndex < 0 || fieldSpokeIndex < 0 ) throw QgsProcessingException( QObject::tr( "Invalid ID field" ) ); const bool geodesic = parameterAsBool( parameters, QStringLiteral( "GEODESIC" ), context ); const double geodesicDistance = parameterAsDouble( parameters, QStringLiteral( "GEODESIC_DISTANCE" ), context ) * 1000; bool dynamicGeodesicDistance = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "GEODESIC_DISTANCE" ) ); QgsExpressionContext expressionContext = createExpressionContext( parameters, context, hubSource.get() ); QgsProperty geodesicDistanceProperty; if ( dynamicGeodesicDistance ) { geodesicDistanceProperty = parameters.value( QStringLiteral( "GEODESIC_DISTANCE" ) ).value< QgsProperty >(); } const bool splitAntimeridian = parameterAsBool( parameters, QStringLiteral( "ANTIMERIDIAN_SPLIT" ), context ); QgsDistanceArea da; da.setSourceCrs( hubSource->sourceCrs(), context.transformContext() ); da.setEllipsoid( context.project()->ellipsoid() ); QgsFields hubOutFields; QgsAttributeList hubFieldIndices; if ( hubFieldsToCopy.empty() ) { hubOutFields = hubSource->fields(); hubFieldIndices.reserve( hubOutFields.count() ); for ( int i = 0; i < hubOutFields.count(); ++i ) { hubFieldIndices << i; } } else { hubFieldIndices.reserve( hubOutFields.count() ); for ( const QString &field : hubFieldsToCopy ) { int index = hubSource->fields().lookupField( field ); if ( index >= 0 ) { hubFieldIndices << index; hubOutFields.append( hubSource->fields().at( index ) ); } } } QgsAttributeList hubFields2Fetch = hubFieldIndices; hubFields2Fetch << fieldHubIndex; QgsFields spokeOutFields; QgsAttributeList spokeFieldIndices; if ( spokeFieldsToCopy.empty() ) { spokeOutFields = spokeSource->fields(); spokeFieldIndices.reserve( spokeOutFields.count() ); for ( int i = 0; i < spokeOutFields.count(); ++i ) { spokeFieldIndices << i; } } else { for ( const QString &field : spokeFieldsToCopy ) { int index = spokeSource->fields().lookupField( field ); if ( index >= 0 ) { spokeFieldIndices << index; spokeOutFields.append( spokeSource->fields().at( index ) ); } } } QgsAttributeList spokeFields2Fetch = spokeFieldIndices; spokeFields2Fetch << fieldSpokeIndex; QgsFields fields = QgsProcessingUtils::combineFields( hubOutFields, spokeOutFields ); QgsWkbTypes::Type outType = geodesic ? QgsWkbTypes::MultiLineString : QgsWkbTypes::LineString; bool hasZ = false; if ( QgsWkbTypes::hasZ( hubSource->wkbType() ) || QgsWkbTypes::hasZ( spokeSource->wkbType() ) ) { outType = QgsWkbTypes::addZ( outType ); hasZ = true; } bool hasM = false; if ( QgsWkbTypes::hasM( hubSource->wkbType() ) || QgsWkbTypes::hasM( spokeSource->wkbType() ) ) { outType = QgsWkbTypes::addM( outType ); hasM = true; } QString dest; std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, outType, hubSource->sourceCrs(), QgsFeatureSink::RegeneratePrimaryKey ) ); if ( !sink ) throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); auto getPointFromFeature = [hasZ, hasM]( const QgsFeature & feature )->QgsPoint { QgsPoint p; if ( feature.geometry().type() == QgsWkbTypes::PointGeometry && !feature.geometry().isMultipart() ) p = *static_cast< const QgsPoint *>( feature.geometry().constGet() ); else p = *static_cast< const QgsPoint *>( feature.geometry().pointOnSurface().constGet() ); if ( hasZ && !p.is3D() ) p.addZValue( 0 ); if ( hasM && !p.isMeasure() ) p.addMValue( 0 ); return p; }; QgsFeatureIterator hubFeatures = hubSource->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( hubFields2Fetch ), QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks ); double step = hubSource->featureCount() > 0 ? 100.0 / hubSource->featureCount() : 1; int i = 0; QgsFeature hubFeature; while ( hubFeatures.nextFeature( hubFeature ) ) { i++; if ( feedback->isCanceled() ) { break; } feedback->setProgress( i * step ); if ( !hubFeature.hasGeometry() ) continue; QgsPoint hubPoint = getPointFromFeature( hubFeature ); // only keep selected attributes QgsAttributes hubAttributes; for ( int j = 0; j < hubFeature.attributes().count(); ++j ) { if ( !hubFieldIndices.contains( j ) ) continue; hubAttributes << hubFeature.attribute( j ); } QgsFeatureRequest spokeRequest = QgsFeatureRequest().setDestinationCrs( hubSource->sourceCrs(), context.transformContext() ); spokeRequest.setSubsetOfAttributes( spokeFields2Fetch ); spokeRequest.setFilterExpression( QgsExpression::createFieldEqualityExpression( fieldSpokeName, hubFeature.attribute( fieldHubIndex ) ) ); QgsFeatureIterator spokeFeatures = spokeSource->getFeatures( spokeRequest, QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks ); QgsFeature spokeFeature; while ( spokeFeatures.nextFeature( spokeFeature ) ) { if ( feedback->isCanceled() ) { break; } if ( !spokeFeature.hasGeometry() ) continue; QgsPoint spokePoint = getPointFromFeature( spokeFeature ); QgsGeometry line; if ( !geodesic ) { line = QgsGeometry( new QgsLineString( QVector< QgsPoint >() << hubPoint << spokePoint ) ); if ( splitAntimeridian ) line = da.splitGeometryAtAntimeridian( line ); } else { double distance = geodesicDistance; if ( dynamicGeodesicDistance ) { expressionContext.setFeature( hubFeature ); distance = geodesicDistanceProperty.valueAsDouble( expressionContext, distance ); } std::unique_ptr< QgsMultiLineString > ml = qgis::make_unique< QgsMultiLineString >(); std::unique_ptr< QgsLineString > l = qgis::make_unique< QgsLineString >( QVector< QgsPoint >() << hubPoint ); QVector< QVector< QgsPointXY > > points = da.geodesicLine( QgsPointXY( hubPoint ), QgsPointXY( spokePoint ), distance, splitAntimeridian ); QVector< QgsPointXY > points1 = points.at( 0 ); points1.pop_front(); if ( points.count() == 1 ) points1.pop_back(); QgsLineString geodesicPoints( points1 ); l->append( &geodesicPoints ); if ( points.count() == 1 ) l->addVertex( spokePoint ); ml->addGeometry( l.release() ); if ( points.count() > 1 ) { QVector< QgsPointXY > points2 = points.at( 1 ); points2.pop_back(); l = qgis::make_unique< QgsLineString >( points2 ); if ( hasZ ) l->addZValue( std::numeric_limits<double>::quiet_NaN() ); if ( hasM ) l->addMValue( std::numeric_limits<double>::quiet_NaN() ); l->addVertex( spokePoint ); ml->addGeometry( l.release() ); } line = QgsGeometry( std::move( ml ) ); } QgsFeature outFeature; QgsAttributes outAttributes = hubAttributes; // only keep selected attributes QgsAttributes spokeAttributes; for ( int j = 0; j < spokeFeature.attributes().count(); ++j ) { if ( !spokeFieldIndices.contains( j ) ) continue; spokeAttributes << spokeFeature.attribute( j ); } outAttributes.append( spokeAttributes ); outFeature.setAttributes( outAttributes ); outFeature.setGeometry( line ); sink->addFeature( outFeature, QgsFeatureSink::FastInsert ); } } QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), dest ); return outputs; }
QVariantMap QgsBufferAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); if ( !source ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) ); QString dest; std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), QgsWkbTypes::Polygon, source->sourceCrs() ) ); if ( !sink ) throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); // fixed parameters bool dissolve = parameterAsBool( parameters, QStringLiteral( "DISSOLVE" ), context ); int segments = parameterAsInt( parameters, QStringLiteral( "SEGMENTS" ), context ); QgsGeometry::EndCapStyle endCapStyle = static_cast< QgsGeometry::EndCapStyle >( 1 + parameterAsInt( parameters, QStringLiteral( "END_CAP_STYLE" ), context ) ); QgsGeometry::JoinStyle joinStyle = static_cast< QgsGeometry::JoinStyle>( 1 + parameterAsInt( parameters, QStringLiteral( "JOIN_STYLE" ), context ) ); double miterLimit = parameterAsDouble( parameters, QStringLiteral( "MITER_LIMIT" ), context ); double bufferDistance = parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context ); bool dynamicBuffer = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DISTANCE" ) ); QgsExpressionContext expressionContext = createExpressionContext( parameters, context, dynamic_cast< QgsProcessingFeatureSource * >( source.get() ) ); QgsProperty bufferProperty; if ( dynamicBuffer ) { bufferProperty = parameters.value( QStringLiteral( "DISTANCE" ) ).value< QgsProperty >(); } long count = source->featureCount(); QgsFeature f; QgsFeatureIterator it = source->getFeatures(); double step = count > 0 ? 100.0 / count : 1; int current = 0; QVector< QgsGeometry > bufferedGeometriesForDissolve; QgsAttributes dissolveAttrs; while ( it.nextFeature( f ) ) { if ( feedback->isCanceled() ) { break; } if ( dissolveAttrs.isEmpty() ) dissolveAttrs = f.attributes(); QgsFeature out = f; if ( out.hasGeometry() ) { double distance = bufferDistance; if ( dynamicBuffer ) { expressionContext.setFeature( f ); distance = bufferProperty.valueAsDouble( expressionContext, bufferDistance ); } QgsGeometry outputGeometry = f.geometry().buffer( distance, segments, endCapStyle, joinStyle, miterLimit ); if ( !outputGeometry ) { QgsMessageLog::logMessage( QObject::tr( "Error calculating buffer for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), Qgis::Warning ); } if ( dissolve ) bufferedGeometriesForDissolve << outputGeometry; else out.setGeometry( outputGeometry ); } if ( !dissolve ) sink->addFeature( out, QgsFeatureSink::FastInsert ); feedback->setProgress( current * step ); current++; } if ( dissolve ) { QgsGeometry finalGeometry = QgsGeometry::unaryUnion( bufferedGeometriesForDissolve ); QgsFeature f; f.setGeometry( finalGeometry ); f.setAttributes( dissolveAttrs ); sink->addFeature( f, QgsFeatureSink::FastInsert ); } QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), dest ); return outputs; }
QVariantMap QgsTransectAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { Side orientation = static_cast< QgsTransectAlgorithm::Side >( parameterAsInt( parameters, QStringLiteral( "SIDE" ), context ) ); double angle = fabs( parameterAsDouble( parameters, QStringLiteral( "ANGLE" ), context ) ); bool dynamicAngle = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "ANGLE" ) ); QgsProperty angleProperty; if ( dynamicAngle ) angleProperty = parameters.value( QStringLiteral( "ANGLE" ) ).value< QgsProperty >(); double length = parameterAsDouble( parameters, QStringLiteral( "LENGTH" ), context ); bool dynamicLength = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "LENGTH" ) ); QgsProperty lengthProperty; if ( dynamicLength ) lengthProperty = parameters.value( QStringLiteral( "LENGTH" ) ).value< QgsProperty >(); if ( orientation == QgsTransectAlgorithm::Both ) length /= 2.0; std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); if ( !source ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) ); QgsExpressionContext expressionContext = createExpressionContext( parameters, context, dynamic_cast< QgsProcessingFeatureSource * >( source.get() ) ); QgsFields fields = source->fields(); fields.append( QgsField( QStringLiteral( "TR_FID" ), QVariant::Int, QString(), 20 ) ); fields.append( QgsField( QStringLiteral( "TR_ID" ), QVariant::Int, QString(), 20 ) ); fields.append( QgsField( QStringLiteral( "TR_SEGMENT" ), QVariant::Int, QString(), 20 ) ); fields.append( QgsField( QStringLiteral( "TR_ANGLE" ), QVariant::Double, QString(), 5, 2 ) ); fields.append( QgsField( QStringLiteral( "TR_LENGTH" ), QVariant::Double, QString(), 20, 6 ) ); fields.append( QgsField( QStringLiteral( "TR_ORIENT" ), QVariant::Int, QString(), 1 ) ); QgsWkbTypes::Type outputWkb = QgsWkbTypes::LineString; if ( QgsWkbTypes::hasZ( source->wkbType() ) ) outputWkb = QgsWkbTypes::addZ( outputWkb ); if ( QgsWkbTypes::hasM( source->wkbType() ) ) outputWkb = QgsWkbTypes::addM( outputWkb ); QString dest; std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, outputWkb, source->sourceCrs(), QgsFeatureSink::RegeneratePrimaryKey ) ); if ( !sink ) throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); QgsFeatureIterator features = source->getFeatures( ); int current = -1; int number = 0; double step = source->featureCount() > 0 ? 100.0 / source->featureCount() : 1; QgsFeature feat; while ( features.nextFeature( feat ) ) { current++; if ( feedback->isCanceled() ) { break; } feedback->setProgress( current * step ); if ( !feat.hasGeometry() ) continue; QgsGeometry inputGeometry = feat.geometry(); if ( dynamicLength || dynamicAngle ) { expressionContext.setFeature( feat ); } double evaluatedLength = length; if ( dynamicLength ) evaluatedLength = lengthProperty.valueAsDouble( context.expressionContext(), length ); double evaluatedAngle = angle; if ( dynamicAngle ) evaluatedAngle = angleProperty.valueAsDouble( context.expressionContext(), angle ); inputGeometry.convertToMultiType(); const QgsMultiLineString *multiLine = static_cast< const QgsMultiLineString * >( inputGeometry.constGet() ); for ( int id = 0; id < multiLine->numGeometries(); ++id ) { const QgsLineString *line = static_cast< const QgsLineString * >( multiLine->geometryN( id ) ); QgsAbstractGeometry::vertex_iterator it = line->vertices_begin(); while ( it != line->vertices_end() ) { QgsVertexId vertexId = it.vertexId(); int i = vertexId.vertex; QgsFeature outFeat; QgsAttributes attrs = feat.attributes(); attrs << current << number << i + 1 << evaluatedAngle << ( ( orientation == QgsTransectAlgorithm::Both ) ? evaluatedLength * 2 : evaluatedLength ) << orientation; outFeat.setAttributes( attrs ); double angleAtVertex = line->vertexAngle( vertexId ); outFeat.setGeometry( calcTransect( *it, angleAtVertex, evaluatedLength, orientation, evaluatedAngle ) ); sink->addFeature( outFeat, QgsFeatureSink::FastInsert ); number++; it++; } } } QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), dest ); return outputs; }