Index: src/app/qgslabelinggui.h =================================================================== --- src/app/qgslabelinggui.h (Revision 14215) +++ src/app/qgslabelinggui.h (Arbeitskopie) @@ -45,6 +45,9 @@ void updatePreview(); void updateOptions(); + void on_mXCoordinateComboBox_currentIndexChanged( const QString & text ); + void on_mYCoordinateComboBox_currentIndexChanged( const QString & text ); + protected: void populatePlacementMethods(); void populateFieldNames(); @@ -57,6 +60,9 @@ private: QgsPalLabeling* mLBL; QgsVectorLayer* mLayer; + + void disableDataDefinedAlignment(); + void enableDataDefinedAlignment(); }; #endif Index: src/app/qgslabelinggui.cpp =================================================================== --- src/app/qgslabelinggui.cpp (Revision 14215) +++ src/app/qgslabelinggui.cpp (Arbeitskopie) @@ -250,6 +250,10 @@ setDataDefinedProperty( mFontFamilyAttributeComboBox, QgsPalLayerSettings::Family, lyr ); setDataDefinedProperty( mBufferSizeAttributeComboBox, QgsPalLayerSettings:: BufferSize, lyr ); setDataDefinedProperty( mBufferColorAttributeComboBox, QgsPalLayerSettings::BufferColor, lyr ); + setDataDefinedProperty( mXCoordinateComboBox, QgsPalLayerSettings::PositionX, lyr ); + setDataDefinedProperty( mYCoordinateComboBox, QgsPalLayerSettings::PositionY, lyr ); + setDataDefinedProperty( mHorizontalAlignmentComboBox, QgsPalLayerSettings::Hali, lyr ); + setDataDefinedProperty( mVerticalAlignmentComboBox, QgsPalLayerSettings::Vali, lyr ); return lyr; } @@ -308,6 +312,10 @@ comboList << mFontFamilyAttributeComboBox; comboList << mBufferSizeAttributeComboBox; comboList << mBufferColorAttributeComboBox; + comboList << mXCoordinateComboBox; + comboList << mYCoordinateComboBox; + comboList << mHorizontalAlignmentComboBox; + comboList << mVerticalAlignmentComboBox; QList::iterator comboIt = comboList.begin(); for ( ; comboIt != comboList.end(); ++comboIt ) @@ -335,6 +343,10 @@ setCurrentComboValue( mFontFamilyAttributeComboBox, s, QgsPalLayerSettings::Family ); setCurrentComboValue( mBufferSizeAttributeComboBox, s , QgsPalLayerSettings::BufferSize ); setCurrentComboValue( mBufferColorAttributeComboBox, s, QgsPalLayerSettings::BufferColor ); + setCurrentComboValue( mXCoordinateComboBox, s, QgsPalLayerSettings::PositionX ); + setCurrentComboValue( mYCoordinateComboBox, s, QgsPalLayerSettings::PositionY ); + setCurrentComboValue( mHorizontalAlignmentComboBox, s, QgsPalLayerSettings::Hali ); + setCurrentComboValue( mVerticalAlignmentComboBox, s, QgsPalLayerSettings::Vali ); } void QgsLabelingGui::changeTextColor() @@ -418,3 +430,41 @@ stackedOptions->setCurrentWidget( pageOptionsEmpty ); } } + +void QgsLabelingGui::on_mXCoordinateComboBox_currentIndexChanged( const QString & text ) +{ + if ( text.isEmpty() ) //no data defined alignment without data defined position + { + disableDataDefinedAlignment(); + } + else if ( !mYCoordinateComboBox->currentText().isEmpty() ) + { + enableDataDefinedAlignment(); + } +} + +void QgsLabelingGui::on_mYCoordinateComboBox_currentIndexChanged( const QString & text ) +{ + if ( text.isEmpty() ) //no data defined alignment without data defined position + { + disableDataDefinedAlignment(); + } + else if ( !mXCoordinateComboBox->currentText().isEmpty() ) + { + enableDataDefinedAlignment(); + } +} + +void QgsLabelingGui::disableDataDefinedAlignment() +{ + mHorizontalAlignmentComboBox->setCurrentIndex( mHorizontalAlignmentComboBox->findText( "" ) ); + mHorizontalAlignmentComboBox->setEnabled( false ); + mVerticalAlignmentComboBox->setCurrentIndex( mVerticalAlignmentComboBox->findText( "" ) ); + mVerticalAlignmentComboBox->setEnabled( false ); +} + +void QgsLabelingGui::enableDataDefinedAlignment() +{ + mHorizontalAlignmentComboBox->setEnabled( true ); + mVerticalAlignmentComboBox->setEnabled( true ); +} Index: src/core/qgspallabeling.cpp =================================================================== --- src/core/qgspallabeling.cpp (Revision 14215) +++ src/core/qgspallabeling.cpp (Arbeitskopie) @@ -193,7 +193,7 @@ return; } - for ( int i = 0; i < 9; ++i ) + for ( int i = 0; i < 13; ++i ) { QMap< QgsPalLayerSettings::DataDefinedProperties, int >::const_iterator it = propertyMap.find(( QgsPalLayerSettings::DataDefinedProperties )i ); QVariant propertyValue; @@ -242,6 +242,10 @@ _readDataDefinedProperty( layer, QgsPalLayerSettings::Family, propertyMap ); _readDataDefinedProperty( layer, QgsPalLayerSettings::BufferSize, propertyMap ); _readDataDefinedProperty( layer, QgsPalLayerSettings::BufferColor, propertyMap ); + _readDataDefinedProperty( layer, QgsPalLayerSettings::PositionX, propertyMap ); + _readDataDefinedProperty( layer, QgsPalLayerSettings::PositionY, propertyMap ); + _readDataDefinedProperty( layer, QgsPalLayerSettings::Hali, propertyMap ); + _readDataDefinedProperty( layer, QgsPalLayerSettings::Vali, propertyMap ); } void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer ) @@ -391,12 +395,12 @@ { QString labelText = f.attributeMap()[fieldIndex].toString(); double labelX, labelY; // will receive label size + QFont labelFont = textFont; //data defined label size? QMap< DataDefinedProperties, int >::const_iterator it = dataDefinedProperties.find( QgsPalLayerSettings::Size ); if ( it != dataDefinedProperties.constEnd() ) { - QFont labelFont = textFont; //find out size QVariant size = f.attributeMap().value( *it ); if ( size.isValid() ) @@ -430,6 +434,69 @@ return; } + //data defined position / alignment? + bool dataDefinedPosition = false; + double xPos, yPos; + + QMap< DataDefinedProperties, int >::const_iterator dPosXIt = dataDefinedProperties.find( QgsPalLayerSettings::PositionX ); + if ( dPosXIt != dataDefinedProperties.constEnd() ) + { + QMap< DataDefinedProperties, int >::const_iterator dPosYIt = dataDefinedProperties.find( QgsPalLayerSettings::PositionY ); + if ( dPosYIt != dataDefinedProperties.constEnd() ) + { + //data defined position + dataDefinedPosition = true; + xPos = f.attributeMap().value( *dPosXIt ).toDouble(); + yPos = f.attributeMap().value( *dPosYIt ).toDouble(); + + //consider alignment settings (by adjusting xPos and yPos, which are lower/left in pal) + + //horizontal alignment + QMap< DataDefinedProperties, int >::const_iterator haliIt = dataDefinedProperties.find( QgsPalLayerSettings::Hali ); + if ( haliIt != dataDefinedProperties.end() ) + { + QString haliString = f.attributeMap().value( *haliIt ).toString(); + if ( haliString.compare( "Center", Qt::CaseInsensitive ) == 0 ) + { + xPos -= labelX / 2.0; + } + else if ( haliString.compare( "Right", Qt::CaseInsensitive ) == 0 ) + { + xPos -= labelX; + } + } + + //vertical alignment + QMap< DataDefinedProperties, int >::const_iterator valiIt = dataDefinedProperties.find( QgsPalLayerSettings::Vali ); + if ( valiIt != dataDefinedProperties.constEnd() ) + { + QString valiString = f.attributeMap().value( *valiIt ).toString(); + if ( valiString.compare( "Bottom", Qt::CaseInsensitive ) != 0 ) + { + if ( valiString.compare( "Top", Qt::CaseInsensitive ) == 0 || valiString.compare( "Cap", Qt::CaseInsensitive ) == 0 ) + { + yPos -= labelY; + } + else + { + QFontMetrics labelFontMetrics( labelFont ); + double descentRatio = labelFontMetrics.descent() / labelFontMetrics.height(); + + if ( valiString.compare( "Base", Qt::CaseInsensitive ) == 0 ) + { + yPos -= labelY * descentRatio; + } + else if ( valiString.compare( "Half", Qt::CaseInsensitive ) == 0 ) + { + yPos -= labelY * descentRatio; + yPos -= labelY * 0.5 * ( 1 - descentRatio ); + } + } + } + } + } + } + QgsPalGeometry* lbl = new QgsPalGeometry( f.id(), labelText, GEOSGeom_clone( geos_geom ) ); // record the created geometry - it will be deleted at the end. @@ -438,7 +505,7 @@ // register feature to the layer try { - if ( !palLayer->registerFeature( lbl->strId(), lbl, labelX, labelY, labelText.toUtf8().constData() ) ) + if ( !palLayer->registerFeature( lbl->strId(), lbl, labelX, labelY, labelText.toUtf8().constData(), xPos, yPos, dataDefinedPosition ) ) return; } catch ( std::exception* e ) Index: src/core/pal/feature.h =================================================================== --- src/core/pal/feature.h (Revision 14215) +++ src/core/pal/feature.h (Arbeitskopie) @@ -86,6 +86,9 @@ void setLabelInfo( LabelInfo* info ) { labelInfo = info; } void setDistLabel( double dist ) { distlabel = dist; } + //Set label position of the feature to fixed x/y values + void setFixedPosition( double x, double y ) { fixedPos = true; fixedPosX = x; fixedPosY = y;} + bool fixedPosition() const { return fixedPos; } protected: Layer *layer; @@ -97,6 +100,10 @@ char *uid; + bool fixedPos; //true in case of fixed position (only 1 candidate position with cost 0) + double fixedPosX; + double fixedPosY; + // array of parts - possibly not necessary //int nPart; //FeaturePart** parts; Index: src/core/pal/layer.cpp =================================================================== --- src/core/pal/layer.cpp (Revision 14215) +++ src/core/pal/layer.cpp (Arbeitskopie) @@ -226,7 +226,8 @@ - bool Layer::registerFeature( const char *geom_id, PalGeometry *userGeom, double label_x, double label_y, const char* labelText ) + bool Layer::registerFeature( const char *geom_id, PalGeometry *userGeom, double label_x, double label_y, const char* labelText, + double labelPosX, double labelPosY, bool fixedPos ) { if ( !geom_id || label_x < 0 || label_y < 0 ) return false; @@ -243,6 +244,10 @@ GEOSGeometry *the_geom = userGeom->getGeosGeometry(); Feature* f = new Feature( this, geom_id, userGeom, label_x, label_y ); + if ( fixedPos ) + { + f->setFixedPosition( labelPosX, labelPosY ); + } bool first_feat = true; @@ -314,7 +319,7 @@ modMutex->unlock(); // if using only biggest parts... - if ( mode == LabelPerFeature && biggest_part != NULL ) + if (( mode == LabelPerFeature || f->fixedPosition() ) && biggest_part != NULL ) { addFeaturePart( biggest_part, labelText ); first_feat = false; Index: src/core/pal/layer.h =================================================================== --- src/core/pal/layer.h (Revision 14215) +++ src/core/pal/layer.h (Arbeitskopie) @@ -283,12 +283,16 @@ * @param label_x label width * @param label_y label height * @param userGeom user's geometry that implements the PalGeometry interface + * @param labelPosX x position of the label (in case of fixed label position) + * @param labelPosY y position of the label (in case of fixed label position) + * @param fixedPos true if a single fixed position for this label is needed * * @throws PalException::FeatureExists * * @return true on success (i.e. valid geometry) */ - bool registerFeature( const char *geom_id, PalGeometry *userGeom, double label_x = -1, double label_y = -1, const char* labelText = NULL ); + bool registerFeature( const char *geom_id, PalGeometry *userGeom, double label_x = -1, double label_y = -1, + const char* labelText = NULL, double labelPosX = 0.0, double labelPosY = 0.0, bool fixedPos = false ); /** return pointer to feature or NULL if doesn't exist */ Feature* getFeature( const char* geom_id ); Index: src/core/pal/feature.cpp =================================================================== --- src/core/pal/feature.cpp (Revision 14215) +++ src/core/pal/feature.cpp (Arbeitskopie) @@ -61,7 +61,7 @@ namespace pal { Feature::Feature( Layer* l, const char* geom_id, PalGeometry* userG, double lx, double ly ) - : layer( l ), userGeom( userG ), label_x( lx ), label_y( ly ), distlabel( 0 ), labelInfo( NULL ) + : layer( l ), userGeom( userG ), label_x( lx ), label_y( ly ), distlabel( 0 ), labelInfo( NULL ), fixedPos( false ) { uid = new char[strlen( geom_id ) +1]; strcpy( uid, geom_id ); @@ -1245,40 +1245,49 @@ double delta = bbox_max[0] - bbox_min[0]; - switch ( type ) + if ( f->fixedPosition() ) { - case GEOS_POINT: - if ( f->layer->getArrangement() == P_POINT_OVER ) - nbp = setPositionOverPoint( x[0], y[0], scale, lPos, delta ); - else - nbp = setPositionForPoint( x[0], y[0], scale, lPos, delta ); - break; - case GEOS_LINESTRING: - if ( f->layer->getArrangement() == P_CURVED ) - nbp = setPositionForLineCurved( lPos, mapShape ); - else - nbp = setPositionForLine( scale, lPos, mapShape, delta ); - break; + nbp = 1; + *lPos = new LabelPosition *[nbp]; + ( *lPos )[0] = new LabelPosition( 0, f->fixedPosX, f->fixedPosY, f->label_x, f->label_y, 0, 0.0, this ); + } + else + { + switch ( type ) + { + case GEOS_POINT: + if ( f->layer->getArrangement() == P_POINT_OVER ) + nbp = setPositionOverPoint( x[0], y[0], scale, lPos, delta ); + else + nbp = setPositionForPoint( x[0], y[0], scale, lPos, delta ); + break; + case GEOS_LINESTRING: + if ( f->layer->getArrangement() == P_CURVED ) + nbp = setPositionForLineCurved( lPos, mapShape ); + else + nbp = setPositionForLine( scale, lPos, mapShape, delta ); + break; - case GEOS_POLYGON: - switch ( f->layer->getArrangement() ) - { - case P_POINT: - case P_POINT_OVER: - double cx, cy; - mapShape->getCentroid( cx, cy ); - if ( f->layer->getArrangement() == P_POINT_OVER ) - nbp = setPositionOverPoint( cx, cy, scale, lPos, delta ); - else - nbp = setPositionForPoint( cx, cy, scale, lPos, delta ); - break; - case P_LINE: - nbp = setPositionForLine( scale, lPos, mapShape, delta ); - break; - default: - nbp = setPositionForPolygon( scale, lPos, mapShape, delta ); - break; - } + case GEOS_POLYGON: + switch ( f->layer->getArrangement() ) + { + case P_POINT: + case P_POINT_OVER: + double cx, cy; + mapShape->getCentroid( cx, cy ); + if ( f->layer->getArrangement() == P_POINT_OVER ) + nbp = setPositionOverPoint( cx, cy, scale, lPos, delta ); + else + nbp = setPositionForPoint( cx, cy, scale, lPos, delta ); + break; + case P_LINE: + nbp = setPositionForLine( scale, lPos, mapShape, delta ); + break; + default: + nbp = setPositionForPolygon( scale, lPos, mapShape, delta ); + break; + } + } } int rnbp = nbp; Index: src/core/qgspallabeling.h =================================================================== --- src/core/qgspallabeling.h (Revision 14215) +++ src/core/qgspallabeling.h (Arbeitskopie) @@ -83,6 +83,10 @@ Family, BufferSize, BufferColor, + PositionX, //x-coordinate data defined label position + PositionY, //y-coordinate data defined label position + Hali, //horizontal alignment for data defined label position (Left, Center, Right) + Vali //vertical alignment for data defined label position (Bottom, Base, Half, Cap, Top) }; QString fieldName; Index: src/ui/qgslabelingguibase.ui =================================================================== --- src/ui/qgslabelingguibase.ui (Revision 14215) +++ src/ui/qgslabelingguibase.ui (Arbeitskopie) @@ -739,7 +739,7 @@ Data defined settings - + @@ -753,79 +753,75 @@ - - - - - Size - - - - - - - - - - Bold - - - - - - - - - - - - - Color - - - - - - - - - - Italic - - - - - - - - - - Underline - - - - - - - - - - Font family - - - - - - - - - - Strikeout - - - - + + + Size + + + + + + + + + Color + + + + + + + + + + Bold + + + + + + + + + + Italic + + + + + + + + + + Underline + + + + + + + + + + Strikeout + + + + + + + + + + Font family + + + + + + @@ -834,35 +830,80 @@ Buffer properties - + - - - - - Buffer size - - - - - - - - - - Buffer color - - - - - - - + + + Buffer size + + + + + + + + + Buffer color + + + + + + + + + Position + + + + + + X Coordinate + + + + + + + + + + Y Coordinate + + + + + + + + + + Horizontal alignment + + + + + + + + + + Vertical alignment + + + + + + + + + + Qt::Vertical