[FEATURE] Data defined label position in new labeling - from Marco Hugentobler.

git-svn-id: http://svn.osgeo.org/qgis/trunk@14423 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
wonder 2010-10-20 20:23:52 +00:00
parent 72c9cdb583
commit ed56bf2e79
11 changed files with 569 additions and 164 deletions

View File

@ -123,6 +123,7 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QWid
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 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QWid
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,7 +251,17 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
{
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 );
@ -250,6 +273,12 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
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 @@ void QgsLabelingGui::populateDataDefinedCombos( QgsPalLayerSettings& s )
comboList << mFontFamilyAttributeComboBox;
comboList << mBufferSizeAttributeComboBox;
comboList << mBufferColorAttributeComboBox;
comboList << mXCoordinateComboBox;
comboList << mYCoordinateComboBox;
comboList << mHorizontalAlignmentComboBox;
comboList << mVerticalAlignmentComboBox;
comboList << mLabelDistanceComboBox;
comboList << mRotationComboBox;
QList<QComboBox*>::iterator comboIt = comboList.begin();
for ( ; comboIt != comboList.end(); ++comboIt )
@ -335,6 +370,12 @@ void QgsLabelingGui::populateDataDefinedCombos( QgsPalLayerSettings& s )
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 @@ void QgsLabelingGui::changeTextFont()
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 @@ void QgsLabelingGui::updateOptions()
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 );
}

View File

@ -45,6 +45,11 @@ class QgsLabelingGui : public QDialog, private Ui::QgsLabelingGuiBase
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 @@ class QgsLabelingGui : public QDialog, private Ui::QgsLabelingGuiBase
private:
QgsPalLabeling* mLBL;
QgsVectorLayer* mLayer;
void disableDataDefinedAlignment();
void enableDataDefinedAlignment();
};
#endif

View File

@ -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 @@ namespace pal
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 @@ namespace pal
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;
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 = 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;
default:
nbp = setPositionForPolygon( scale, lPos, mapShape, delta );
break;
}
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;

View File

@ -86,6 +86,11 @@ namespace pal
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 @@ namespace pal
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;

View File

@ -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

View File

@ -74,6 +74,11 @@ namespace pal
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 @@ namespace pal
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 @@ namespace pal
* \return alpha to rotate text (in rad)
*/
double getAlpha() const;
bool getReversed() const { return reversed; }
void print();

View File

@ -226,7 +226,8 @@ namespace pal
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 @@ namespace pal
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 @@ namespace pal
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;

View File

@ -283,12 +283,16 @@ namespace pal
* @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 );

View File

@ -132,6 +132,8 @@ QgsPalLayerSettings::QgsPalLayerSettings()
minFeatureSize = 0.0;
vectorScaleFactor = 1.0;
rasterCompressFactor = 1.0;
addDirectionSymbol = false;
fontSizeInMapUnits = false;
}
QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s )
@ -156,6 +158,8 @@ QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s )
minFeatureSize = s.minFeatureSize;
vectorScaleFactor = s.vectorScaleFactor;
rasterCompressFactor = s.rasterCompressFactor;
addDirectionSymbol = s.addDirectionSymbol;
fontSizeInMapUnits = s.fontSizeInMapUnits;
dataDefinedProperties = s.dataDefinedProperties;
fontMetrics = NULL;
@ -193,7 +197,7 @@ static void _writeDataDefinedPropertyMap( QgsVectorLayer* layer, const QMap< Qgs
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 @@ static void _readDataDefinedPropertyMap( QgsVectorLayer* layer, QMap< QgsPalLaye
_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 @@ void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer )
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 @@ void QgsPalLayerSettings::writeToLayer( QgsVectorLayer* layer )
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 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetrics* fm, QString te
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 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, const QgsRenderContext
{
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 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, const QgsRenderContext
{
return;
}
labelFont.setPointSize( sizeToPixel( sizeDouble, context ) );
labelFont.setPixelSize( sizeToPixel( sizeDouble, context ) );
}
QFontMetrics labelFontMetrics( labelFont );
calculateLabelSize( &labelFontMetrics, labelText, labelX, labelY );
@ -430,6 +448,88 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, const QgsRenderContext
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 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, const QgsRenderContext
// 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,8 +553,19 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, const QgsRenderContext
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();
@ -465,9 +577,17 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, const QgsRenderContext
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 @@ void QgsPalLabeling::drawLabeling( QgsRenderContext& context )
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 @@ void QgsPalLabeling::drawLabel( pal::LabelPosition* label, QPainter* painter, co
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 @@ void QgsPalLabeling::drawLabel( pal::LabelPosition* label, QPainter* painter, co
painter->restore();
if ( label->getNextPart() )
drawLabel( label->getNextPart(), painter, f, c, xform, drawBuffer );
drawLabel( label->getNextPart(), painter, f, c, xform, bufferSize, bufferColor, drawBuffer );
}
}

View File

@ -83,6 +83,12 @@ class CORE_EXPORT QgsPalLayerSettings
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 @@ class CORE_EXPORT QgsPalLayerSettings
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 @@ class CORE_EXPORT QgsPalLayerSettings
/**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*/

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>496</width>
<height>659</height>
<width>504</width>
<height>686</height>
</rect>
</property>
<property name="windowTitle">
@ -396,7 +396,7 @@
</item>
</layout>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QLabel" name="label_29">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -412,7 +412,7 @@
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_16">
<item>
<widget class="QgsColorButton" name="btnTextColor">
@ -445,7 +445,7 @@
</item>
</layout>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QLabel" name="label_30">
<property name="text">
<string>Buffer</string>
@ -455,7 +455,7 @@
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_17">
<item>
<widget class="QCheckBox" name="chkBuffer">
@ -512,7 +512,7 @@
</item>
</layout>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QLabel" name="label_33">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -528,8 +528,14 @@
</property>
</widget>
</item>
<item row="4" column="1">
<item row="5" column="1">
<widget class="QgsLabelPreview" name="lblFontPreview">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
@ -544,13 +550,45 @@
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<item row="4" column="0" colspan="2">
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="mFontSizeLabel">
<property name="text">
<string>Font size</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QDoubleSpinBox" name="mFontSizeSpinBox">
<property name="maximum">
<double>999999999.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="mFontSizeUnitComboBox">
<item>
<property name="text">
<string>In points</string>
</property>
</item>
<item>
<property name="text">
<string>In map units</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
@ -678,7 +716,7 @@
</property>
</widget>
</item>
<item row="7" column="0">
<item row="8" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_19">
<item>
<widget class="QLabel" name="label_19">
@ -696,7 +734,7 @@
</item>
</layout>
</item>
<item row="8" column="0">
<item row="9" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_20">
<item>
<widget class="QCheckBox" name="chkNoObstacle">
@ -733,13 +771,20 @@
</item>
</layout>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="chkAddDirectionSymbol">
<property name="text">
<string>add direction symbol</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_4">
<attribute name="title">
<string>Data defined settings</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_4">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QGroupBox" name="mFontAttributePropertiesGroupBox">
<property name="sizePolicy">
@ -753,78 +798,74 @@
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_11">
<item row="0" column="0">
<widget class="QLabel" name="mSizeLabel">
<property name="text">
<string>Size</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="mSizeAttributeComboBox"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="mBoldLabel">
<property name="text">
<string>Bold</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="mBoldAttributeComboBox"/>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="mColorAttributeComboBox"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="mColorLabel">
<property name="text">
<string>Color</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="mItalicAttributeComboBox"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="mItalicLabel">
<property name="text">
<string>Italic</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="mUnderlineAttributeComboBox"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="mUnderlineLabel">
<property name="text">
<string>Underline</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="mFontFamilyAttributeComboBox"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="mFontFamilyLabel">
<property name="text">
<string>Font family</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="mStrikeoutAttributeComboBox"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="mStrikeoutLabel">
<property name="text">
<string>Strikeout</string>
</property>
</widget>
</item>
</layout>
<widget class="QLabel" name="mSizeLabel">
<property name="text">
<string>Size</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="mSizeAttributeComboBox"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="mColorLabel">
<property name="text">
<string>Color</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="mColorAttributeComboBox"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="mBoldLabel">
<property name="text">
<string>Bold</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="mBoldAttributeComboBox"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="mItalicLabel">
<property name="text">
<string>Italic</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="mItalicAttributeComboBox"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="mUnderlineLabel">
<property name="text">
<string>Underline</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="mUnderlineAttributeComboBox"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="mStrikeoutLabel">
<property name="text">
<string>Strikeout</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="mStrikeoutAttributeComboBox"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="mFontFamilyLabel">
<property name="text">
<string>Font family</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="mFontFamilyAttributeComboBox"/>
</item>
</layout>
</widget>
@ -834,35 +875,100 @@
<property name="title">
<string>Buffer properties</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="mBufferSizeLabel">
<property name="text">
<string>Buffer size</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="mBufferSizeAttributeComboBox"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="mBufferColorLabel">
<property name="text">
<string>Buffer color</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="mBufferColorAttributeComboBox"/>
</item>
</layout>
<widget class="QLabel" name="mBufferSizeLabel">
<property name="text">
<string>Buffer size</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="mBufferSizeAttributeComboBox"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="mBufferColorLabel">
<property name="text">
<string>Buffer color</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="mBufferColorAttributeComboBox"/>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QGroupBox" name="mPositionAttributeGroupBox">
<property name="title">
<string>Position</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="1" column="0">
<widget class="QLabel" name="mXCoordinateLabel">
<property name="text">
<string>X Coordinate</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="mXCoordinateComboBox"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="mYCoordinateLabel">
<property name="text">
<string>Y Coordinate</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="mYCoordinateComboBox"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="mHorizontalAlignmentLabel">
<property name="text">
<string>Horizontal alignment</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="mHorizontalAlignmentComboBox"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="mVerticalAlignmentLabel">
<property name="text">
<string>Vertical alignment</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="mVerticalAlignmentComboBox"/>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="mRotationComboBox"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="mRotationLabel">
<property name="text">
<string>Rotation</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="mLabelDistanceComboBox"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="mLabelDistanceLabel">
<property name="text">
<string>Label distance</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>