Skip to content
Permalink
Browse files

Unify label rotation with other rotation settings

Label rotation is now specified in degrees clockwise, just like
symbol rotation, map rotation, etc.

Fix #4518
  • Loading branch information
nyalldawson committed May 30, 2017
1 parent d99d14b commit 21a4ac4d3a747182c78224e23718bd09c6243d73
@@ -1732,6 +1732,7 @@ members were removed. Use the QgsProperty framework through dataDefinedPropertie
and setDataDefinedProperties() instead.
- readXml() and writeXml() now expect a reference to QgsReadWriteContext.
- fromLayer() has been reoved. Labeling is read/written in QgsAbstractVectorLayerLabeling and its subclasses.
- angleOffset is now in degrees clockwise. QGIS 2.x used degrees counterclockwise.


QgsPanelWidgetStack {#qgis_api_break_3_0_QgsPanelWidgetStack}
@@ -239,6 +239,7 @@ class QgsPalLayerSettings
Hali,
Vali,
Rotation,
LabelRotation,
RepeatDistance,
RepeatDistanceUnit,
Priority,
@@ -346,7 +347,12 @@ Offset type for layer (only applies in certain placement modes)
double yOffset; // offset from point in mm or map units
bool labelOffsetInMapUnits; //true if label offset is in map units (otherwise in mm)
QgsMapUnitScale labelOffsetMapUnitScale;
double angleOffset; // rotation applied to offset labels

double angleOffset;
%Docstring
Label rotation, in degrees clockwise
%End

bool preserveRotation; // preserve predefined rotation data during label pin/unpin operations

double maxCurvedCharAngleIn; // maximum angle between inside curved label characters (defaults to 20.0, range 20.0 to 60.0)
@@ -405,16 +405,15 @@ class QgsTextBackgroundSettings

double rotation() const;
%Docstring
Returns the rotation for the background shape.
Returns the rotation for the background shape, in degrees clockwise.
.. seealso:: rotationType()
.. seealso:: setRotation()
:rtype: float
%End

void setRotation( double rotation );
%Docstring
Sets the rotation for the background shape.
\param rotation angle in degrees to rotate
Sets the ``rotation`` for the background shape, in degrees clockwise.
.. seealso:: rotation()
.. seealso:: setRotationType()
%End
@@ -396,7 +396,7 @@ void QgsDwgImportDialog::createGroup( QgsLayerTreeGroup *group, QString name, QS
" WHEN alignv=3 THEN 'Top'"
" END"
" END" ).arg( DRW::MTEXT ) ) );
pls.dataDefinedProperties().setProperty( QgsPalLayerSettings::Rotation, QgsProperty::fromExpression( QStringLiteral( "angle*180.0/pi()" ) ) );
pls.dataDefinedProperties().setProperty( QgsPalLayerSettings::LabelRotation, QgsProperty::fromExpression( QStringLiteral( "360-angle*180.0/pi()" ) ) );

pls.placement = QgsPalLayerSettings::OrderedPositionsAroundPoint;
l->setLabeling( new QgsVectorLayerSimpleLabeling( pls ) );
@@ -545,7 +545,7 @@ void QgsLabelingGui::populateDataDefinedButtons()
mCoordAlignmentHDDBtn->setUsageInfo( ddPlaceInfo );
registerDataDefinedButton( mCoordAlignmentVDDBtn, QgsPalLayerSettings::Vali );
mCoordAlignmentVDDBtn->setUsageInfo( ddPlaceInfo );
registerDataDefinedButton( mCoordRotationDDBtn, QgsPalLayerSettings::Rotation );
registerDataDefinedButton( mCoordRotationDDBtn, QgsPalLayerSettings::LabelRotation );
mCoordRotationDDBtn->setUsageInfo( ddPlaceInfo );

// rendering
@@ -36,6 +36,7 @@ QgsLabelPropertyDialog::QgsLabelPropertyDialog( const QString &layerId, const QS
QDialog( parent, f ), mLabelFont( labelFont ), mCurLabelField( -1 )
{
setupUi( this );
mRotationSpinBox->setClearValue( 0 );
fillHaliComboBox();
fillValiComboBox();

@@ -314,7 +315,7 @@ void QgsLabelPropertyDialog::setDataDefinedValues( QgsVectorLayer *vlayer )
case QgsPalLayerSettings::Color:
mFontColorButton->setColor( QColor( result.toString() ) );
break;
case QgsPalLayerSettings::Rotation:
case QgsPalLayerSettings::LabelRotation:
{
double rot = result.toDouble( &ok );
if ( ok )
@@ -407,7 +408,7 @@ void QgsLabelPropertyDialog::enableDataDefinedWidgets( QgsVectorLayer *vlayer )
case QgsPalLayerSettings::Color:
mFontColorButton->setEnabled( true );
break;
case QgsPalLayerSettings::Rotation:
case QgsPalLayerSettings::LabelRotation:
mRotationSpinBox->setEnabled( true );
break;
//font related properties
@@ -618,7 +619,7 @@ void QgsLabelPropertyDialog::on_mRotationSpinBox_valueChanged( double d )
//null value so that size is reset to default
rotation.clear();
}
insertChangedValue( QgsPalLayerSettings::Rotation, rotation );
insertChangedValue( QgsPalLayerSettings::LabelRotation, rotation );
}

void QgsLabelPropertyDialog::on_mFontColorButton_colorChanged( const QColor &color )
@@ -485,7 +485,7 @@ bool QgsMapToolLabel::layerIsRotatable( QgsVectorLayer *vlayer, int &rotationCol

bool QgsMapToolLabel::labelIsRotatable( QgsVectorLayer *layer, const QgsPalLayerSettings &settings, int &rotationCol ) const
{
QString rColName = dataDefinedColumnName( QgsPalLayerSettings::Rotation, settings );
QString rColName = dataDefinedColumnName( QgsPalLayerSettings::LabelRotation, settings );
rotationCol = layer->fields().lookupField( rColName );
return rotationCol != -1;
}
@@ -211,7 +211,8 @@ void QgsPalLayerSettings::initPropertyDefinitions()
QgsPalLayerSettings::Vali, QgsPropertyDefinition( "Vali", QgsPropertyDefinition::DataTypeString, QObject::tr( "Vertical alignment" ), QObject::tr( "string " ) + QStringLiteral( "[<b>Bottom</b>|<b>Base</b>|<br>"
"<b>Half</b>|<b>Cap</b>|<b>Top</b>]" ) )
},
{ QgsPalLayerSettings::Rotation, QgsPropertyDefinition( "Rotation", QObject::tr( "Label rotation" ), QgsPropertyDefinition::Rotation ) },
{ QgsPalLayerSettings::Rotation, QgsPropertyDefinition( "Rotation", QObject::tr( "Label rotation (deprecated)" ), QgsPropertyDefinition::Rotation ) },
{ QgsPalLayerSettings::LabelRotation, QgsPropertyDefinition( "LabelRotation", QObject::tr( "Label rotation" ), QgsPropertyDefinition::Rotation ) },
{ QgsPalLayerSettings::ScaleVisibility, QgsPropertyDefinition( "ScaleVisibility", QObject::tr( "Scale based visibility" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::MinScale, QgsPropertyDefinition( "MinScale", QObject::tr( "Minimum scale (denominator)" ), QgsPropertyDefinition::Double ) },
{ QgsPalLayerSettings::MaxScale, QgsPropertyDefinition( "MaxScale", QObject::tr( "Maximum scale (denominator)" ), QgsPropertyDefinition::Double ) },
@@ -598,7 +599,18 @@ void QgsPalLayerSettings::readFromLayerCustomProperties( QgsVectorLayer *layer )
{
labelOffsetMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( layer->customProperty( QStringLiteral( "labeling/labelOffsetMapUnitScale" ) ).toString() );
}
angleOffset = layer->customProperty( QStringLiteral( "labeling/angleOffset" ), QVariant( 0.0 ) ).toDouble();

QVariant tempAngle = layer->customProperty( QStringLiteral( "labeling/angleOffset" ), QVariant() );
if ( tempAngle.isValid() )
{
double oldAngle = layer->customProperty( QStringLiteral( "labeling/angleOffset" ), QVariant( 0.0 ) ).toDouble();
angleOffset = fmod( 360 - oldAngle, 360.0 );
}
else
{
angleOffset = layer->customProperty( QStringLiteral( "labeling/rotationAngle" ), QVariant( 0.0 ) ).toDouble();
}

preserveRotation = layer->customProperty( QStringLiteral( "labeling/preserveRotation" ), QVariant( true ) ).toBool();
maxCurvedCharAngleIn = layer->customProperty( QStringLiteral( "labeling/maxCurvedCharAngleIn" ), QVariant( 25.0 ) ).toDouble();
maxCurvedCharAngleOut = layer->customProperty( QStringLiteral( "labeling/maxCurvedCharAngleOut" ), QVariant( -25.0 ) ).toDouble();
@@ -691,6 +703,11 @@ void QgsPalLayerSettings::readFromLayerCustomProperties( QgsVectorLayer *layer )
mDataDefinedProperties.setProperty( ShadowOpacity, QgsProperty::fromExpression( QStringLiteral( "100 - (%1)" ).arg( mDataDefinedProperties.property( ShadowTransparency ).asExpression() ) ) );
mDataDefinedProperties.setProperty( ShadowTransparency, QgsProperty() );
}
if ( mDataDefinedProperties.isActive( Rotation ) )
{
mDataDefinedProperties.setProperty( LabelRotation, QgsProperty::fromExpression( QStringLiteral( "360 - (%1)" ).arg( mDataDefinedProperties.property( Rotation ).asExpression() ) ) );
mDataDefinedProperties.setProperty( Rotation, QgsProperty() );
}
}

void QgsPalLayerSettings::readXml( QDomElement &elem, const QgsReadWriteContext &context )
@@ -755,7 +772,17 @@ void QgsPalLayerSettings::readXml( QDomElement &elem, const QgsReadWriteContext
{
labelOffsetMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( placementElem.attribute( QStringLiteral( "labelOffsetMapUnitScale" ) ) );
}
angleOffset = placementElem.attribute( QStringLiteral( "angleOffset" ), QStringLiteral( "0" ) ).toDouble();

if ( placementElem.hasAttribute( QStringLiteral( "angleOffset" ) ) )
{
double oldAngle = placementElem.attribute( QStringLiteral( "angleOffset" ), QStringLiteral( "0" ) ).toDouble();
angleOffset = fmod( 360 - oldAngle, 360.0 );
}
else
{
angleOffset = placementElem.attribute( QStringLiteral( "rotationAngle" ), QStringLiteral( "0" ) ).toDouble();
}

preserveRotation = placementElem.attribute( QStringLiteral( "preserveRotation" ), QStringLiteral( "1" ) ).toInt();
maxCurvedCharAngleIn = placementElem.attribute( QStringLiteral( "maxCurvedCharAngleIn" ), QStringLiteral( "25" ) ).toDouble();
maxCurvedCharAngleOut = placementElem.attribute( QStringLiteral( "maxCurvedCharAngleOut" ), QStringLiteral( "-25" ) ).toDouble();
@@ -831,6 +858,11 @@ void QgsPalLayerSettings::readXml( QDomElement &elem, const QgsReadWriteContext
mDataDefinedProperties.setProperty( ShadowOpacity, QgsProperty::fromExpression( QStringLiteral( "100 - (%1)" ).arg( mDataDefinedProperties.property( ShadowTransparency ).asExpression() ) ) );
mDataDefinedProperties.setProperty( ShadowTransparency, QgsProperty() );
}
if ( mDataDefinedProperties.isActive( Rotation ) )
{
mDataDefinedProperties.setProperty( LabelRotation, QgsProperty::fromExpression( QStringLiteral( "360 - (%1)" ).arg( mDataDefinedProperties.property( Rotation ).asExpression() ) ) );
mDataDefinedProperties.setProperty( Rotation, QgsProperty() );
}
}


@@ -878,7 +910,7 @@ QDomElement QgsPalLayerSettings::writeXml( QDomDocument &doc, const QgsReadWrite
placementElem.setAttribute( QStringLiteral( "yOffset" ), yOffset );
placementElem.setAttribute( QStringLiteral( "labelOffsetInMapUnits" ), labelOffsetInMapUnits );
placementElem.setAttribute( QStringLiteral( "labelOffsetMapUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( labelOffsetMapUnitScale ) );
placementElem.setAttribute( QStringLiteral( "angleOffset" ), angleOffset );
placementElem.setAttribute( QStringLiteral( "rotationAngle" ), angleOffset );
placementElem.setAttribute( QStringLiteral( "preserveRotation" ), preserveRotation );
placementElem.setAttribute( QStringLiteral( "maxCurvedCharAngleIn" ), maxCurvedCharAngleIn );
placementElem.setAttribute( QStringLiteral( "maxCurvedCharAngleOut" ), maxCurvedCharAngleOut );
@@ -1576,13 +1608,13 @@ void QgsPalLayerSettings::registerFeature( QgsFeature &f, QgsRenderContext &cont
if ( placement == QgsPalLayerSettings::OverPoint && !qgsDoubleNear( angleOffset, 0.0 ) )
{
layerDefinedRotation = true;
angle = angleOffset * M_PI / 180; // convert to radians
angle = ( 360 - angleOffset ) * M_PI / 180; // convert to radians counterclockwise
}

const QgsMapToPixel &m2p = context.mapToPixel();
//data defined rotation?
context.expressionContext().setOriginalValueVariable( angleOffset );
exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::Rotation, context.expressionContext() );
exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::LabelRotation, context.expressionContext() );
if ( exprVal.isValid() )
{
bool ok;
@@ -1593,8 +1625,8 @@ void QgsPalLayerSettings::registerFeature( QgsFeature &f, QgsRenderContext &cont
dataDefinedRotation = true;
// TODO: add setting to disable having data defined rotation follow
// map rotation ?
rotD -= m2p.mapRotation();
angle = rotD * M_PI / 180.0;
rotD += m2p.mapRotation();
angle = ( 360 - rotD ) * M_PI / 180.0;
}
}

@@ -353,7 +353,8 @@ class CORE_EXPORT QgsPalLayerSettings
PositionY = 10, //!< Y-coordinate data defined label position
Hali = 11, //!< Horizontal alignment for data defined label position (Left, Center, Right)
Vali = 12, //!< Vertical alignment for data defined label position (Bottom, Base, Half, Cap, Top)
Rotation = 14, //!< Label rotation
Rotation = 14, //!< Label rotation (deprecated, for old project compatibility only)
LabelRotation = 96, //!< Label rotation (deprecated, for old project compatibility only)
RepeatDistance = 84,
RepeatDistanceUnit = 86,
Priority = 87,
@@ -463,7 +464,10 @@ class CORE_EXPORT QgsPalLayerSettings
double yOffset; // offset from point in mm or map units
bool labelOffsetInMapUnits; //true if label offset is in map units (otherwise in mm)
QgsMapUnitScale labelOffsetMapUnitScale;
double angleOffset; // rotation applied to offset labels

//! Label rotation, in degrees clockwise
double angleOffset;

bool preserveRotation; // preserve predefined rotation data during label pin/unpin operations

double maxCurvedCharAngleIn; // maximum angle between inside curved label characters (defaults to 20.0, range 20.0 to 60.0)
@@ -369,14 +369,15 @@ class CORE_EXPORT QgsTextBackgroundSettings
*/
void setRotationType( RotationType type );

/** Returns the rotation for the background shape.
/**
* Returns the rotation for the background shape, in degrees clockwise.
* \see rotationType()
* \see setRotation()
*/
double rotation() const;

/** Sets the rotation for the background shape.
* \param rotation angle in degrees to rotate
/**
* Sets the \a rotation for the background shape, in degrees clockwise.
* \see rotation()
* \see setRotationType()
*/
@@ -3768,7 +3768,7 @@ void QgsVectorLayer::readSldLabeling( const QDomNode &node )
double rotation = rotationElem.text().toDouble( &ok );
if ( ok )
{
settings.angleOffset = rotation;
settings.angleOffset = 360 - rotation;
}
}
}
@@ -214,9 +214,6 @@ void QgsTextFormatWidget::initWidget()
mPlacePolygonBtnGrp->setExclusive( true );
connect( mPlacePolygonBtnGrp, static_cast<void ( QButtonGroup::* )( int )>( &QButtonGroup::buttonClicked ), this, &QgsTextFormatWidget::updatePlacementWidgets );

// TODO: is this necessary? maybe just use the data defined-only rotation?
mPointAngleDDBtn->setVisible( false );

// Global settings group for groupboxes' saved/restored collapsed state
// maintains state across different dialogs
Q_FOREACH ( QgsCollapsibleGroupBox *grpbox, findChildren<QgsCollapsibleGroupBox *>() )
@@ -359,7 +356,6 @@ void QgsTextFormatWidget::initWidget()
<< mObstacleTypeComboBox
<< mOffsetTypeComboBox
<< mPalShowAllLabelsForLayerChkBx
<< mPointAngleDDBtn
<< mPointAngleSpinBox
<< mPointOffsetDDBtn
<< mPointOffsetUnitsDDBtn
@@ -37,9 +37,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>431</width>
<height>622</height>
<y>-391</y>
<width>417</width>
<height>689</height>
</rect>
</property>
<layout class="QVBoxLayout" name="mLabelPropertiesLayout">
@@ -576,11 +576,17 @@
</item>
<item row="5" column="1">
<widget class="QgsDoubleSpinBox" name="mRotationSpinBox">
<property name="wrapping">
<bool>true</bool>
</property>
<property name="specialValueText">
<string>Default</string>
</property>
<property name="suffix">
<string>˚</string>
</property>
<property name="minimum">
<double>-1.000000000000000</double>
<double>-360.000000000000000</double>
</property>
<property name="maximum">
<double>360.000000000000000</double>
@@ -623,24 +629,12 @@
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QgsScrollArea</class>
<extends>QScrollArea</extends>
<header>qgsscrollarea.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsColorButton</class>
<extends>QToolButton</extends>
<header>qgscolorbutton.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsCollapsibleGroupBox</class>
<extends>QGroupBox</extends>
<header>qgscollapsiblegroupbox.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsDoubleSpinBox</class>
<extends>QDoubleSpinBox</extends>
@@ -651,6 +645,18 @@
<extends>QSpinBox</extends>
<header>qgsspinbox.h</header>
</customwidget>
<customwidget>
<class>QgsCollapsibleGroupBox</class>
<extends>QGroupBox</extends>
<header>qgscollapsiblegroupbox.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsScrollArea</class>
<extends>QScrollArea</extends>
<header>qgsscrollarea.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>mLabelTextLineEdit</tabstop>

0 comments on commit 21a4ac4

Please sign in to comment.
You can’t perform that action at this time.