Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2.1] World file generation #658

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions python/core/composer/qgscomposition.sip
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ class QgsComposition : QGraphicsScene
bool printAsRaster() const;
void setPrintAsRaster( bool enabled );

bool generateWorldFile() const;
void setGenerateWorldFile( bool enabled );

QgsComposerMap* worldFileMap();
void setWorldFileMap( QgsComposerMap* map );

double selectionTolerance() const;
void setSelectionTolerance( double tol );

Expand Down Expand Up @@ -271,6 +277,9 @@ class QgsComposition : QGraphicsScene
@note added in version 1.9*/
void renderPage( QPainter* p, int page );

/** Compute world file parameters */
void computeWorldFileParameters( double& a, double& b, double& c, double& d, double& e, double& f ) const;

QgsAtlasComposition& atlasComposition();

public slots:
Expand Down
67 changes: 67 additions & 0 deletions src/app/composer/qgscomposer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,22 @@ void QgsComposer::on_mActionExportAsImage_triggered()
image.save( outputFilePath, fileNExt.second.toLocal8Bit().constData() );
}
}

//
// Write the world file if asked to
if ( mComposition->generateWorldFile() )
{
double a, b, c, d, e, f;
mComposition->computeWorldFileParameters( a, b, c, d, e, f );

QFileInfo fi( fileNExt.first );
// build the world file name
QString worldFileName = fi.absolutePath() + "/" + fi.baseName() + "."
+ fi.suffix()[0] + fi.suffix()[fi.suffix().size()-1] + "w";

writeWorldFile( worldFileName, a, b, c, d, e, f );
}

mView->setPaintingEnabled( true );
}
else
Expand Down Expand Up @@ -1125,6 +1141,21 @@ void QgsComposer::on_mActionExportAsImage_triggered()
image.save( outputFilePath, format.toLocal8Bit().constData() );
}
}

//
// Write the world file if asked to
if ( mComposition->generateWorldFile() )
{
double a, b, c, d, e, f;
mComposition->computeWorldFileParameters( a, b, c, d, e, f );

QFileInfo fi( filename );
// build the world file name
QString worldFileName = fi.absolutePath() + "/" + fi.baseName() + "."
+ fi.suffix()[0] + fi.suffix()[fi.suffix().size()-1] + "w";

writeWorldFile( worldFileName, a, b, c, d, e, f );
}
}
atlasMap->endRender();
mView->setPaintingEnabled( true );
Expand Down Expand Up @@ -1861,6 +1892,24 @@ void QgsComposer::readXML( const QDomElement& composerElem, const QDomDocument&
mComposition->addItemsFromXML( composerElem, doc, &mMapsToRestore );
}

// look for world file composer map, if needed
// Note: this must be done after maps have been added by addItemsFromXML
if ( mComposition->generateWorldFile() )
{
QDomElement compositionElem = compositionNodeList.at( 0 ).toElement();
QgsComposerMap* worldFileMap = 0;
QList<const QgsComposerMap*> maps = mComposition->composerMapItems();
for ( QList<const QgsComposerMap*>::const_iterator it = maps.begin(); it != maps.end(); ++it )
{
if (( *it )->id() == compositionElem.attribute( "worldFileMap" ).toInt() )
{
worldFileMap = const_cast<QgsComposerMap*>( *it );
break;
}
}
mComposition->setWorldFileMap( worldFileMap );
}

mComposition->sortZList();
mView->setComposition( mComposition );

Expand Down Expand Up @@ -2284,3 +2333,21 @@ void QgsComposer::createComposerView()
mView->setVerticalRuler( mVerticalRuler );
mViewLayout->addWidget( mView, 1, 1 );
}

void QgsComposer::writeWorldFile( QString worldFileName, double a, double b, double c, double d, double e, double f ) const
{
QFile worldFile( worldFileName );
if ( !worldFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
return;
}
QTextStream fout(&worldFile);

// QString::number does not use locale settings (for the decimal point)
// which is what we want here
fout << QString::number(a, 'f') << "\r\n";
fout << QString::number(d, 'f') << "\r\n";
fout << QString::number(b, 'f') << "\r\n";
fout << QString::number(e, 'f') << "\r\n";
fout << QString::number(c, 'f') << "\r\n";
fout << QString::number(f, 'f') << "\r\n";
}
3 changes: 3 additions & 0 deletions src/app/composer/qgscomposer.h
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,9 @@ class QgsComposer: public QMainWindow, private Ui::QgsComposerBase
//! Create composer view and rulers
void createComposerView();

//! Write a world file
void writeWorldFile( QString fileName, double a, double b, double c, double d, double e, double f ) const;

/**Composer title*/
QString mTitle;

Expand Down
89 changes: 89 additions & 0 deletions src/app/composer/qgscompositionwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include <qgis.h>
#include "qgscompositionwidget.h"
#include "qgscomposition.h"
#include "qgscomposermap.h"
#include "qgscomposeritem.h"
#include <QColorDialog>
#include <QWidget>
#include <QPrinter> //for screen resolution
Expand Down Expand Up @@ -49,6 +51,29 @@ QgsCompositionWidget::QgsCompositionWidget( QWidget* parent, QgsComposition* c )
//print as raster
mPrintAsRasterCheckBox->setChecked( mComposition->printAsRaster() );

// world file generation
mGenerateWorldFileCheckBox->setChecked( mComposition->generateWorldFile() );

// populate the map list
mWorldFileMapComboBox->clear();
QList<const QgsComposerMap*> availableMaps = mComposition->composerMapItems();
QList<const QgsComposerMap*>::const_iterator mapItemIt = availableMaps.constBegin();
for ( ; mapItemIt != availableMaps.constEnd(); ++mapItemIt )
{
mWorldFileMapComboBox->addItem( tr( "Map %1" ).arg(( *mapItemIt )->id() ), qVariantFromValue(( void* )*mapItemIt ) );
}

int idx = mWorldFileMapComboBox->findData( qVariantFromValue(( void* )mComposition->worldFileMap() ) );
if ( idx != -1 )
{
mWorldFileMapComboBox->setCurrentIndex( idx );
}

// Connect to addition / removal of maps
connect( mComposition, SIGNAL( composerMapAdded( QgsComposerMap* ) ), this, SLOT( onComposerMapAdded( QgsComposerMap* ) ) );
connect( mComposition, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SLOT( onItemRemoved( QgsComposerItem* ) ) );


mAlignmentSnapGroupCheckBox->setChecked( mComposition->alignmentSnap() );
mAlignmentToleranceSpinBox->setValue( mComposition->alignmentSnapTolerance() );

Expand Down Expand Up @@ -412,6 +437,70 @@ void QgsCompositionWidget::on_mPrintAsRasterCheckBox_toggled( bool state )
mComposition->setPrintAsRaster( state );
}

void QgsCompositionWidget::on_mGenerateWorldFileCheckBox_toggled( bool state )
{
if ( !mComposition )
{
return;
}

mComposition->setGenerateWorldFile( state );
mWorldFileMapComboBox->setEnabled( state );
}

void QgsCompositionWidget::onComposerMapAdded( QgsComposerMap* map )
{
if ( !mComposition )
{
return;
}

mWorldFileMapComboBox->addItem( tr( "Map %1" ).arg( map->id() ), qVariantFromValue(( void* )map ) );
if ( mWorldFileMapComboBox->count() == 1 )
{
mComposition->setWorldFileMap( map );
}
}

void QgsCompositionWidget::onItemRemoved( QgsComposerItem* item )
{
if ( !mComposition )
{
return;
}

QgsComposerMap* map = dynamic_cast<QgsComposerMap*>( item );
if ( map )
{
int idx = mWorldFileMapComboBox->findData( qVariantFromValue(( void* )map ) );
if ( idx != -1 )
{
mWorldFileMapComboBox->removeItem( idx );
}
}
if ( mWorldFileMapComboBox->count() == 0 )
{
mComposition->setWorldFileMap( 0 );
}
}

void QgsCompositionWidget::on_mWorldFileMapComboBox_currentIndexChanged( int index )
{
if ( !mComposition )
{
return;
}
if ( index == -1 )
{
mComposition->setWorldFileMap( 0 );
}
else
{
QgsComposerMap* map = reinterpret_cast<QgsComposerMap*>( mWorldFileMapComboBox->itemData( index ).value<void*>() );
mComposition->setWorldFileMap( map );
}
}

void QgsCompositionWidget::on_mSnapToGridGroupCheckBox_toggled( bool state )
{
if ( mComposition )
Expand Down
10 changes: 10 additions & 0 deletions src/app/composer/qgscompositionwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include "ui_qgscompositionwidgetbase.h"

class QgsComposition;
class QgsComposerMap;
class QgsComposerItem;

/** \ingroup MapComposer
* Struct to hold map composer paper properties.
Expand Down Expand Up @@ -48,6 +50,8 @@ class QgsCompositionWidget: public QWidget, private Ui::QgsCompositionWidgetBase
void on_mNumPagesSpinBox_valueChanged( int value );
void on_mResolutionSpinBox_valueChanged( const int value );
void on_mPrintAsRasterCheckBox_toggled( bool state );
void on_mGenerateWorldFileCheckBox_toggled( bool state );
void on_mWorldFileMapComboBox_currentIndexChanged( int index );

void on_mSnapToGridGroupCheckBox_toggled( bool state );
void on_mGridResolutionSpinBox_valueChanged( double d );
Expand All @@ -65,6 +69,12 @@ class QgsCompositionWidget: public QWidget, private Ui::QgsCompositionWidgetBase
/**Sets Print as raster checkbox value*/
void setPrintAsRasterCheckBox( bool state );

private slots:
/* when a new map is added */
void onComposerMapAdded( QgsComposerMap* );
/* when a map is deleted */
void onItemRemoved( QgsComposerItem* );

private:
QgsComposition* mComposition;
QMap<QString, QgsCompositionPaper> mPaperMap;
Expand Down
72 changes: 72 additions & 0 deletions src/core/composer/qgscomposition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ QgsComposition::QgsComposition( QgsMapRenderer* mapRenderer )
mPageHeight( 210 ),
mSpaceBetweenPages( 10 ),
mPrintAsRaster( false ),
mGenerateWorldFile( false ),
mWorldFileMap( 0 ),
mUseAdvancedEffects( true ),
mSelectionTolerance( 0.0 ),
mSnapToGrid( false ),
Expand Down Expand Up @@ -82,6 +84,8 @@ QgsComposition::QgsComposition()
mPageHeight( 210 ),
mSpaceBetweenPages( 10 ),
mPrintAsRaster( false ),
mGenerateWorldFile( false ),
mWorldFileMap( 0 ),
mUseAdvancedEffects( true ),
mSelectionTolerance( 0.0 ),
mSnapToGrid( false ),
Expand Down Expand Up @@ -420,6 +424,11 @@ bool QgsComposition::writeXML( QDomElement& composerElem, QDomDocument& doc )
compositionElem.setAttribute( "printResolution", mPrintResolution );
compositionElem.setAttribute( "printAsRaster", mPrintAsRaster );

compositionElem.setAttribute( "generateWorldFile", mGenerateWorldFile ? 1 : 0 );
if ( mGenerateWorldFile && mWorldFileMap ) {
compositionElem.setAttribute( "worldFileMap", mWorldFileMap->id() );
}

compositionElem.setAttribute( "alignmentSnap", mAlignmentSnap ? 1 : 0 );
compositionElem.setAttribute( "alignmentSnapTolerance", mAlignmentSnapTolerance );

Expand Down Expand Up @@ -505,6 +514,8 @@ bool QgsComposition::readXML( const QDomElement& compositionElem, const QDomDocu
mPrintAsRaster = compositionElem.attribute( "printAsRaster" ).toInt();
mPrintResolution = compositionElem.attribute( "printResolution", "300" ).toInt();

mGenerateWorldFile = compositionElem.attribute( "generateWorldFile", "0" ).toInt() == 1 ? true : false;

updatePaperItems();
return true;
}
Expand Down Expand Up @@ -2158,3 +2169,64 @@ bool QgsComposition::nearestItem( const QMap< double, const QgsComposerItem* >&
}
}

void QgsComposition::computeWorldFileParameters( double& a, double& b, double& c, double& d, double& e, double& f ) const
{
//
// Word file parameters : affine transformation parameters from pixel coordinates to map coordinates

if ( !mWorldFileMap )
{
return;
}

QRectF brect = mWorldFileMap->boundingRect();
QgsRectangle extent = mWorldFileMap->extent();

double alpha = mWorldFileMap->rotation() / 180 * M_PI;

double xr = extent.width() / brect.width();
double yr = extent.height() / brect.height();

double XC = extent.center().x();
double YC = extent.center().y();

// get the extent for the page
double xmin = extent.xMinimum() - mWorldFileMap->transform().dx() * xr;
double ymax = extent.yMaximum() + mWorldFileMap->transform().dy() * yr;
QgsRectangle paperExtent( xmin, ymax - paperHeight() * yr, xmin + paperWidth() * xr, ymax );

double X0 = paperExtent.xMinimum();
double Y0 = paperExtent.yMinimum();

int widthPx = ( int )( printResolution() * paperWidth() / 25.4 );
int heightPx = ( int )( printResolution() * paperHeight() / 25.4 );

double Ww = paperExtent.width() / widthPx;
double Hh = paperExtent.height() / heightPx;

// scaling matrix
double s[6];
s[0] = Ww;
s[1] = 0;
s[2] = X0;
s[3] = 0;
s[4] = -Hh;
s[5] = Y0 + paperExtent.height();

// rotation matrix
double r[6];
r[0] = cos(alpha);
r[1] = -sin(alpha);
r[2] = XC * (1 - cos(alpha)) + YC * sin(alpha);
r[3] = sin(alpha);
r[4] = cos(alpha);
r[5] = - XC * sin(alpha) + YC * (1 - cos(alpha));

// result = rotation x scaling = rotation(scaling(X))
a = r[0] * s[0] + r[1] * s[3];
b = r[0] * s[1] + r[1] * s[4];
c = r[0] * s[2] + r[1] * s[5] + r[2];
d = r[3] * s[0] + r[4] * s[3];
e = r[3] * s[1] + r[4] * s[4];
f = r[3] * s[2] + r[4] * s[5] + r[5];
}