Skip to content

Commit

Permalink
Add option to set inside and outside maximum for delta angle between …
Browse files Browse the repository at this point in the history
…curved label characters

- Addresses #6763, #6673 and #2113, but does not perform any feature simplification
- Recommend adding some letter [and word] spacing before applying any delta angle adjustment
  • Loading branch information
dakcarto committed Nov 28, 2012
1 parent b9b943d commit ee12df2
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 9 deletions.
2 changes: 2 additions & 0 deletions python/core/qgspallabeling.sip
Expand Up @@ -135,6 +135,8 @@ class QgsPalLayerSettings
bool reverseDirectionSymbol;
DirectionSymbols placeDirectionSymbol; // whether to place left/right, above or below label
unsigned int upsidedownLabels; // whether, or how, to show upsidedown labels
double maxCurvedCharAngleIn; // maximum angle between inside curved label characters (defaults to 20.0, range 20.0 to 60.0)
double maxCurvedCharAngleOut; // maximum angle between outside curved label characters (defaults to -20.0, range -20.0 to -95.0)
bool fontSizeInMapUnits; //true if font size is in map units (otherwise in points)
bool fontLimitPixelSize; // true is label should be limited by fontMinPixelSize/fontMaxPixelSize
int fontMinPixelSize; // minimum pixel size for showing rendered map unit labels (1 - 1000)
Expand Down
9 changes: 9 additions & 0 deletions src/app/qgslabelinggui.cpp
Expand Up @@ -212,6 +212,9 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsM
mUpsidedownRadioOff->setChecked( true );
break;
}
mMaxCharAngleInDSpinBox->setValue( lyr.maxCurvedCharAngleIn );
// lyr.maxCurvedCharAngleOut must be negative, but it is shown as positive spinbox in GUI
mMaxCharAngleOutDSpinBox->setValue( qAbs( lyr.maxCurvedCharAngleOut ) );

wrapCharacterEdit->setText( lyr.wrapChar );
mFontLineHeightSpinBox->setValue( lyr.multilineHeight );
Expand Down Expand Up @@ -501,6 +504,10 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
{
lyr.upsidedownLabels = QgsPalLayerSettings::ShowAll;
}
lyr.maxCurvedCharAngleIn = mMaxCharAngleInDSpinBox->value();
// lyr.maxCurvedCharAngleOut must be negative, but it is shown as positive spinbox in GUI
lyr.maxCurvedCharAngleOut = -mMaxCharAngleOutDSpinBox->value();

lyr.minFeatureSize = mMinSizeSpinBox->value();
lyr.limitNumLabels = mLimitLabelChkBox->isChecked();
lyr.maxNumLabels = mLimitLabelSpinBox->value();
Expand Down Expand Up @@ -958,6 +965,8 @@ void QgsLabelingGui::updateOptions()
|| ( stackedPlacement->currentWidget() == pageLine && radLineCurved->isChecked() ) )
{
stackedOptions->setCurrentWidget( pageOptionsLine );
mMaxCharAngleFrame->setVisible(( stackedPlacement->currentWidget() == pageLine
&& radLineCurved->isChecked() ) );
}
else
{
Expand Down
5 changes: 4 additions & 1 deletion src/core/pal/feature.cpp
Expand Up @@ -837,7 +837,10 @@ namespace pal
// normalise between -180 and 180
while ( angle_delta > M_PI ) angle_delta -= 2 * M_PI;
while ( angle_delta < -M_PI ) angle_delta += 2 * M_PI;
if ( f->labelInfo->max_char_angle_delta > 0 && fabs( angle_delta ) > f->labelInfo->max_char_angle_delta*( M_PI / 180 ) )
if (( f->labelInfo->max_char_angle_inside > 0 && angle_delta > 0
&& angle_delta > f->labelInfo->max_char_angle_inside*( M_PI / 180 ) )
|| ( f->labelInfo->max_char_angle_outside < 0 && angle_delta < 0
&& angle_delta < f->labelInfo->max_char_angle_outside*( M_PI / 180 ) ) )
{
delete slp;
return NULL;
Expand Down
9 changes: 6 additions & 3 deletions src/core/pal/feature.h
Expand Up @@ -58,16 +58,19 @@ namespace pal
double width;
} CharacterInfo;

LabelInfo( int num, double height )
LabelInfo( int num, double height, double maxinangle = 20.0, double maxoutangle = -20.0 )
{
max_char_angle_delta = 20;
max_char_angle_inside = maxinangle;
// outside angle should be negative
max_char_angle_outside = maxoutangle > 0 ? -maxoutangle : maxoutangle;
label_height = height;
char_num = num;
char_info = new CharacterInfo[num];
}
~LabelInfo() { delete [] char_info; }

double max_char_angle_delta;
double max_char_angle_inside;
double max_char_angle_outside;
double label_height;
int char_num;
CharacterInfo* char_info;
Expand Down
34 changes: 31 additions & 3 deletions src/core/qgspallabeling.cpp
Expand Up @@ -96,13 +96,23 @@ class QgsPalGeometry : public PalGeometry
const char* strId() { return mStrId.data(); }
QString text() { return mText; }

pal::LabelInfo* info( QFontMetricsF* fm, const QgsMapToPixel* xform, double fontScale )
pal::LabelInfo* info( QFontMetricsF* fm, const QgsMapToPixel* xform, double fontScale, double maxinangle, double maxoutangle )
{
if ( mInfo )
return mInfo;

mFontMetrics = new QFontMetricsF( *fm ); // duplicate metrics for when drawing label

// max angle between curved label characters (20.0/-20.0 was default in QGIS <= 1.8)
if ( maxinangle < 20.0 )
maxinangle = 20.0;
if ( 60.0 < maxinangle )
maxinangle = 60.0;
if ( maxoutangle > -20.0 )
maxoutangle = -20.0;
if ( -95.0 > maxoutangle )
maxoutangle = -95.0;

// create label info!
QgsPoint ptZero = xform->toMapCoordinates( 0, 0 );
QgsPoint ptSize = xform->toMapCoordinatesF( 0.0, -fm->height() / fontScale );
Expand All @@ -111,7 +121,7 @@ class QgsPalGeometry : public PalGeometry
// (non-curved spacings handled by Qt in QgsPalLayerSettings/QgsPalLabeling)
qreal charWidth;
qreal wordSpaceFix;
mInfo = new pal::LabelInfo( mText.count(), ptSize.y() - ptZero.y() );
mInfo = new pal::LabelInfo( mText.count(), ptSize.y() - ptZero.y(), maxinangle, maxoutangle );
for ( int i = 0; i < mText.count(); i++ )
{
mInfo->char_info[i].chr = mText[i].unicode();
Expand Down Expand Up @@ -221,6 +231,8 @@ QgsPalLayerSettings::QgsPalLayerSettings()
reverseDirectionSymbol = false;
placeDirectionSymbol = SymbolLeftRight;
upsidedownLabels = Upright;
maxCurvedCharAngleIn = 20.0;
maxCurvedCharAngleOut = -20.0;
fontSizeInMapUnits = false;
fontLimitPixelSize = false;
fontMinPixelSize = 0; //trigger to turn it on by default for map unit labels
Expand Down Expand Up @@ -280,6 +292,8 @@ QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s )
reverseDirectionSymbol = s.reverseDirectionSymbol;
placeDirectionSymbol = s.placeDirectionSymbol;
upsidedownLabels = s.upsidedownLabels;
maxCurvedCharAngleIn = s.maxCurvedCharAngleIn;
maxCurvedCharAngleOut = s.maxCurvedCharAngleOut;
fontSizeInMapUnits = s.fontSizeInMapUnits;
fontLimitPixelSize = s.fontLimitPixelSize;
fontMinPixelSize = s.fontMinPixelSize;
Expand Down Expand Up @@ -470,6 +484,8 @@ void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer )
reverseDirectionSymbol = layer->customProperty( "labeling/reverseDirectionSymbol" ).toBool();
placeDirectionSymbol = ( DirectionSymbols ) layer->customProperty( "labeling/placeDirectionSymbol", QVariant( SymbolLeftRight ) ).toUInt();
upsidedownLabels = ( UpsideDownLabels ) layer->customProperty( "labeling/upsidedownLabels", QVariant( Upright ) ).toUInt();
maxCurvedCharAngleIn = layer->customProperty( "labeling/maxCurvedCharAngleIn", QVariant( 20.0 ) ).toDouble();
maxCurvedCharAngleOut = layer->customProperty( "labeling/maxCurvedCharAngleOut", QVariant( -20.0 ) ).toDouble();
minFeatureSize = layer->customProperty( "labeling/minFeatureSize" ).toDouble();
limitNumLabels = layer->customProperty( "labeling/limitNumLabels", QVariant( false ) ).toBool();
maxNumLabels = layer->customProperty( "labeling/maxNumLabels", QVariant( 2000 ) ).toInt();
Expand Down Expand Up @@ -540,6 +556,8 @@ void QgsPalLayerSettings::writeToLayer( QgsVectorLayer* layer )
layer->setCustomProperty( "labeling/reverseDirectionSymbol", reverseDirectionSymbol );
layer->setCustomProperty( "labeling/placeDirectionSymbol", ( unsigned int )placeDirectionSymbol );
layer->setCustomProperty( "labeling/upsidedownLabels", ( unsigned int )upsidedownLabels );
layer->setCustomProperty( "labeling/maxCurvedCharAngleIn", maxCurvedCharAngleIn );
layer->setCustomProperty( "labeling/maxCurvedCharAngleOut", maxCurvedCharAngleOut );
layer->setCustomProperty( "labeling/minFeatureSize", minFeatureSize );
layer->setCustomProperty( "labeling/limitNumLabels", limitNumLabels );
layer->setCustomProperty( "labeling/maxNumLabels", maxNumLabels );
Expand Down Expand Up @@ -776,6 +794,16 @@ void QgsPalLayerSettings::registerFeature( QgsVectorLayer* layer, QgsFeature& f
double labelX, labelY; // will receive label size
calculateLabelSize( labelFontMetrics, labelText, labelX, labelY );

// maximum angle between curved label characters
double maxcharanglein = 20.0;
double maxcharangleout = -20.0;
if ( placement == QgsPalLayerSettings::Curved )
{
maxcharanglein = maxCurvedCharAngleIn;
maxcharangleout = maxCurvedCharAngleOut > 0 ? -maxCurvedCharAngleOut : maxCurvedCharAngleOut;
}
// TODO: add data defined override for maximum angle between curved label characters

QgsGeometry* geom = f.geometry();
if ( !geom )
{
Expand Down Expand Up @@ -1037,7 +1065,7 @@ void QgsPalLayerSettings::registerFeature( QgsVectorLayer* layer, QgsFeature& f
// TODO: only for placement which needs character info
pal::Feature* feat = palLayer->getFeature( lbl->strId() );
// account for any data defined font metrics adjustments
feat->setLabelInfo( lbl->info( labelFontMetrics, xform, rasterCompressFactor ) );
feat->setLabelInfo( lbl->info( labelFontMetrics, xform, rasterCompressFactor, maxcharanglein, maxcharangleout ) );
delete labelFontMetrics;

// TODO: allow layer-wide feature dist in PAL...?
Expand Down
2 changes: 2 additions & 0 deletions src/core/qgspallabeling.h
Expand Up @@ -189,6 +189,8 @@ class CORE_EXPORT QgsPalLayerSettings
bool reverseDirectionSymbol;
DirectionSymbols placeDirectionSymbol; // whether to place left/right, above or below label
unsigned int upsidedownLabels; // whether, or how, to show upsidedown labels
double maxCurvedCharAngleIn; // maximum angle between inside curved label characters (defaults to 20.0, range 20.0 to 60.0)
double maxCurvedCharAngleOut; // maximum angle between outside curved label characters (defaults to -20.0, range -20.0 to -95.0)
bool fontSizeInMapUnits; //true if font size is in map units (otherwise in points)
bool fontLimitPixelSize; // true is label should be limited by fontMinPixelSize/fontMaxPixelSize
int fontMinPixelSize; // minimum pixel size for showing rendered map unit labels (1 - 1000)
Expand Down
140 changes: 138 additions & 2 deletions src/ui/qgslabelingguibase.ui
Expand Up @@ -1921,7 +1921,7 @@
<x>0</x>
<y>0</y>
<width>686</width>
<height>574</height>
<height>618</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_13">
Expand Down Expand Up @@ -2366,6 +2366,142 @@
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="mMaxCharAngleFrame">
<layout class="QGridLayout" name="gridLayout_22">
<property name="verticalSpacing">
<number>6</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item row="1" column="4">
<widget class="QDoubleSpinBox" name="mMaxCharAngleOutDSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>90</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>20.000000000000000</double>
</property>
<property name="maximum">
<double>95.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer_13">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>8</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="3">
<widget class="QLabel" name="mMaxCharAngleOutLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>outside</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="mMaxCharAngleInLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>inside</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QDoubleSpinBox" name="mMaxCharAngleInDSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>90</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>20.000000000000000</double>
</property>
<property name="maximum">
<double>60.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="5">
<spacer name="horizontalSpacer_12">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="6">
<widget class="QLabel" name="mMaxCharAngleLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Maximum angle between curved characters</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="pageOptionsEmpty"/>
Expand Down Expand Up @@ -2858,7 +2994,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>488</width>
<width>686</width>
<height>981</height>
</rect>
</property>
Expand Down

2 comments on commit ee12df2

@NathanW2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks heaps Larry

@timlinux
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

Please sign in to comment.