Skip to content

Commit

Permalink
Merge pull request #33161 from m-kuhn/dxf_export_quadrant_based
Browse files Browse the repository at this point in the history
Respect placement quadrant in DXF export
  • Loading branch information
m-kuhn committed Dec 5, 2019
2 parents c01f804 + 2bd4689 commit 2f5d210
Show file tree
Hide file tree
Showing 5 changed files with 256 additions and 4 deletions.
59 changes: 58 additions & 1 deletion src/core/dxf/qgsdxfexport.cpp
Expand Up @@ -1269,6 +1269,63 @@ void QgsDxfExport::writeText( const QString &layer, const QString &text, pal::La
VAlign vali = VAlign::Undefined;

const QgsPropertyCollection &props = layerSettings.dataDefinedProperties();

if ( props.isActive( QgsPalLayerSettings::OffsetQuad ) )
{
const QVariant exprVal = props.value( QgsPalLayerSettings::OffsetQuad, expressionContext );
if ( exprVal.isValid() )
{
int offsetQuad = exprVal.toInt();

lblX -= label->dX();
lblY -= label->dY();

switch ( offsetQuad )
{
case 0: // Above Left
hali = HAlign::HRight;
vali = VAlign::VBottom;
break;
case 1: // Above
hali = HAlign::HCenter;
vali = VAlign::VBottom;
break;
case 2: // Above Right
hali = HAlign::HLeft;
vali = VAlign::VBottom;
break;
case 3: // Left
hali = HAlign::HRight;
vali = VAlign::VMiddle;
break;
case 4: // Over
hali = HAlign::HCenter;
vali = VAlign::VMiddle;
break;
case 5: // Right
hali = HAlign::HLeft;
vali = VAlign::VMiddle;
break;
case 6: // Below Left
hali = HAlign::HRight;
vali = VAlign::VTop;
break;
case 7: // Below
hali = HAlign::HCenter;
vali = VAlign::VTop;
break;
case 8: // Below Right
hali = HAlign::HLeft;
vali = VAlign::VTop;
break;
default: // OverHali
hali = HAlign::HCenter;
vali = VAlign::VTop;
break;
}
}
}

if ( props.isActive( QgsPalLayerSettings::Hali ) )
{
hali = HAlign::HLeft;
Expand Down Expand Up @@ -1403,7 +1460,7 @@ void QgsDxfExport::writeText( const QString &layer, const QString &text, const Q
writeGroup( 1, pt ); // Second alignment point
writeGroup( 40, size );
writeGroup( 1, text );
writeGroup( 50, angle );
writeGroup( 50, fmod( angle, 360 ) );
if ( hali != HAlign::Undefined )
writeGroup( 72, static_cast<int>( hali ) );
writeGroup( 7, QStringLiteral( "STANDARD" ) ); // so far only support for standard font
Expand Down
2 changes: 1 addition & 1 deletion src/core/pal/feature.cpp
Expand Up @@ -310,7 +310,7 @@ std::size_t FeaturePart::createCandidatesOverPoint( double x, double y, std::vec
}
}

lPos.emplace_back( qgis::make_unique< LabelPosition >( id, lx, ly, labelW, labelH, angle, cost, this, false, quadrantFromOffset() ) );
lPos.emplace_back( qgis::make_unique< LabelPosition >( id, lx, ly, labelW, labelH, angle, cost, this, false, quadrantFromOffset(), xdiff, ydiff ) );
return nbp;
}

Expand Down
16 changes: 15 additions & 1 deletion src/core/pal/labelposition.cpp
Expand Up @@ -40,7 +40,7 @@

using namespace pal;

LabelPosition::LabelPosition( int id, double x1, double y1, double w, double h, double alpha, double cost, FeaturePart *feature, bool isReversed, Quadrant quadrant )
LabelPosition::LabelPosition( int id, double x1, double y1, double w, double h, double alpha, double cost, FeaturePart *feature, bool isReversed, Quadrant quadrant, double dX, double dY )
: id( id )
, feature( feature )
, probFeat( 0 )
Expand All @@ -55,6 +55,8 @@ LabelPosition::LabelPosition( int id, double x1, double y1, double w, double h,
, mCost( cost )
, mHasObstacleConflict( false )
, mUpsideDownCharCount( 0 )
, mDx( dX )
, mDy( dY )
{
type = GEOS_POLYGON;
nbPoints = 4;
Expand Down Expand Up @@ -160,6 +162,8 @@ LabelPosition::LabelPosition( const LabelPosition &other )
quadrant = other.quadrant;
mHasObstacleConflict = other.mHasObstacleConflict;
mUpsideDownCharCount = other.mUpsideDownCharCount;
mDx = other.mDx;
mDy = other.mDy;
}

bool LabelPosition::isIn( double *bbox )
Expand Down Expand Up @@ -319,6 +323,16 @@ bool LabelPosition::isInConflictMultiPart( LabelPosition *lp )
return false; // no conflict found
}

double LabelPosition::dY() const
{
return mDy;
}

double LabelPosition::dX() const
{
return mDx;
}

int LabelPosition::partCount() const
{
if ( nextPart )
Expand Down
21 changes: 20 additions & 1 deletion src/core/pal/labelposition.h
Expand Up @@ -88,11 +88,14 @@ namespace pal
* \param feature labelpos owners
* \param isReversed label is reversed
* \param quadrant relative position of label to feature
* \param dX the correction of the anchor point in x direction
* \param dY the correction of the anchor point in y direction
*/
LabelPosition( int id, double x1, double y1,
double w, double h,
double alpha, double cost,
FeaturePart *feature, bool isReversed = false, Quadrant quadrant = QuadrantOver );
FeaturePart *feature, bool isReversed = false, Quadrant quadrant = QuadrantOver,
double dX = 0.0, double dY = 0.0 );

//! Copy constructor
LabelPosition( const LabelPosition &other );
Expand Down Expand Up @@ -312,6 +315,20 @@ namespace pal
// for polygon cost calculation
static bool polygonObstacleCallback( pal::FeaturePart *obstacle, void *ctx );

/**
* The offset of the anchor point in x direction.
*
* \since QGIS 3.12
*/
double dX() const;

/**
* The offset of the anchor point in y direction.
*
* \since QGIS 3.12
*/
double dY() const;

protected:

int id;
Expand Down Expand Up @@ -347,6 +364,8 @@ namespace pal
bool mHasObstacleConflict;
bool mHasHardConflict = false;
int mUpsideDownCharCount;
double mDx = 0.0;
double mDy = 0.0;

/**
* Calculates the total number of parts for this label position
Expand Down
162 changes: 162 additions & 0 deletions tests/src/core/testqgsdxfexport.cpp
Expand Up @@ -56,6 +56,8 @@ class TestQgsDxfExport : public QObject
void testTextAngle();
void testTextAlign();
void testTextAlign_data();
void testTextQuadrant();
void testTextQuadrant_data();
void testGeometryGeneratorExport();
void testCurveExport();
void testCurveExport_data();
Expand Down Expand Up @@ -687,6 +689,166 @@ void TestQgsDxfExport::testTextAlign_data()
<< QStringLiteral( "Half" );
}

void TestQgsDxfExport::testTextQuadrant()
{
QFETCH( int, offsetQuad );
QFETCH( QgsDxfExport::HAlign, dxfHali );
QFETCH( QgsDxfExport::VAlign, dxfVali );
QFETCH( double, angle );

QgsPalLayerSettings settings;
settings.fieldName = QStringLiteral( "text" );

QgsPropertyCollection props = settings.dataDefinedProperties();
QgsProperty offsetQuadProp = QgsProperty();
offsetQuadProp.setStaticValue( offsetQuad );
props.setProperty( QgsPalLayerSettings::OffsetQuad, offsetQuadProp );
props.setProperty( QgsPalLayerSettings::Property::LabelRotation, angle );
settings.setDataDefinedProperties( props );

QgsTextFormat format;
format.setFont( QgsFontUtils::getStandardTestFont( QStringLiteral( "Bold" ) ).family() );
format.setSize( 12 );
format.setNamedStyle( QStringLiteral( "Bold" ) );
format.setColor( QColor( 200, 0, 200 ) );
settings.setFormat( format );

std::unique_ptr< QgsVectorLayer > vl = qgis::make_unique< QgsVectorLayer >( QStringLiteral( "Point?crs=epsg:2056&field=text:string" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) );
QgsGeometry g = QgsGeometry::fromWkt( "Point(2685025.687 1292145.297)" );
QgsFeature f( vl->fields() );
f.setGeometry( g );
f.setAttribute( 0, QStringLiteral( "182" ) );

vl->dataProvider()->addFeatures( QgsFeatureList() << f );
vl->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) );
vl->setLabelsEnabled( true );

QgsMapSettings mapSettings;
QSize size( 640, 480 );
mapSettings.setOutputSize( size );
mapSettings.setExtent( QgsRectangle( 2685025.687, 1292045.297, 2685125.687, 1292145.297 ) );
mapSettings.setLayers( QList<QgsMapLayer *>() << vl.get() );
mapSettings.setOutputDpi( 96 );
mapSettings.setDestinationCrs( vl->crs() );

QgsDxfExport d;
d.addLayers( QList< QgsDxfExport::DxfLayer >() << QgsDxfExport::DxfLayer( vl.get() ) );
d.setMapSettings( mapSettings );
d.setSymbologyScale( 1000 );
d.setSymbologyExport( QgsDxfExport::FeatureSymbology );
d.setFlags( QgsDxfExport::FlagNoMText );
d.setExtent( mapSettings.extent() );

static int testNumber = 0;
++testNumber;
QString file = getTempFileName( QStringLiteral( "text_dxf_offset_quad_%1_%2" ).arg( offsetQuad ).arg( angle ) );
QFile dxfFile( file );
QCOMPARE( d.writeToFile( &dxfFile, QStringLiteral( "CP1252" ) ), QgsDxfExport::ExportResult::Success );
dxfFile.close();
QString debugInfo;
QVERIFY2( fileContainsText( file, QStringLiteral( "TEXT\n"
" 5\n"
"**no check**\n"
"100\n"
"AcDbEntity\n"
"100\n"
"AcDbText\n"
" 8\n"
"vl\n"
"420\n"
"**no check**\n"
" 10\n"
"REGEX ^2685025\\.68\\d*\n"
" 20\n"
"REGEX ^1292145\\.29\\d*\n"
" 11\n"
"REGEX ^2685025\\.68\\d*\n"
" 21\n"
"REGEX ^1292145\\.29\\d*\n"
" 40\n"
"**no check**\n"
" 1\n"
"182\n"
" 50\n"
"%1\n"
" 72\n"
" %2\n"
" 7\n"
"STANDARD\n"
"100\n"
"AcDbText\n"
" 73\n"
" %3" ).arg( QString::number( fmod( 360 - angle, 360 ), 'f', 1 ) ).arg( QString::number( static_cast<int>( dxfHali ) ), QString::number( static_cast<int>( dxfVali ) ) ), &debugInfo ), debugInfo.toUtf8().constData() );
}

void TestQgsDxfExport::testTextQuadrant_data()
{
QTest::addColumn<int>( "offsetQuad" );
QTest::addColumn<QgsDxfExport::HAlign>( "dxfHali" );
QTest::addColumn<QgsDxfExport::VAlign>( "dxfVali" );
QTest::addColumn<double>( "angle" );

QTest::newRow( "Above Left, no rotation" )
<< 0
<< QgsDxfExport::HAlign::HRight
<< QgsDxfExport::VAlign::VBottom
<< 0.0;

QTest::newRow( "Above, no rotation" )
<< 1
<< QgsDxfExport::HAlign::HCenter
<< QgsDxfExport::VAlign::VBottom
<< 0.0;

QTest::newRow( "Above Right, no rotation" )
<< 2
<< QgsDxfExport::HAlign::HLeft
<< QgsDxfExport::VAlign::VBottom
<< 0.0;

QTest::newRow( "Left, no rotation" )
<< 3
<< QgsDxfExport::HAlign::HRight
<< QgsDxfExport::VAlign::VMiddle
<< 0.0;

QTest::newRow( "Over, no rotation" )
<< 4
<< QgsDxfExport::HAlign::HCenter
<< QgsDxfExport::VAlign::VMiddle
<< 0.0;

QTest::newRow( "Right, no rotation" )
<< 5
<< QgsDxfExport::HAlign::HLeft
<< QgsDxfExport::VAlign::VMiddle
<< 0.0;

QTest::newRow( "Below Left, no rotation" )
<< 6
<< QgsDxfExport::HAlign::HRight
<< QgsDxfExport::VAlign::VTop
<< 0.0;

QTest::newRow( "Below, no rotation" )
<< 7
<< QgsDxfExport::HAlign::HCenter
<< QgsDxfExport::VAlign::VTop
<< 0.0;

QTest::newRow( "Below Right, no rotation" )
<< 8
<< QgsDxfExport::HAlign::HLeft
<< QgsDxfExport::VAlign::VTop
<< 0.0;

QTest::newRow( "Below, 20°" )
<< 7
<< QgsDxfExport::HAlign::HCenter
<< QgsDxfExport::VAlign::VTop
<< 20.0;
}

void TestQgsDxfExport::testGeometryGeneratorExport()
{
QgsDxfExport d;
Expand Down

0 comments on commit 2f5d210

Please sign in to comment.