Index: src/app/qgslabelinggui.h =================================================================== --- src/app/qgslabelinggui.h (Revision 14355) +++ src/app/qgslabelinggui.h (Arbeitskopie) @@ -45,6 +45,11 @@ void updatePreview(); void updateOptions(); + void on_mFontSizeSpinBox_valueChanged( double d ); + void on_mFontSizeUnitComboBox_currentIndexChanged( int index ); + void on_mXCoordinateComboBox_currentIndexChanged( const QString & text ); + void on_mYCoordinateComboBox_currentIndexChanged( const QString & text ); + protected: void populatePlacementMethods(); void populateFieldNames(); @@ -57,6 +62,9 @@ private: QgsPalLabeling* mLBL; QgsVectorLayer* mLayer; + + void disableDataDefinedAlignment(); + void enableDataDefinedAlignment(); }; #endif Index: src/app/qgslabelinggui.cpp =================================================================== --- src/app/qgslabelinggui.cpp (Revision 14355) +++ src/app/qgslabelinggui.cpp (Arbeitskopie) @@ -123,6 +123,7 @@ chkMergeLines->setChecked( lyr.mergeLines ); chkMultiLine->setChecked( lyr.multiLineLabels ); mMinSizeSpinBox->setValue( lyr.minFeatureSize ); + chkAddDirectionSymbol->setChecked( lyr.addDirectionSymbol ); bool scaleBased = ( lyr.scaleMin != 0 && lyr.scaleMax != 0 ); chkScaleBasedVisibility->setChecked( scaleBased ); @@ -139,7 +140,19 @@ btnTextColor->setColor( lyr.textColor ); btnBufferColor->setColor( lyr.bufferColor ); - updateFont( lyr.textFont ); + + if ( lyr.fontSizeInMapUnits ) + { + mFontSizeUnitComboBox->setCurrentIndex( 1 ); + } + else + { + mFontSizeUnitComboBox->setCurrentIndex( 0 ); + } + + QFont textFont = lyr.textFont; + updateFont( textFont ); + mFontSizeSpinBox->setValue( textFont.pointSizeF() ); updateUi(); updateOptions(); @@ -238,8 +251,18 @@ { lyr.bufferSize = 0; } + if ( chkAddDirectionSymbol->isChecked() ) + { + lyr.addDirectionSymbol = true; + } + else + { + lyr.addDirectionSymbol = false; + } lyr.minFeatureSize = mMinSizeSpinBox->value(); + lyr.fontSizeInMapUnits = ( mFontSizeUnitComboBox->currentIndex() == 1 ); + //data defined labeling setDataDefinedProperty( mSizeAttributeComboBox, QgsPalLayerSettings::Size, lyr ); setDataDefinedProperty( mColorAttributeComboBox, QgsPalLayerSettings::Color, lyr ); @@ -250,6 +273,12 @@ 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 ); + setDataDefinedProperty( mLabelDistanceComboBox, QgsPalLayerSettings::LabelDistance, lyr ); + setDataDefinedProperty( mRotationComboBox, QgsPalLayerSettings::Rotation, lyr ); return lyr; } @@ -308,6 +337,12 @@ comboList << mFontFamilyAttributeComboBox; comboList << mBufferSizeAttributeComboBox; comboList << mBufferColorAttributeComboBox; + comboList << mXCoordinateComboBox; + comboList << mYCoordinateComboBox; + comboList << mHorizontalAlignmentComboBox; + comboList << mVerticalAlignmentComboBox; + comboList << mLabelDistanceComboBox; + comboList << mRotationComboBox; QList::iterator comboIt = comboList.begin(); for ( ; comboIt != comboList.end(); ++comboIt ) @@ -335,6 +370,12 @@ 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 ); + setCurrentComboValue( mLabelDistanceComboBox, s, QgsPalLayerSettings::LabelDistance ); + setCurrentComboValue( mRotationComboBox, s, QgsPalLayerSettings::Rotation ); } void QgsLabelingGui::changeTextColor() @@ -352,14 +393,21 @@ bool ok; QFont font = QFontDialog::getFont( &ok, lblFontPreview->font(), this ); if ( ok ) + { updateFont( font ); + } + mFontSizeSpinBox->setValue( font.pointSizeF() ); } void QgsLabelingGui::updateFont( QFont font ) { - lblFontName->setText( QString( "%1, %2 %3" ).arg( font.family() ).arg( font.pointSize() ).arg( tr( "pt" ) ) ); + QString fontSizeUnitString = tr( "pt" ); + if ( mFontSizeUnitComboBox->currentIndex() == 1 ) + { + fontSizeUnitString = tr( "map units" ); + } + lblFontName->setText( QString( "%1, %2 %3" ).arg( font.family() ).arg( font.pointSize() ).arg( fontSizeUnitString ) ); lblFontPreview->setFont( font ); - updatePreview(); } @@ -418,3 +466,57 @@ stackedOptions->setCurrentWidget( pageOptionsEmpty ); } } + +void QgsLabelingGui::on_mFontSizeSpinBox_valueChanged( double d ) +{ + QFont font = lblFontPreview->font(); + font.setPointSizeF( d ); + lblFontPreview->setFont( font ); + updateFont( font ); +} + +void QgsLabelingGui::on_mFontSizeUnitComboBox_currentIndexChanged( int index ) +{ + updateFont( lblFontPreview->font() ); +} + +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 ); + mRotationComboBox->setCurrentIndex( mRotationComboBox->findText( "" ) ); + mRotationComboBox->setEnabled( false ); +} + +void QgsLabelingGui::enableDataDefinedAlignment() +{ + mHorizontalAlignmentComboBox->setEnabled( true ); + mVerticalAlignmentComboBox->setEnabled( true ); + mRotationComboBox->setEnabled( true ); +} Index: src/core/qgspallabeling.cpp =================================================================== --- src/core/qgspallabeling.cpp (Revision 14355) +++ src/core/qgspallabeling.cpp (Arbeitskopie) @@ -132,6 +132,8 @@ minFeatureSize = 0.0; vectorScaleFactor = 1.0; rasterCompressFactor = 1.0; + addDirectionSymbol = false; + fontSizeInMapUnits = false; } QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s ) @@ -156,6 +158,8 @@ minFeatureSize = s.minFeatureSize; vectorScaleFactor = s.vectorScaleFactor; rasterCompressFactor = s.rasterCompressFactor; + addDirectionSymbol = s.addDirectionSymbol; + fontSizeInMapUnits = s.fontSizeInMapUnits; dataDefinedProperties = s.dataDefinedProperties; fontMetrics = NULL; @@ -193,7 +197,7 @@ return; } - for ( int i = 0; i < 9; ++i ) + for ( int i = 0; i < 15; ++i ) { QMap< QgsPalLayerSettings::DataDefinedProperties, int >::const_iterator it = propertyMap.find(( QgsPalLayerSettings::DataDefinedProperties )i ); QVariant propertyValue; @@ -242,6 +246,12 @@ _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 ); + _readDataDefinedProperty( layer, QgsPalLayerSettings::LabelDistance, propertyMap ); + _readDataDefinedProperty( layer, QgsPalLayerSettings::Rotation, propertyMap ); } void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer ) @@ -269,7 +279,9 @@ labelPerPart = layer->customProperty( "labeling/labelPerPart" ).toBool(); mergeLines = layer->customProperty( "labeling/mergeLines" ).toBool(); multiLineLabels = layer->customProperty( "labeling/multiLineLabels" ).toBool(); + addDirectionSymbol = layer->customProperty( "labeling/addDirectionSymbol" ).toBool(); minFeatureSize = layer->customProperty( "labeling/minFeatureSize" ).toDouble(); + fontSizeInMapUnits = layer->customProperty( "labeling/fontSizeInMapUnits" ).toBool(); _readDataDefinedPropertyMap( layer, dataDefinedProperties ); } @@ -299,7 +311,9 @@ layer->setCustomProperty( "labeling/labelPerPart", labelPerPart ); layer->setCustomProperty( "labeling/mergeLines", mergeLines ); layer->setCustomProperty( "labeling/multiLineLabels", multiLineLabels ); + layer->setCustomProperty( "labeling/addDirectionSymbol", addDirectionSymbol ); layer->setCustomProperty( "labeling/minFeatureSize", minFeatureSize ); + layer->setCustomProperty( "labeling/fontSizeInMapUnits", fontSizeInMapUnits ); _writeDataDefinedPropertyMap( layer, dataDefinedProperties ); } @@ -358,6 +372,10 @@ return; } + if ( addDirectionSymbol && !multiLineLabels && placement == QgsPalLayerSettings::Line ) //consider the space needed for the direction symbol + { + text.append( ">" ); + } QRectF labelRect = fm->boundingRect( text ); double w, h; if ( !multiLineLabels ) @@ -391,12 +409,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() ) @@ -406,7 +424,7 @@ { return; } - labelFont.setPointSize( sizeToPixel( sizeDouble, context ) ); + labelFont.setPixelSize( sizeToPixel( sizeDouble, context ) ); } QFontMetrics labelFontMetrics( labelFont ); calculateLabelSize( &labelFontMetrics, labelText, labelX, labelY ); @@ -430,6 +448,88 @@ return; } + //data defined position / alignment / rotation? + bool dataDefinedPosition = false; + bool dataDefinedRotation = false; + double xPos, yPos, angle; + + 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(); + + //x/y shift in case of alignment + double xdiff = 0; + double ydiff = 0; + + //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 ) + { + xdiff -= labelX / 2.0; + } + else if ( haliString.compare( "Right", Qt::CaseInsensitive ) == 0 ) + { + xdiff -= 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 ) + { + ydiff -= labelY; + } + else + { + QFontMetrics labelFontMetrics( labelFont ); + double descentRatio = labelFontMetrics.descent() / labelFontMetrics.height(); + + if ( valiString.compare( "Base", Qt::CaseInsensitive ) == 0 ) + { + ydiff -= labelY * descentRatio; + } + else if ( valiString.compare( "Half", Qt::CaseInsensitive ) == 0 ) + { + ydiff -= labelY * descentRatio; + ydiff -= labelY * 0.5 * ( 1 - descentRatio ); + } + } + } + } + + //data defined rotation? + QMap< DataDefinedProperties, int >::const_iterator rotIt = dataDefinedProperties.find( QgsPalLayerSettings::Rotation ); + if ( rotIt != dataDefinedProperties.constEnd() ) + { + dataDefinedRotation = true; + angle = f.attributeMap().value( *rotIt ).toDouble() * M_PI / 180; + //adjust xdiff and ydiff because the hali/vali point needs to be the rotation center + double xd = xdiff * cos( angle ) - ydiff * sin( angle ); + double yd = xdiff * sin( angle ) + ydiff * cos( angle ); + xdiff = xd; + ydiff = yd; + } + + yPos += ydiff; + xPos += xdiff; + } + } + QgsPalGeometry* lbl = new QgsPalGeometry( f.id(), labelText, GEOSGeom_clone( geos_geom ) ); // record the created geometry - it will be deleted at the end. @@ -438,7 +538,8 @@ // 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, angle, dataDefinedRotation ) ) return; } catch ( std::exception* e ) @@ -452,9 +553,20 @@ feat->setLabelInfo( lbl->info( fontMetrics, xform, rasterCompressFactor ) ); // TODO: allow layer-wide feature dist in PAL...? - if ( dist != 0 ) - feat->setDistLabel( fabs( ptOne.x() - ptZero.x() )* dist * vectorScaleFactor ); + //data defined label-feature distance? + double distance = dist; + QMap< DataDefinedProperties, int >::const_iterator dDistIt = dataDefinedProperties.find( QgsPalLayerSettings::LabelDistance ); + if ( dDistIt != dataDefinedProperties.constEnd() ) + { + distance = f.attributeMap().value( *dDistIt ).toDouble(); + } + + if ( distance != 0 ) + { + feat->setDistLabel( fabs( ptOne.x() - ptZero.x() )* distance * vectorScaleFactor ); + } + //add parameters for data defined labeling to QgsPalGeometry QMap< DataDefinedProperties, int >::const_iterator dIt = dataDefinedProperties.constBegin(); for ( ; dIt != dataDefinedProperties.constEnd(); ++dIt ) @@ -465,9 +577,17 @@ int QgsPalLayerSettings::sizeToPixel( double size, const QgsRenderContext& c ) const { - // set font size from points to output size - double pixelSize = 0.3527 * size * c.scaleFactor() * c.rasterScaleFactor() + 0.5; - return ( int )pixelSize; + double pixelSize; + if ( fontSizeInMapUnits ) + { + pixelSize = size / c.mapToPixel().mapUnitsPerPixel() * c.rasterScaleFactor(); + } + else //font size in points + { + // set font size from points to output size + pixelSize = 0.3527 * size * c.scaleFactor() * c.rasterScaleFactor(); + } + return ( int )( pixelSize + 0.5 ); } @@ -730,7 +850,7 @@ QVariant dataDefinedSize = palGeometry->dataDefinedValues().value( QgsPalLayerSettings::Size ); if ( dataDefinedSize.isValid() ) { - fontForLabel.setPointSize( lyr.sizeToPixel( dataDefinedSize.toDouble(), context ) ); + fontForLabel.setPixelSize( lyr.sizeToPixel( dataDefinedSize.toDouble(), context ) ); } //font color QVariant dataDefinedColor = palGeometry->dataDefinedValues().value( QgsPalLayerSettings::Color ); @@ -871,6 +991,20 @@ QString text = (( QgsPalGeometry* )label->getFeaturePart()->getUserGeometry() )->text(); QString txt = ( label->getPartId() == -1 ? text : QString( text[label->getPartId()] ) ); + //add the direction symbol if needed + if ( !txt.isEmpty() && lyr.placement == QgsPalLayerSettings::Line && + lyr.addDirectionSymbol && !lyr.multiLineLabels ) + { + if ( label->getReversed() ) + { + txt.prepend( "<" ); + } + else + { + txt.append( ">" ); + } + } + //QgsDebugMsg( "drawLabel " + QString::number( drawBuffer ) + " " + txt ); QStringList multiLineList; @@ -913,7 +1047,7 @@ painter->restore(); if ( label->getNextPart() ) - drawLabel( label->getNextPart(), painter, f, c, xform, drawBuffer ); + drawLabel( label->getNextPart(), painter, f, c, xform, bufferSize, bufferColor, drawBuffer ); } } Index: src/core/pal/feature.h =================================================================== --- src/core/pal/feature.h (Revision 14355) +++ src/core/pal/feature.h (Arbeitskopie) @@ -86,6 +86,11 @@ 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; } + //Set label rotation to fixed value + void setFixedAngle( double a ) { fixedRotation = true; fixedAngle = a; } protected: Layer *layer; @@ -97,6 +102,13 @@ char *uid; + bool fixedPos; //true in case of fixed position (only 1 candidate position with cost 0) + double fixedPosX; + double fixedPosY; + //Fixed (e.g. data defined) angle only makes sense together with fixed position + bool fixedRotation; + double fixedAngle; //fixed angle value (in rad) + // array of parts - possibly not necessary //int nPart; //FeaturePart** parts; Index: src/core/pal/labelposition.cpp =================================================================== --- src/core/pal/labelposition.cpp (Revision 14355) +++ src/core/pal/labelposition.cpp (Arbeitskopie) @@ -54,8 +54,8 @@ namespace pal { - LabelPosition::LabelPosition( int id, double x1, double y1, double w, double h, double alpha, double cost, FeaturePart *feature ) - : id( id ), cost( cost ), feature( feature ), nbOverlap( 0 ), alpha( alpha ), w( w ), h( h ), nextPart( NULL ), partId( -1 ) + LabelPosition::LabelPosition( int id, double x1, double y1, double w, double h, double alpha, double cost, FeaturePart *feature, bool isReversed ) + : id( id ), cost( cost ), feature( feature ), nbOverlap( 0 ), alpha( alpha ), w( w ), h( h ), nextPart( NULL ), partId( -1 ), reversed( isReversed ) { // alpha take his value bw 0 and 2*pi rad Index: src/core/pal/labelposition.h =================================================================== --- src/core/pal/labelposition.h (Revision 14355) +++ src/core/pal/labelposition.h (Arbeitskopie) @@ -74,6 +74,11 @@ LabelPosition* nextPart; int partId; + //True if label direction is the same as line / polygon ring direction. + //Could be used by the application to draw a directional arrow ('<' or '>') + //if the layer arrangement is P_LINE + bool reversed; + bool isInConflictSinglePart( LabelPosition* lp ); bool isInConflictMultiPart( LabelPosition* lp ); @@ -93,7 +98,7 @@ LabelPosition( int id, double x1, double y1, double w, double h, double alpha, double cost, - FeaturePart *feature ); + FeaturePart *feature, bool isReversed = false ); /** copy constructor */ LabelPosition( const LabelPosition& other ); @@ -190,6 +195,7 @@ * \return alpha to rotate text (in rad) */ double getAlpha() const; + bool getReversed() const { return reversed; } void print(); Index: src/core/pal/layer.cpp =================================================================== --- src/core/pal/layer.cpp (Revision 14355) +++ 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, double angle, bool fixedAngle ) { if ( !geom_id || label_x < 0 || label_y < 0 ) return false; @@ -245,6 +246,14 @@ GEOSGeometry *the_geom = userGeom->getGeosGeometry(); Feature* f = new Feature( this, geom_id, userGeom, label_x, label_y ); + if ( fixedPos ) + { + f->setFixedPosition( labelPosX, labelPosY ); + } + if ( fixedAngle ) + { + f->setFixedAngle( angle ); + } bool first_feat = true; @@ -316,7 +325,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 14355) +++ 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, double angle = 0.0, bool fixedAngle = 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 14355) +++ 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 ), fixedRotation( false ) { uid = new char[strlen( geom_id ) +1]; strcpy( uid, geom_id ); @@ -599,11 +599,11 @@ reversed = ( alpha >= M_PI / 2 || alpha < -M_PI / 2 ); if (( !reversed && ( flags & FLAG_ABOVE_LINE ) ) || ( reversed && ( flags & FLAG_BELOW_LINE ) ) ) - positions->push_back( new LabelPosition( i, bx + cos( beta ) *distlabel , by + sin( beta ) *distlabel, xrm, yrm, alpha, cost, this ) ); // Line + positions->push_back( new LabelPosition( i, bx + cos( beta ) *distlabel , by + sin( beta ) *distlabel, xrm, yrm, alpha, cost, this, reversed ) ); // Line if (( !reversed && ( flags & FLAG_BELOW_LINE ) ) || ( reversed && ( flags & FLAG_ABOVE_LINE ) ) ) - positions->push_back( new LabelPosition( i, bx - cos( beta ) *( distlabel + yrm ) , by - sin( beta ) *( distlabel + yrm ), xrm, yrm, alpha, cost, this ) ); // Line + positions->push_back( new LabelPosition( i, bx - cos( beta ) *( distlabel + yrm ) , by - sin( beta ) *( distlabel + yrm ), xrm, yrm, alpha, cost, this, reversed ) ); // Line if ( flags & FLAG_ON_LINE ) - positions->push_back( new LabelPosition( i, bx - yrm*cos( beta ) / 2, by - yrm*sin( beta ) / 2, xrm, yrm, alpha, cost, this ) ); // Line + positions->push_back( new LabelPosition( i, bx - yrm*cos( beta ) / 2, by - yrm*sin( beta ) / 2, xrm, yrm, alpha, cost, this, reversed ) ); // Line } else if ( f->layer->arrangement == P_HORIZ ) { @@ -1245,40 +1245,54 @@ 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]; + double angle = 0.0; + if ( f->fixedRotation ) + { + angle = f->fixedAngle; + } + ( *lPos )[0] = new LabelPosition( 0, f->fixedPosX, f->fixedPosY, f->label_x, f->label_y, angle, 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 14355) +++ src/core/qgspallabeling.h (Arbeitskopie) @@ -83,6 +83,12 @@ 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) + LabelDistance, + Rotation //data defined rotation (only usefull in connection with data defined position) }; QString fieldName; @@ -103,6 +109,10 @@ bool mergeLines; bool multiLineLabels; //draw labels on multiple lines if they contain '\n' double minFeatureSize; // minimum feature size to be labelled (in mm) + // Adds '<' or '>' to the label string pointing to the direction of the line / polygon ring + // Works only if Placement == Line + bool addDirectionSymbol; + bool fontSizeInMapUnits; //true if font size is in map units (otherwise in points) // called from register feature hook void calculateLabelSize( const QFontMetrics* fm, QString text, double& labelX, double& labelY ); @@ -130,7 +140,7 @@ /**Stores field indices for data defined layer properties*/ QMap< DataDefinedProperties, int > dataDefinedProperties; - /**Calculates pixel size (considering scale factors and oversampling) + /**Calculates pixel size (considering output size should be in pixel or map units, scale factors and oversampling) @param size size to convert @param c rendercontext @return font pixel size*/ Index: src/ui/qgslabelingguibase.ui =================================================================== --- src/ui/qgslabelingguibase.ui (Revision 14355) +++ src/ui/qgslabelingguibase.ui (Arbeitskopie) @@ -6,8 +6,8 @@ 0 0 - 496 - 659 + 504 + 686 @@ -396,7 +396,7 @@ - + @@ -412,7 +412,7 @@ - + @@ -445,7 +445,7 @@ - + Buffer @@ -455,7 +455,7 @@ - + @@ -512,7 +512,7 @@ - + @@ -528,8 +528,14 @@ - + + + + 0 + 0 + + 30 @@ -544,13 +550,45 @@ - + Qt::Horizontal + + + + Font size + + + + + + + + + 999999999.000000000000000 + + + + + + + + In points + + + + + In map units + + + + + + @@ -678,7 +716,7 @@ - + @@ -696,7 +734,7 @@ - + @@ -733,13 +771,20 @@ + + + + add direction symbol + + + Data defined settings - + @@ -753,79 +798,75 @@ - - - - - Size - - - - - - - - - - Bold - - - - - - - - - - - - - Color - - - - - - - - - - Italic - - - - - - - - - - Underline - - - - - - - - - - Font family - - - - - - - - - - Strikeout - - - - + + + Size + + + + + + + + + Color + + + + + + + + + + Bold + + + + + + + + + + Italic + + + + + + + + + + Underline + + + + + + + + + + Strikeout + + + + + + + + + + Font family + + + + + + @@ -834,35 +875,100 @@ Buffer properties - + - - - - - Buffer size - - - - - - - - - - Buffer color - - - - - - - + + + Buffer size + + + + + + + + + Buffer color + + + + + + + + + Position + + + + + + X Coordinate + + + + + + + + + + Y Coordinate + + + + + + + + + + Horizontal alignment + + + + + + + + + + Vertical alignment + + + + + + + + + + + + + Rotation + + + + + + + + + + Label distance + + + + + + + Qt::Vertical