@@ -74,6 +74,9 @@ QgsAtlasRendering::QgsAtlasRendering( QgsComposition* composition )
7474
7575void QgsAtlasRendering::begin ( const QString& filenamePattern )
7676{
77+ if ( !impl->composition || !impl->composition ->atlasMap () || !impl->composition ->atlasMap ()->atlasCoverageLayer () )
78+ return ;
79+
7780 impl->filenamePattern = filenamePattern;
7881
7982 QgsVectorLayer* coverage = impl->composition ->atlasMap ()->atlasCoverageLayer ();
@@ -103,12 +106,7 @@ void QgsAtlasRendering::begin( const QString& filenamePattern )
103106 }
104107
105108 // select all features with all attributes
106- QgsAttributeList selectedAttributes;
107- for ( QgsFieldMap::const_iterator fit = fieldmap.begin (); fit != fieldmap.end (); ++fit )
108- {
109- selectedAttributes.push_back ( fit.key () );
110- }
111- provider->select ( selectedAttributes );
109+ provider->select ( provider->attributeIndexes () );
112110
113111 // features must be stored in a list, since modifying the layer's extent rewinds nextFeature()
114112 QgsFeature feature;
@@ -134,101 +132,104 @@ void QgsAtlasRendering::begin( const QString& filenamePattern )
134132
135133 // special columns for expressions
136134 QgsExpression::setSpecialColumn ( " $numfeatures" , QVariant ( (int )impl->nFeatures ) );
137- QgsExpression::setSpecialColumn ( " $numpages" , QVariant ( (int )impl->composition ->numPages () ) );
138135}
139136
140137void QgsAtlasRendering::prepareForFeature ( size_t featureI )
141138{
142- QgsFeature* fit = &impl->features [featureI];
139+ if ( !impl->composition || !impl->composition ->atlasMap () || !impl->composition ->atlasMap ()->atlasCoverageLayer () )
140+ return ;
143141
144- if ( impl->filenamePattern .size () > 0 )
142+ QgsFeature* fit = &impl->features [featureI];
143+
144+ if ( impl->filenamePattern .size () > 0 )
145+ {
146+ QgsExpression::setSpecialColumn ( " $feature" , QVariant ( (int )featureI + 1 ) );
147+ QVariant filenameRes = impl->filenameExpr ->evaluate ( &*fit );
148+ if ( impl->filenameExpr ->hasEvalError () )
145149 {
146- QgsExpression::setSpecialColumn ( " $feature" , QVariant ( (int )featureI + 1 ) );
147- QVariant filenameRes = impl->filenameExpr ->evaluate ( &*fit );
148- if ( impl->filenameExpr ->hasEvalError () )
149- {
150- throw std::runtime_error ( " Filename eval error: " + impl->filenameExpr ->evalErrorString ().toStdString () );
151- }
152-
153- impl->currentFilename = filenameRes.toString ();
150+ throw std::runtime_error ( " Filename eval error: " + impl->filenameExpr ->evalErrorString ().toStdString () );
154151 }
155-
156- //
157- // compute the new extent
158- // keep the original aspect ratio
159- // and apply a margin
160-
161- // QgsGeometry::boundingBox is expressed in the geometry"s native CRS
162- // They have to be transformed to the MapRenderer's one
163- QgsRectangle geom_rect = impl->transform .transform ( fit->geometry ()->boundingBox () );
164- double xa1 = geom_rect.xMinimum ();
165- double xa2 = geom_rect.xMaximum ();
166- double ya1 = geom_rect.yMinimum ();
167- double ya2 = geom_rect.yMaximum ();
168- QgsRectangle new_extent = geom_rect;
169-
170- // restore the original extent
171- // (successive calls to setNewExtent tend to deform the original rectangle)
172- impl->composition ->atlasMap ()->setNewExtent ( impl->origExtent );
173-
174- if ( impl->composition ->atlasMap ()->atlasFixedScale () )
152+
153+ impl->currentFilename = filenameRes.toString ();
154+ }
155+
156+ //
157+ // compute the new extent
158+ // keep the original aspect ratio
159+ // and apply a margin
160+
161+ // QgsGeometry::boundingBox is expressed in the geometry"s native CRS
162+ // We have to transform the grometry to the destination CRS and ask for the bounding box
163+ // Note: we cannot directly take the transformation of the bounding box, since transformations are not linear
164+
165+ QgsGeometry tgeom ( *fit->geometry () );
166+ tgeom.transform ( impl->transform );
167+ QgsRectangle geom_rect = tgeom.boundingBox ();
168+
169+ double xa1 = geom_rect.xMinimum ();
170+ double xa2 = geom_rect.xMaximum ();
171+ double ya1 = geom_rect.yMinimum ();
172+ double ya2 = geom_rect.yMaximum ();
173+ QgsRectangle new_extent = geom_rect;
174+
175+ // restore the original extent
176+ // (successive calls to setNewExtent tend to deform the original rectangle)
177+ impl->composition ->atlasMap ()->setNewExtent ( impl->origExtent );
178+
179+ if ( impl->composition ->atlasMap ()->atlasFixedScale () )
180+ {
181+ // only translate, keep the original scale (i.e. width x height)
182+
183+ double geom_center_x = (xa1 + xa2) / 2.0 ;
184+ double geom_center_y = (ya1 + ya2) / 2.0 ;
185+ double xx = geom_center_x - impl->origExtent .width () / 2.0 ;
186+ double yy = geom_center_y - impl->origExtent .height () / 2.0 ;
187+ new_extent = QgsRectangle ( xx,
188+ yy,
189+ xx + impl->origExtent .width (),
190+ yy + impl->origExtent .height () );
191+ }
192+ else
193+ {
194+ // auto scale
195+
196+ double geom_ratio = geom_rect.width () / geom_rect.height ();
197+ double map_ratio = impl->origExtent .width () / impl->origExtent .height ();
198+
199+ // geometry height is too big
200+ if ( geom_ratio < map_ratio )
175201 {
176- // only translate, keep the original scale (i.e. width x height)
177-
178- double geom_center_x = (xa1 + xa2) / 2.0 ;
179- double geom_center_y = (ya1 + ya2) / 2.0 ;
180- double xx = geom_center_x - impl->origExtent .width () / 2.0 ;
181- double yy = geom_center_y - impl->origExtent .height () / 2.0 ;
182- new_extent = QgsRectangle ( xx,
183- yy,
184- xx + impl->origExtent .width (),
185- yy + impl->origExtent .height () );
202+ new_extent = QgsRectangle ( (xa1 + xa2 + map_ratio * (ya1 - ya2)) / 2.0 ,
203+ ya1,
204+ xa1 + map_ratio * (ya2 - ya1),
205+ ya2);
186206 }
187- else
207+ // geometry width is too big
208+ else if ( geom_ratio > map_ratio )
188209 {
189- // auto scale
190-
191- double geom_ratio = geom_rect.width () / geom_rect.height ();
192- double map_ratio = impl->origExtent .width () / impl->origExtent .height ();
193-
194- // geometry height is too big
195- if ( geom_ratio < map_ratio )
196- {
197- new_extent = QgsRectangle ( (xa1 + xa2 + map_ratio * (ya1 - ya2)) / 2.0 ,
198- ya1,
199- xa1 + map_ratio * (ya2 - ya1),
200- ya2);
201- }
202- // geometry width is too big
203- else if ( geom_ratio > map_ratio )
204- {
205- new_extent = QgsRectangle ( xa1,
206- (ya1 + ya2 + (xa1 - xa2) / map_ratio) / 2.0 ,
207- xa2,
208- ya1 + (xa2 - xa1) / map_ratio);
209- }
210- if ( impl->composition ->atlasMap ()->atlasMargin () > 0.0 )
211- {
212- new_extent.scale ( 1 + impl->composition ->atlasMap ()->atlasMargin () );
213- }
210+ new_extent = QgsRectangle ( xa1,
211+ (ya1 + ya2 + (xa1 - xa2) / map_ratio) / 2.0 ,
212+ xa2,
213+ ya1 + (xa2 - xa1) / map_ratio);
214214 }
215-
216- // evaluate label expressions
217- QList<QgsComposerLabel*> labels;
218- impl->composition ->composerItems ( labels );
219- QgsExpression::setSpecialColumn ( " $feature" , QVariant ( (int )featureI + 1 ) );
220-
221- for ( QList<QgsComposerLabel*>::iterator lit = labels.begin (); lit != labels.end (); ++lit )
215+ if ( impl->composition ->atlasMap ()->atlasMargin () > 0.0 )
222216 {
223- // build a local substitution map
224- QMap<QString, QVariant> pageMap;
225- pageMap.insert ( " $page" , QVariant ( (int )impl->composition ->itemPageNumber ( *lit ) + 1 ) );
226- (*lit)->setExpressionContext ( fit, impl->composition ->atlasMap ()->atlasCoverageLayer (), pageMap );
217+ new_extent.scale ( 1 + impl->composition ->atlasMap ()->atlasMargin () );
227218 }
228-
229-
230- // set the new extent (and render)
231- impl->composition ->atlasMap ()->setNewExtent ( new_extent );
219+ }
220+
221+ // evaluate label expressions
222+ QList<QgsComposerLabel*> labels;
223+ impl->composition ->composerItems ( labels );
224+ QgsExpression::setSpecialColumn ( " $feature" , QVariant ( (int )featureI + 1 ) );
225+
226+ for ( QList<QgsComposerLabel*>::iterator lit = labels.begin (); lit != labels.end (); ++lit )
227+ {
228+ (*lit)->setExpressionContext ( fit, impl->composition ->atlasMap ()->atlasCoverageLayer () );
229+ }
230+
231+ // set the new extent (and render)
232+ impl->composition ->atlasMap ()->setNewExtent ( new_extent );
232233}
233234
234235size_t QgsAtlasRendering::numFeatures () const
@@ -243,6 +244,9 @@ const QString& QgsAtlasRendering::currentFilename() const
243244
244245void QgsAtlasRendering::end ()
245246{
247+ if ( !impl->composition || !impl->composition ->atlasMap () || !impl->composition ->atlasMap ()->atlasCoverageLayer () )
248+ return ;
249+
246250 // reset label expression contexts
247251 QList<QgsComposerLabel*> labels;
248252 impl->composition ->composerItems ( labels );
@@ -350,6 +354,10 @@ void QgsComposition::setNumPages( int pages )
350354 mPages .removeLast ();
351355 }
352356 }
357+
358+ // update the corresponding variable
359+ QgsExpression::setSpecialColumn ( " $numpages" , QVariant ((int )numPages ()) );
360+
353361 emit nPagesChanged ();
354362}
355363
@@ -1700,6 +1708,8 @@ void QgsComposition::addPaperItem()
17001708 addItem ( paperItem );
17011709 paperItem->setZValue ( 0 );
17021710 mPages .push_back ( paperItem );
1711+
1712+ QgsExpression::setSpecialColumn ( " $numpages" , QVariant ((int )mPages .size ()) );
17031713}
17041714
17051715void QgsComposition::removePaperItems ()
@@ -1709,6 +1719,7 @@ void QgsComposition::removePaperItems()
17091719 delete mPages .at ( i );
17101720 }
17111721 mPages .clear ();
1722+ QgsExpression::setSpecialColumn ( " $numpages" , QVariant ((int )0 ) );
17121723}
17131724
17141725void QgsComposition::deleteAndRemoveMultiFrames ()
@@ -1836,3 +1847,32 @@ void QgsComposition::renderPage( QPainter* p, int page )
18361847
18371848 mPlotStyle = savedPlotStyle;
18381849}
1850+
1851+ void QgsComposition::setAtlasMap ( QgsComposerMap* map )
1852+ {
1853+ mAtlasMap = map;
1854+ if ( map != 0 )
1855+ {
1856+ QObject::connect ( map, SIGNAL ( atlasCoverageLayerChanged ( QgsVectorLayer* )), this , SLOT ( onAtlasCoverageChanged ( QgsVectorLayer* ) ) );
1857+ }
1858+ else
1859+ {
1860+ QObject::disconnect ( map, SIGNAL ( atlasCoverageLayerChanged ( QgsVectorLayer* )), this , SLOT ( onAtlasCoverageChanged ( QgsVectorLayer* ) ) );
1861+ }
1862+ }
1863+
1864+ void QgsComposition::onAtlasCoverageChanged ( QgsVectorLayer* )
1865+ {
1866+ // update variables
1867+ if ( mAtlasMap != 0 && mAtlasMap ->atlasCoverageLayer () != 0 )
1868+ {
1869+ QgsVectorDataProvider* provider = mAtlasMap ->atlasCoverageLayer ()->dataProvider ();
1870+ QgsExpression::setSpecialColumn ( " $numfeatures" , QVariant ( (int )provider->featureCount () ) );
1871+ }
1872+ else
1873+ {
1874+ QgsExpression::setSpecialColumn ( " $numfeatures" , QVariant ( (int )0 ) );
1875+ }
1876+ //
1877+ QgsExpression::setSpecialColumn ( " $numpages" , QVariant ( (int )numPages () ) );
1878+ }
0 commit comments