mirror of
https://github.com/qgis/QGIS.git
synced 2025-12-15 00:07:25 -05:00
Default to a "Follow placement" mode for the text anchor point, which
means when the line anchor is < 25% then it will be matched to the start of the text, when the line anchor is > 75% it will be matched to the end of the text, otherwise match to center of text
This commit is contained in:
parent
3924437947
commit
94f198b36b
@ -22,6 +22,7 @@ QgsLabelLineSettings.AnchorClipping.baseClass = QgsLabelLineSettings
|
||||
QgsLabelLineSettings.AnchorTextPoint.StartOfText.__doc__ = "Anchor using start of text"
|
||||
QgsLabelLineSettings.AnchorTextPoint.CenterOfText.__doc__ = "Anchor using center of text"
|
||||
QgsLabelLineSettings.AnchorTextPoint.EndOfText.__doc__ = "Anchor using end of text"
|
||||
QgsLabelLineSettings.AnchorTextPoint.FollowPlacement.__doc__ = "Automatically set the anchor point based on the lineAnchorPercent() value. Values <25% will use the start of text, values > 75% will use the end of text, and values in between will use the center of the text"
|
||||
QgsLabelLineSettings.AnchorTextPoint.__doc__ = 'Anchor point of label text.\n\n.. versionadded:: 3.26\n\n' + '* ``StartOfText``: ' + QgsLabelLineSettings.AnchorTextPoint.StartOfText.__doc__ + '\n' + '* ``CenterOfText``: ' + QgsLabelLineSettings.AnchorTextPoint.CenterOfText.__doc__ + '\n' + '* ``EndOfText``: ' + QgsLabelLineSettings.AnchorTextPoint.EndOfText.__doc__ + '\n' + '* ``FollowPlacement``: ' + QgsLabelLineSettings.AnchorTextPoint.FollowPlacement.__doc__
|
||||
# --
|
||||
QgsLabelLineSettings.AnchorTextPoint.baseClass = QgsLabelLineSettings
|
||||
|
||||
@ -52,6 +52,7 @@ a "perimeter" style mode).
|
||||
StartOfText,
|
||||
CenterOfText,
|
||||
EndOfText,
|
||||
FollowPlacement,
|
||||
};
|
||||
|
||||
QgsLabeling::LinePlacementFlags placementFlags() const;
|
||||
|
||||
@ -98,6 +98,23 @@ void QgsLabelFeature::setOverrunSmoothDistance( double overrunSmoothDistance )
|
||||
mOverrunSmoothDistance = overrunSmoothDistance;
|
||||
}
|
||||
|
||||
QgsLabelLineSettings::AnchorTextPoint QgsLabelFeature::lineAnchorTextPoint() const
|
||||
{
|
||||
if ( mAnchorTextPoint == QgsLabelLineSettings::AnchorTextPoint::FollowPlacement )
|
||||
{
|
||||
if ( mLineAnchorPercent < 0.25 )
|
||||
return QgsLabelLineSettings::AnchorTextPoint::StartOfText;
|
||||
else if ( mLineAnchorPercent > 0.75 )
|
||||
return QgsLabelLineSettings::AnchorTextPoint::EndOfText;
|
||||
else
|
||||
return QgsLabelLineSettings::AnchorTextPoint::CenterOfText;
|
||||
}
|
||||
else
|
||||
{
|
||||
return mAnchorTextPoint;
|
||||
}
|
||||
}
|
||||
|
||||
const QgsLabelObstacleSettings &QgsLabelFeature::obstacleSettings() const
|
||||
{
|
||||
return mObstacleSettings;
|
||||
|
||||
@ -478,7 +478,7 @@ class CORE_EXPORT QgsLabelFeature
|
||||
*
|
||||
* \since QGIS 3.26
|
||||
*/
|
||||
QgsLabelLineSettings::AnchorTextPoint lineAnchorTextPoint() const { return mAnchorTextPoint; }
|
||||
QgsLabelLineSettings::AnchorTextPoint lineAnchorTextPoint() const;
|
||||
|
||||
/**
|
||||
* Sets the line anchor text \a point, which dictates which part of the label text
|
||||
|
||||
@ -76,7 +76,9 @@ void QgsLabelLineSettings::updateDataDefinedProperties( const QgsPropertyCollect
|
||||
const QString value = properties.valueAsString( QgsPalLayerSettings::LineAnchorTextPoint, context, QString(), &ok ).trimmed();
|
||||
if ( ok )
|
||||
{
|
||||
if ( value.compare( QLatin1String( "start" ), Qt::CaseInsensitive ) == 0 )
|
||||
if ( value.compare( QLatin1String( "follow" ), Qt::CaseInsensitive ) == 0 )
|
||||
mAnchorTextPoint = AnchorTextPoint::FollowPlacement;
|
||||
else if ( value.compare( QLatin1String( "start" ), Qt::CaseInsensitive ) == 0 )
|
||||
mAnchorTextPoint = AnchorTextPoint::StartOfText;
|
||||
else if ( value.compare( QLatin1String( "center" ), Qt::CaseInsensitive ) == 0 )
|
||||
mAnchorTextPoint = AnchorTextPoint::CenterOfText;
|
||||
|
||||
@ -85,6 +85,7 @@ class CORE_EXPORT QgsLabelLineSettings
|
||||
StartOfText, //!< Anchor using start of text
|
||||
CenterOfText, //!< Anchor using center of text
|
||||
EndOfText, //!< Anchor using end of text
|
||||
FollowPlacement, //!< Automatically set the anchor point based on the lineAnchorPercent() value. Values <25% will use the start of text, values > 75% will use the end of text, and values in between will use the center of the text
|
||||
};
|
||||
Q_ENUM( AnchorTextPoint )
|
||||
|
||||
@ -379,7 +380,7 @@ class CORE_EXPORT QgsLabelLineSettings
|
||||
double mLineAnchorPercent = 0.5;
|
||||
AnchorType mAnchorType = AnchorType::HintOnly;
|
||||
AnchorClipping mAnchorClipping = AnchorClipping::UseVisiblePartsOfLine;
|
||||
AnchorTextPoint mAnchorTextPoint = AnchorTextPoint::CenterOfText;
|
||||
AnchorTextPoint mAnchorTextPoint = AnchorTextPoint::FollowPlacement;
|
||||
};
|
||||
|
||||
#endif // QGSLABELLINESETTINGS_H
|
||||
|
||||
@ -227,7 +227,7 @@ void QgsPalLayerSettings::initPropertyDefinitions()
|
||||
{ QgsPalLayerSettings::LineAnchorPercent, QgsPropertyDefinition( "LineAnchorPercent", QObject::tr( "Line anchor percentage, as fraction from 0.0 to 1.0" ), QgsPropertyDefinition::Double0To1, origin ) },
|
||||
{ QgsPalLayerSettings::LineAnchorClipping, QgsPropertyDefinition( "LineAnchorClipping", QgsPropertyDefinition::DataTypeString, QObject::tr( "Line anchor clipping mode" ), QObject::tr( "string " ) + QStringLiteral( "[<b>visible</b>|<b>entire</b>]" ), origin ) },
|
||||
{ QgsPalLayerSettings::LineAnchorType, QgsPropertyDefinition( "LineAnchorType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Line anchor type" ), QObject::tr( "string " ) + QStringLiteral( "[<b>hint</b>|<b>strict</b>]" ), origin ) },
|
||||
{ QgsPalLayerSettings::LineAnchorTextPoint, QgsPropertyDefinition( "LineAnchorTextPoint", QgsPropertyDefinition::DataTypeString, QObject::tr( "Line anchor text point" ), QObject::tr( "string " ) + QStringLiteral( "[<b>start</b>|<b>center</b>|<b>end</b>]" ), origin ) },
|
||||
{ QgsPalLayerSettings::LineAnchorTextPoint, QgsPropertyDefinition( "LineAnchorTextPoint", QgsPropertyDefinition::DataTypeString, QObject::tr( "Line anchor text point" ), QObject::tr( "string " ) + QStringLiteral( "[<b>follow</b>|<b>start</b>|<b>center</b>|<b>end</b>]" ), origin ) },
|
||||
{ QgsPalLayerSettings::Priority, QgsPropertyDefinition( "Priority", QgsPropertyDefinition::DataTypeNumeric, QObject::tr( "Label priority" ), QObject::tr( "double [0.0-10.0]" ), origin ) },
|
||||
{ QgsPalLayerSettings::IsObstacle, QgsPropertyDefinition( "IsObstacle", QObject::tr( "Feature is a label obstacle" ), QgsPropertyDefinition::Boolean, origin ) },
|
||||
{ QgsPalLayerSettings::ObstacleFactor, QgsPropertyDefinition( "ObstacleFactor", QgsPropertyDefinition::DataTypeNumeric, QObject::tr( "Obstacle factor" ), QObject::tr( "double [0.0-10.0]" ), origin ) },
|
||||
|
||||
@ -806,6 +806,8 @@ std::size_t FeaturePart::createHorizontalCandidatesAlongLine( std::vector<std::u
|
||||
break;
|
||||
}
|
||||
|
||||
const QgsLabelLineSettings::AnchorTextPoint textPoint = mLF->lineAnchorTextPoint();
|
||||
|
||||
double candidateCenterX, candidateCenterY;
|
||||
int i = 0;
|
||||
while ( currentDistanceAlongLine <= totalLineLength )
|
||||
@ -822,7 +824,7 @@ std::size_t FeaturePart::createHorizontalCandidatesAlongLine( std::vector<std::u
|
||||
cost /= 1000; // < 0, 0.0005 >
|
||||
|
||||
double labelX = 0;
|
||||
switch ( mLF->lineAnchorTextPoint() )
|
||||
switch ( textPoint )
|
||||
{
|
||||
case QgsLabelLineSettings::AnchorTextPoint::StartOfText:
|
||||
labelX = candidateCenterX;
|
||||
@ -833,6 +835,9 @@ std::size_t FeaturePart::createHorizontalCandidatesAlongLine( std::vector<std::u
|
||||
case QgsLabelLineSettings::AnchorTextPoint::EndOfText:
|
||||
labelX = candidateCenterX - labelWidth;
|
||||
break;
|
||||
case QgsLabelLineSettings::AnchorTextPoint::FollowPlacement:
|
||||
// not possible here
|
||||
break;
|
||||
}
|
||||
lPos.emplace_back( std::make_unique< LabelPosition >( i, labelX, candidateCenterY - labelHeight / 2, labelWidth, labelHeight, 0, cost, this, false, LabelPosition::QuadrantOver ) );
|
||||
|
||||
@ -938,6 +943,8 @@ std::size_t FeaturePart::createCandidatesAlongLineNearStraightSegments( std::vec
|
||||
return 0; //createCandidatesAlongLineNearMidpoint will be more appropriate
|
||||
}
|
||||
|
||||
const QgsLabelLineSettings::AnchorTextPoint textPoint = mLF->lineAnchorTextPoint();
|
||||
|
||||
const std::size_t candidateTargetCount = maximumLineCandidates();
|
||||
double lineStepDistance = ( totalLineLength - labelWidth ); // distance to move along line with each candidate
|
||||
lineStepDistance = std::min( std::min( labelHeight, labelWidth ), lineStepDistance / candidateTargetCount );
|
||||
@ -997,7 +1004,7 @@ std::size_t FeaturePart::createCandidatesAlongLineNearStraightSegments( std::vec
|
||||
|
||||
const double labelCenter = currentDistanceAlongLine + labelWidth / 2.0;
|
||||
double labelTextAnchor = 0;
|
||||
switch ( mLF->lineAnchorTextPoint() )
|
||||
switch ( textPoint )
|
||||
{
|
||||
case QgsLabelLineSettings::AnchorTextPoint::StartOfText:
|
||||
labelTextAnchor = currentDistanceAlongLine;
|
||||
@ -1008,6 +1015,9 @@ std::size_t FeaturePart::createCandidatesAlongLineNearStraightSegments( std::vec
|
||||
case QgsLabelLineSettings::AnchorTextPoint::EndOfText:
|
||||
labelTextAnchor = currentDistanceAlongLine + labelWidth;
|
||||
break;
|
||||
case QgsLabelLineSettings::AnchorTextPoint::FollowPlacement:
|
||||
// not possible here
|
||||
break;
|
||||
}
|
||||
|
||||
const bool placementIsFlexible = mLF->lineAnchorPercent() > 0.1 && mLF->lineAnchorPercent() < 0.9;
|
||||
@ -1133,6 +1143,8 @@ std::size_t FeaturePart::createCandidatesAlongLineNearMidpoint( std::vector< std
|
||||
double lineStepDistance = ( totalLineLength - labelWidth ); // distance to move along line with each candidate
|
||||
double currentDistanceAlongLine = 0;
|
||||
|
||||
const QgsLabelLineSettings::AnchorTextPoint textPoint = mLF->lineAnchorTextPoint();
|
||||
|
||||
const std::size_t candidateTargetCount = maximumLineCandidates();
|
||||
|
||||
if ( totalLineLength > labelWidth )
|
||||
@ -1159,7 +1171,7 @@ std::size_t FeaturePart::createCandidatesAlongLineNearMidpoint( std::vector< std
|
||||
break;
|
||||
|
||||
case QgsLabelLineSettings::AnchorType::Strict:
|
||||
switch ( mLF->lineAnchorTextPoint() )
|
||||
switch ( textPoint )
|
||||
{
|
||||
case QgsLabelLineSettings::AnchorTextPoint::StartOfText:
|
||||
currentDistanceAlongLine = std::min( lineAnchorPoint, totalLineLength * 0.99 - labelWidth );
|
||||
@ -1170,6 +1182,9 @@ std::size_t FeaturePart::createCandidatesAlongLineNearMidpoint( std::vector< std
|
||||
case QgsLabelLineSettings::AnchorTextPoint::EndOfText:
|
||||
currentDistanceAlongLine = std::min( lineAnchorPoint - labelWidth, totalLineLength * 0.99 - labelWidth );
|
||||
break;
|
||||
case QgsLabelLineSettings::AnchorTextPoint::FollowPlacement:
|
||||
// not possible here
|
||||
break;
|
||||
}
|
||||
lineStepDistance = -1;
|
||||
break;
|
||||
@ -1212,7 +1227,7 @@ std::size_t FeaturePart::createCandidatesAlongLineNearMidpoint( std::vector< std
|
||||
|
||||
// penalize positions which are further from the line's anchor point
|
||||
double textAnchorPoint = 0;
|
||||
switch ( mLF->lineAnchorTextPoint() )
|
||||
switch ( textPoint )
|
||||
{
|
||||
case QgsLabelLineSettings::AnchorTextPoint::StartOfText:
|
||||
textAnchorPoint = currentDistanceAlongLine;
|
||||
@ -1223,6 +1238,9 @@ std::size_t FeaturePart::createCandidatesAlongLineNearMidpoint( std::vector< std
|
||||
case QgsLabelLineSettings::AnchorTextPoint::EndOfText:
|
||||
textAnchorPoint = currentDistanceAlongLine + labelWidth;
|
||||
break;
|
||||
case QgsLabelLineSettings::AnchorTextPoint::FollowPlacement:
|
||||
// not possible here
|
||||
break;
|
||||
}
|
||||
double costCenter = std::fabs( lineAnchorPoint - textAnchorPoint ) / totalLineLength; // <0, 0.5>
|
||||
cost += costCenter / 1000; // < 0, 0.0005 >
|
||||
@ -1482,16 +1500,19 @@ std::size_t FeaturePart::createCurvedCandidatesAlongLine( std::vector< std::uniq
|
||||
break;
|
||||
|
||||
case QgsLabelLineSettings::AnchorType::Strict:
|
||||
switch ( mLF->lineAnchorTextPoint() )
|
||||
switch ( textPoint )
|
||||
{
|
||||
case QgsLabelLineSettings::AnchorTextPoint::StartOfText:
|
||||
distanceAlongLineToStartCandidate = std::clamp( lineAnchorPoint, 0.0, totalDistance * 0.99 );
|
||||
distanceAlongLineToStartCandidate = std::clamp( lineAnchorPoint, 0.0, totalDistance * 0.999 );
|
||||
break;
|
||||
case QgsLabelLineSettings::AnchorTextPoint::CenterOfText:
|
||||
distanceAlongLineToStartCandidate = std::clamp( lineAnchorPoint - getLabelWidth() / 2, 0.0, totalDistance * 0.99 - getLabelWidth() );
|
||||
distanceAlongLineToStartCandidate = std::clamp( lineAnchorPoint - getLabelWidth() / 2, 0.0, totalDistance * 0.999 - getLabelWidth() / 2 );
|
||||
break;
|
||||
case QgsLabelLineSettings::AnchorTextPoint::EndOfText:
|
||||
distanceAlongLineToStartCandidate = std::clamp( lineAnchorPoint - getLabelWidth(), 0.0, totalDistance * 0.99 ) ;
|
||||
distanceAlongLineToStartCandidate = std::clamp( lineAnchorPoint - getLabelWidth(), 0.0, totalDistance * 0.999 - getLabelWidth() ) ;
|
||||
break;
|
||||
case QgsLabelLineSettings::AnchorTextPoint::FollowPlacement:
|
||||
// not possible here
|
||||
break;
|
||||
}
|
||||
singleCandidateOnly = true;
|
||||
@ -1553,7 +1574,7 @@ std::size_t FeaturePart::createCurvedCandidatesAlongLine( std::vector< std::uniq
|
||||
|
||||
// penalize positions which are further from the line's anchor point
|
||||
double labelTextAnchor = 0;
|
||||
switch ( mLF->lineAnchorTextPoint() )
|
||||
switch ( textPoint )
|
||||
{
|
||||
case QgsLabelLineSettings::AnchorTextPoint::StartOfText:
|
||||
labelTextAnchor = distanceAlongLineToStartCandidate;
|
||||
@ -1564,6 +1585,9 @@ std::size_t FeaturePart::createCurvedCandidatesAlongLine( std::vector< std::uniq
|
||||
case QgsLabelLineSettings::AnchorTextPoint::EndOfText:
|
||||
labelTextAnchor = distanceAlongLineToStartCandidate + getLabelWidth();
|
||||
break;
|
||||
case QgsLabelLineSettings::AnchorTextPoint::FollowPlacement:
|
||||
// not possible here
|
||||
break;
|
||||
}
|
||||
double costCenter = std::fabs( lineAnchorPoint - labelTextAnchor ) / totalDistance; // <0, 0.5>
|
||||
cost += costCenter / ( anchorIsFlexiblePlacement ? 100 : 10 ); // < 0, 0.005 >, or <0, 0.05> if preferring placement close to start/end of line
|
||||
|
||||
@ -36,6 +36,7 @@ QgsLabelLineAnchorWidget::QgsLabelLineAnchorWidget( QWidget *parent, QgsVectorLa
|
||||
mAnchorTypeComboBox->addItem( tr( "Preferred Placement Hint" ), static_cast< int >( QgsLabelLineSettings::AnchorType::HintOnly ) );
|
||||
mAnchorTypeComboBox->addItem( tr( "Strict" ), static_cast< int >( QgsLabelLineSettings::AnchorType::Strict ) );
|
||||
|
||||
mAnchorTextPointComboBox->addItem( tr( "Automatic" ), static_cast< int >( QgsLabelLineSettings::AnchorTextPoint::FollowPlacement ) );
|
||||
mAnchorTextPointComboBox->addItem( tr( "Start of Text" ), static_cast< int >( QgsLabelLineSettings::AnchorTextPoint::StartOfText ) );
|
||||
mAnchorTextPointComboBox->addItem( tr( "Center of Text" ), static_cast< int >( QgsLabelLineSettings::AnchorTextPoint::CenterOfText ) );
|
||||
mAnchorTextPointComboBox->addItem( tr( "End of Text" ), static_cast< int >( QgsLabelLineSettings::AnchorTextPoint::EndOfText ) );
|
||||
@ -170,6 +171,9 @@ void QgsLabelLineAnchorWidget::updateAnchorTextPointHint()
|
||||
case QgsLabelLineSettings::AnchorTextPoint::EndOfText:
|
||||
hint = tr( "Labels are placed so that the end of their text is placed at the anchor point." );
|
||||
break;
|
||||
case QgsLabelLineSettings::AnchorTextPoint::FollowPlacement:
|
||||
hint = tr( "The text justification is determined based on the anchor point. Anchors close to the start of the line will use the start of the text, anchors close to the end will use the end of the text, and central values will use the center of the text." );
|
||||
break;
|
||||
}
|
||||
mAnchorTextPointHintLabel->setText( hint );
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user