Skip to content

Commit

Permalink
Merge pull request #44944 from domi4484/labelUsabilityImprovements
Browse files Browse the repository at this point in the history
Make rotate label tool work with label not pinned or dd moved fix #43967
  • Loading branch information
m-kuhn authored Sep 17, 2021
2 parents 850215f + c0a9b04 commit f79e62e
Show file tree
Hide file tree
Showing 10 changed files with 45 additions and 72 deletions.
12 changes: 2 additions & 10 deletions src/app/labeling/qgsmaptoollabel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ void QgsMapToolLabel::createRubberBands()

//fixpoint rubber band
QgsPointXY fixPoint;
if ( currentLabelRotationPoint( fixPoint, false, false ) )
if ( currentLabelRotationPoint( fixPoint, false ) )
{
if ( mCanvas )
{
Expand Down Expand Up @@ -389,7 +389,7 @@ bool QgsMapToolLabel::currentLabelPreserveRotation()
return true; // default, so there is no accidental data loss
}

bool QgsMapToolLabel::currentLabelRotationPoint( QgsPointXY &pos, bool ignoreUpsideDown, bool rotatingUnpinned )
bool QgsMapToolLabel::currentLabelRotationPoint( QgsPointXY &pos, bool ignoreUpsideDown )
{
QVector<QgsPointXY> cornerPoints = mCurrentLabel.pos.cornerPoints;
if ( cornerPoints.size() < 4 )
Expand Down Expand Up @@ -418,14 +418,6 @@ bool QgsMapToolLabel::currentLabelRotationPoint( QgsPointXY &pos, bool ignoreUps
QString haliString, valiString;
currentAlignment( haliString, valiString );

// rotate unpinned labels (i.e. no hali/vali settings) as if hali/vali was Center/Half
if ( rotatingUnpinned )
{
haliString = QStringLiteral( "Center" );
valiString = QStringLiteral( "Half" );
}

// QFont labelFont = labelFontCurrentFeature();
QFontMetricsF labelFontMetrics( mCurrentLabel.pos.labelFont );

// NOTE: this assumes the label corner points comprise a rectangle and that the
Expand Down
2 changes: 1 addition & 1 deletion src/app/labeling/qgsmaptoollabel.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ class APP_EXPORT QgsMapToolLabel: public QgsMapToolAdvancedDigitizing
* \param ignoreUpsideDown treat label as right-side-up
* \returns TRUE in case of success
*/
bool currentLabelRotationPoint( QgsPointXY &pos, bool ignoreUpsideDown = false, bool rotatingUnpinned = false );
bool currentLabelRotationPoint( QgsPointXY &pos, bool ignoreUpsideDown = false );

//! Creates label / feature / fixpoint rubber bands for the current label position
void createRubberBands();
Expand Down
3 changes: 1 addition & 2 deletions src/app/labeling/qgsmaptoolmovelabel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ void QgsMapToolMoveLabel::cadCanvasPressEvent( QgsMapMouseEvent *e )
if ( !labelAtPosition( e, labelPos ) )
{
mCurrentLabel = LabelDetails();

return;
}

Expand Down Expand Up @@ -241,7 +240,7 @@ void QgsMapToolMoveLabel::cadCanvasPressEvent( QgsMapMouseEvent *e )

mStartPointMapCoords = e->mapPoint();
QgsPointXY referencePoint;
if ( !currentLabelRotationPoint( referencePoint, !currentLabelPreserveRotation(), false ) )
if ( !currentLabelRotationPoint( referencePoint, !currentLabelPreserveRotation() ) )
{
referencePoint.setX( mCurrentLabel.pos.labelRect.xMinimum() );
referencePoint.setY( mCurrentLabel.pos.labelRect.yMinimum() );
Expand Down
2 changes: 1 addition & 1 deletion src/app/labeling/qgsmaptoolpinlabels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ bool QgsMapToolPinLabels::pinUnpinCurrentLabel( bool pin )
// QgsPointXY labelpoint = labelpos.cornerPoints.at( 0 );

QgsPointXY referencePoint;
if ( !currentLabelRotationPoint( referencePoint, !preserveRot, false ) )
if ( !currentLabelRotationPoint( referencePoint, !preserveRot ) )
{
referencePoint.setX( labelpos.labelRect.xMinimum() );
referencePoint.setY( labelpos.labelRect.yMinimum() );
Expand Down
25 changes: 2 additions & 23 deletions src/app/labeling/qgsmaptoolrotatelabel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,19 +104,9 @@ void QgsMapToolRotateLabel::canvasPressEvent( QgsMapMouseEvent *e )
if ( !mCurrentLabel.valid )
return;

// only rotate non-pinned OverPoint placements until other placements are supported in pal::Feature

if ( !mCurrentLabel.pos.isPinned
&& mCurrentLabel.settings.placement != QgsPalLayerSettings::OverPoint )
{
return;
}

// rotate unpinned labels (i.e. no hali/vali settings) as if hali/vali was Center/Half
if ( !currentLabelRotationPoint( mRotationPoint, false, !mCurrentLabel.pos.isPinned ) )
{
// Get label rotation point
if ( !currentLabelRotationPoint( mRotationPoint, false ) )
return;
}

{
mCurrentMouseAzimuth = convertAzimuth( mRotationPoint.azimuth( toMapCoordinates( e->pos() ) ) );
Expand Down Expand Up @@ -295,17 +285,6 @@ void QgsMapToolRotateLabel::keyReleaseEvent( QKeyEvent *e )
}
}

bool QgsMapToolRotateLabel::canModifyLabel( const QgsMapToolLabel::LabelDetails &label )
{
// only rotate non-pinned OverPoint placements until other placements are supported in pal::Feature

if ( !label.pos.isPinned
&& label.settings.placement != QgsPalLayerSettings::OverPoint )
return false;

return true;
}

int QgsMapToolRotateLabel::roundTo15Degrees( double n )
{
const int m = static_cast< int >( n / 15.0 + 0.5 );
Expand Down
2 changes: 0 additions & 2 deletions src/app/labeling/qgsmaptoolrotatelabel.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ class APP_EXPORT QgsMapToolRotateLabel: public QgsMapToolLabel

protected:

bool canModifyLabel( const LabelDetails &label ) override;

static int roundTo15Degrees( double n );
//! Converts azimuth value so that 0 is corresponds to East
static double convertAzimuth( double a );
Expand Down
13 changes: 1 addition & 12 deletions src/core/labeling/qgspallabeling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2331,8 +2331,7 @@ std::unique_ptr<QgsLabelFeature> QgsPalLayerSettings::registerFeatureWithDetails
offsetY = context.convertToMapUnits( -yOff, offUnit, labelOffsetMapUnitScale );

// layer defined rotation?
// only rotate non-pinned OverPoint placements until other placements are supported in pal::Feature
if ( placement == QgsPalLayerSettings::OverPoint && !qgsDoubleNear( angleOffset, 0.0 ) )
if ( !qgsDoubleNear( angleOffset, 0.0 ) )
{
layerDefinedRotation = true;
angle = ( 360 - angleOffset ) * M_PI / 180; // convert to radians counterclockwise
Expand Down Expand Up @@ -2475,16 +2474,6 @@ std::unique_ptr<QgsLabelFeature> QgsPalLayerSettings::registerFeatureWithDetails
xPos += xdiff;
yPos += ydiff;
}
else
{
anchorPosition = QgsPointXY( xPos, yPos );

// only rotate non-pinned OverPoint placements until other placements are supported in pal::Feature
if ( dataDefinedRotation && placement != QgsPalLayerSettings::OverPoint )
{
angle = 0.0;
}
}
}
}
}
Expand Down
58 changes: 37 additions & 21 deletions src/core/pal/feature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,11 +430,12 @@ std::unique_ptr<LabelPosition> FeaturePart::createCandidatePointOnSurface( Point
return std::make_unique< LabelPosition >( 0, px, py, getLabelWidth(), getLabelHeight(), 0.0, 0.0, this, false, LabelPosition::QuadrantOver );
}

void createCandidateAtOrderedPositionOverPoint( double &labelX, double &labelY, LabelPosition::Quadrant &quadrant, double x, double y, double labelWidth, double labelHeight, QgsPalLayerSettings::PredefinedPointPosition position, double distanceToLabel, const QgsMargins &visualMargin, double symbolWidthOffset, double symbolHeightOffset )
void createCandidateAtOrderedPositionOverPoint( double &labelX, double &labelY, LabelPosition::Quadrant &quadrant, double x, double y, double labelWidth, double labelHeight, QgsPalLayerSettings::PredefinedPointPosition position, double distanceToLabel, const QgsMargins &visualMargin, double symbolWidthOffset, double symbolHeightOffset, double angle )
{
double alpha = 0.0;
double deltaX = 0;
double deltaY = 0;

switch ( position )
{
case QgsPalLayerSettings::TopLeft:
Expand Down Expand Up @@ -522,6 +523,12 @@ void createCandidateAtOrderedPositionOverPoint( double &labelX, double &labelY,
break;
}

// Take care of the label angle when creating candidates. See pr comments #44944 for details
// https://github.com/qgis/QGIS/pull/44944#issuecomment-914670088
QTransform transformRotation;
transformRotation.rotate( angle * 180 / M_PI );
transformRotation.map( deltaX, deltaY, &deltaX, &deltaY );

//have bearing, distance - calculate reference point
double referenceX = std::cos( alpha ) * distanceToLabel + x;
double referenceY = std::sin( alpha ) * distanceToLabel + y;
Expand Down Expand Up @@ -552,7 +559,7 @@ std::size_t FeaturePart::createCandidatesAtOrderedPositionsOverPoint( double x,

double labelX = 0;
double labelY = 0;
createCandidateAtOrderedPositionOverPoint( labelX, labelY, quadrant, x, y, labelWidth, labelHeight, position, distanceToLabel, visualMargin, symbolWidthOffset, symbolHeightOffset );
createCandidateAtOrderedPositionOverPoint( labelX, labelY, quadrant, x, y, labelWidth, labelHeight, position, distanceToLabel, visualMargin, symbolWidthOffset, symbolHeightOffset, angle );

if ( ! mLF->permissibleZonePrepared() || GeomFunction::containsCandidate( mLF->permissibleZonePrepared(), labelX, labelY, labelWidth, labelHeight, angle ) )
{
Expand Down Expand Up @@ -615,8 +622,8 @@ std::size_t FeaturePart::createCandidatesAroundPoint( double x, double y, std::v
double angleToCandidate;
for ( i = 0, angleToCandidate = M_PI_4; i < maxNumberCandidates; i++, angleToCandidate += candidateAngleIncrement )
{
double labelX = x;
double labelY = y;
double deltaX = 0.0;
double deltaY = 0.0;

if ( angleToCandidate > a360 )
angleToCandidate -= a360;
Expand All @@ -625,62 +632,71 @@ std::size_t FeaturePart::createCandidatesAroundPoint( double x, double y, std::v

if ( angleToCandidate < gamma1 || angleToCandidate > a360 - gamma1 ) // on the right
{
labelX += distanceToLabel;
deltaX = distanceToLabel;
double iota = ( angleToCandidate + gamma1 );
if ( iota > a360 - gamma1 )
iota -= a360;

//ly += -yrm/2.0 + tan(alpha)*(distlabel + xrm/2);
labelY += -labelHeight + labelHeight * iota / ( 2 * gamma1 );
deltaY = -labelHeight + labelHeight * iota / ( 2 * gamma1 );

quadrant = LabelPosition::QuadrantRight;
}
else if ( angleToCandidate < a90 - gamma2 ) // top-right
{
labelX += distanceToLabel * std::cos( angleToCandidate );
labelY += distanceToLabel * std::sin( angleToCandidate );
deltaX = distanceToLabel * std::cos( angleToCandidate );
deltaY = distanceToLabel * std::sin( angleToCandidate );
quadrant = LabelPosition::QuadrantAboveRight;
}
else if ( angleToCandidate < a90 + gamma2 ) // top
{
//lx += -xrm/2.0 - tan(alpha+a90)*(distlabel + yrm/2);
labelX += -labelWidth * ( angleToCandidate - a90 + gamma2 ) / ( 2 * gamma2 );
labelY += distanceToLabel;
deltaX = -labelWidth * ( angleToCandidate - a90 + gamma2 ) / ( 2 * gamma2 );
deltaY = distanceToLabel;
quadrant = LabelPosition::QuadrantAbove;
}
else if ( angleToCandidate < a180 - gamma1 ) // top left
{
labelX += distanceToLabel * std::cos( angleToCandidate ) - labelWidth;
labelY += distanceToLabel * std::sin( angleToCandidate );
deltaX = distanceToLabel * std::cos( angleToCandidate ) - labelWidth;
deltaY = distanceToLabel * std::sin( angleToCandidate );
quadrant = LabelPosition::QuadrantAboveLeft;
}
else if ( angleToCandidate < a180 + gamma1 ) // left
{
labelX += -distanceToLabel - labelWidth;
deltaX = -distanceToLabel - labelWidth;
//ly += -yrm/2.0 - tan(alpha)*(distlabel + xrm/2);
labelY += - ( angleToCandidate - a180 + gamma1 ) * labelHeight / ( 2 * gamma1 );
deltaY = - ( angleToCandidate - a180 + gamma1 ) * labelHeight / ( 2 * gamma1 );
quadrant = LabelPosition::QuadrantLeft;
}
else if ( angleToCandidate < a270 - gamma2 ) // down - left
{
labelX += distanceToLabel * std::cos( angleToCandidate ) - labelWidth;
labelY += distanceToLabel * std::sin( angleToCandidate ) - labelHeight;
deltaX = distanceToLabel * std::cos( angleToCandidate ) - labelWidth;
deltaY = distanceToLabel * std::sin( angleToCandidate ) - labelHeight;
quadrant = LabelPosition::QuadrantBelowLeft;
}
else if ( angleToCandidate < a270 + gamma2 ) // down
{
labelY += -distanceToLabel - labelHeight;
deltaY = -distanceToLabel - labelHeight;
//lx += -xrm/2.0 + tan(alpha+a90)*(distlabel + yrm/2);
labelX += -labelWidth + ( angleToCandidate - a270 + gamma2 ) * labelWidth / ( 2 * gamma2 );
deltaX = -labelWidth + ( angleToCandidate - a270 + gamma2 ) * labelWidth / ( 2 * gamma2 );
quadrant = LabelPosition::QuadrantBelow;
}
else if ( angleToCandidate < a360 ) // down - right
{
labelX += distanceToLabel * std::cos( angleToCandidate );
labelY += distanceToLabel * std::sin( angleToCandidate ) - labelHeight;
deltaX = distanceToLabel * std::cos( angleToCandidate );
deltaY = distanceToLabel * std::sin( angleToCandidate ) - labelHeight;
quadrant = LabelPosition::QuadrantBelowRight;
}

// Take care of the label angle when creating candidates. See pr comments #44944 for details
// https://github.com/qgis/QGIS/pull/44944#issuecomment-914670088
QTransform transformRotation;
transformRotation.rotate( angle * 180 / M_PI );
transformRotation.map( deltaX, deltaY, &deltaX, &deltaY );

double labelX = x + deltaX;
double labelY = y + deltaY;

double cost;

if ( maxNumberCandidates == 1 )
Expand Down Expand Up @@ -1826,7 +1842,7 @@ std::size_t FeaturePart::createCandidatesOutsidePolygon( std::vector<std::unique
LabelPosition::Quadrant quadrant = LabelPosition::QuadrantAboveLeft;

// Satisfy R2: Label should be placed entirely outside at some distance from the area feature.
createCandidateAtOrderedPositionOverPoint( labelX, labelY, quadrant, x, y, labelWidth, labelHeight, position, distanceToLabel * 0.5, visualMargin, 0, 0 );
createCandidateAtOrderedPositionOverPoint( labelX, labelY, quadrant, x, y, labelWidth, labelHeight, position, distanceToLabel * 0.5, visualMargin, 0, 0, labelAngle );

std::unique_ptr< LabelPosition > candidate = std::make_unique< LabelPosition >( i, labelX, labelY, labelWidth, labelHeight, labelAngle, 0, this, false, quadrant );
if ( candidate->intersects( preparedBuffer.get() ) )
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit f79e62e

Please sign in to comment.