191 changes: 57 additions & 134 deletions src/core/qgspallabeling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -701,25 +701,6 @@ void QgsPalLayerSettings::registerFeature( QgsVectorLayer* layer, QgsFeature& f
}
}

// convert centroids to points before processing to use GEOS instead of PAL calculation
if ( centroidPoly )
{
QgsGeometry* centroidpt = geom->centroid();
if ( centroidpt->isGeosValid() && extentGeom->contains( centroidpt ) )
{
geom = QgsGeometry::fromPoint( centroidpt->asPoint() );
if ( geom->type() == QGis::Point )
{
QgsDebugMsg( QString( "Feature %1 centroid converted to point: " ).arg( f.id() ) );
}
}
else
{
// invalid geom type or outside extents
return;
}
}

GEOSGeometry* geos_geom = geom->asGeos();

if ( geos_geom == NULL )
Expand All @@ -730,17 +711,56 @@ void QgsPalLayerSettings::registerFeature( QgsVectorLayer* layer, QgsFeature& f
//data defined position / alignment / rotation?
bool dataDefinedPosition = false;
bool labelIsPinned = false;
bool layerDefinedRotation = false;
bool dataDefinedRotation = false;
double xPos = 0.0, yPos = 0.0, angle = 0.0;
bool ddXPos = false, ddYPos = false;
double quadOffsetX = 0.0, quadOffsetY = 0.0;
double offsetX = 0.0, offsetY = 0.0;

// adjust quadrant offset of labels
if ( xQuadOffset != 0 )
{
quadOffsetX = xQuadOffset;
}
if ( yQuadOffset != 0 )
{
quadOffsetY = yQuadOffset;
}

// adjust offset of labels to match chosen unit and map scale
double mapUntsPerMM = context.mapToPixel().mapUnitsPerPixel() * context.scaleFactor();
if ( xOffset != 0 )
{
offsetX = xOffset;
if ( !labelOffsetInMapUnits )
{
offsetX = xOffset * mapUntsPerMM; //convert offset from mm to map units
}
}
if ( yOffset != 0 )
{
offsetY = yOffset;
if ( !labelOffsetInMapUnits )
{
offsetY = yOffset * mapUntsPerMM; //convert offset from mm to map units
}
}

// layer defined rotation?
// only rotate non-pinned OverPoint placements until other placements are supported in pal::Feature
if ( placement == QgsPalLayerSettings::OverPoint && angleOffset != 0 )
{
layerDefinedRotation = true;
angle = angleOffset * M_PI / 180; // convert to radians
}

//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.0;

}

QMap< DataDefinedProperties, int >::const_iterator dPosXIt = dataDefinedProperties.find( QgsPalLayerSettings::PositionX );
Expand All @@ -757,13 +777,19 @@ void QgsPalLayerSettings::registerFeature( QgsVectorLayer* layer, QgsFeature& f
{
dataDefinedPosition = true;
labelIsPinned = true;
// layer rotation set, but don't rotate pinned labels unless data defined
if ( layerDefinedRotation && !dataDefinedRotation )
{
angle = 0.0;
}

//x/y shift in case of alignment
double xdiff = 0.0;
double ydiff = 0.0;

//horizontal alignment
QMap< DataDefinedProperties, int >::const_iterator haliIt = dataDefinedProperties.find( QgsPalLayerSettings::Hali );
if ( haliIt != dataDefinedProperties.end() )
if ( haliIt != dataDefinedProperties.constEnd() )
{
QString haliString = f.attributeMap().value( *haliIt ).toString();
if ( haliString.compare( "Center", Qt::CaseInsensitive ) == 0 )
Expand Down Expand Up @@ -824,55 +850,17 @@ void QgsPalLayerSettings::registerFeature( QgsVectorLayer* layer, QgsFeature& f
xPos += xdiff;
yPos += ydiff;
}
else
{
// only rotate non-pinned OverPoint placements until other placements are supported in pal::Feature
if ( dataDefinedRotation && placement != QgsPalLayerSettings::OverPoint )
{
angle = 0.0;
}
}
}
}

// treat rotated labels of PAL layer point/centroid features as data defined
// does not flag label as pinned or rotateable
// always set rotation center as if Center/Half were set for data defined
bool overPointCentroid = false;
if ( !labelIsPinned
&& placement == QgsPalLayerSettings::OverPoint
&& geom->type() == QGis::Point )
{
overPointCentroid = true;
dataDefinedPosition = true;

QgsPoint fPt = geom->asPoint();
// default reference (feature) point is lower left corner of label bounding box
xPos = fPt.x();
yPos = fPt.y();

double xdiff = 0.0;
double ydiff = 0.0;

// as per Center for data defined
xdiff -= labelX / 2.0;

// as per Half for data defined
QFontMetrics labelFontMetrics( labelFont );
double descentRatio = labelFontMetrics.descent() / labelFontMetrics.height();
ydiff -= labelY * 0.5 * ( 1 - descentRatio );

if ( !dataDefinedRotation && angleOffset != 0 )
{
dataDefinedRotation = true;
angle = angleOffset * M_PI / 180; // convert to radians
}

if ( dataDefinedRotation )
{
//adjust xdiff and ydiff for Center/Half
double xd = xdiff * cos( angle ) - ydiff * sin( angle );
double yd = xdiff * sin( angle ) + ydiff * cos( angle );
xdiff = xd;
ydiff = yd;
}

xPos += xdiff;
yPos += ydiff;
}

QgsPalGeometry* lbl = new QgsPalGeometry( f.id(), labelText, geos_geom_clone );

// record the created geometry - it will be deleted at the end.
Expand All @@ -882,7 +870,8 @@ void QgsPalLayerSettings::registerFeature( QgsVectorLayer* layer, QgsFeature& f
try
{
if ( !palLayer->registerFeature( lbl->strId(), lbl, labelX, labelY, labelText.toUtf8().constData(),
xPos, yPos, dataDefinedPosition, angle, dataDefinedRotation ) )
xPos, yPos, dataDefinedPosition, angle, dataDefinedRotation,
quadOffsetX, quadOffsetY, offsetX, offsetY ) )
return;
}
catch ( std::exception &e )
Expand Down Expand Up @@ -919,72 +908,6 @@ void QgsPalLayerSettings::registerFeature( QgsVectorLayer* layer, QgsFeature& f
feat->setDistLabel( qAbs( ptOne.x() - ptZero.x() )* distance );
}

// treat offset labels of PAL layer point/centroid features as data defined
// does not flag label as pinned
// done after feature registration so label W and H are relative to any applied rotation
if ( overPointCentroid )
{
double labelW = labelX;
double labelH = labelY;

if ( dataDefinedRotation )
{
// use LabelPosition construction to calculate new rotated label dimensions
pal::FeaturePart* fpart = new FeaturePart( feat, geom->asGeos() );
pal::LabelPosition* lp = new LabelPosition( 1, xPos, yPos, labelX, labelY, angle, 0.0, fpart );

// lp->getWidth or lp->getHeight doesn't account for rotation, get bbox instead
double amin[2], amax[2];
lp->getBoundingBox( amin, amax );
QgsRectangle lblrect = QgsRectangle( amin[0], amin[1], amax[0], amax[1] );

labelW = lblrect.width();
labelH = lblrect.height();
delete fpart;
delete lp;
}

// x/y shift in case of alignment other than center
double xdiff = 0.0;
double ydiff = 0.0;

// quadrant offsets are -1, 0, or 1 (positive is up and right)
if ( xQuadOffset != 0 )
{
xdiff += labelW / 2 * xQuadOffset;
}
if ( yQuadOffset != 0 )
{
ydiff += labelH / 2 * yQuadOffset;
}

double mapUntsPerMM = context.mapToPixel().mapUnitsPerPixel() * context.scaleFactor();

if ( xOffset != 0 )
{
double xoff = xOffset;
if ( !labelOffsetInMapUnits ) //convert offset from mm to map units
{
xoff = xOffset * mapUntsPerMM;
}
xdiff += xoff;
}

if ( yOffset != 0 )
{
double yoff = yOffset;
if ( !labelOffsetInMapUnits ) //convert offset from mm to map units
{
yoff = yOffset * mapUntsPerMM;
}
ydiff += yoff;
}

xPos += xdiff;
yPos += ydiff;
feat->setFixedPosition( xPos, yPos );
}

//add parameters for data defined labeling to QgsPalGeometry
QMap< DataDefinedProperties, int >::const_iterator dIt = dataDefinedProperties.constBegin();
for ( ; dIt != dataDefinedProperties.constEnd(); ++dIt )
Expand Down