Start porting map item
@ -183,6 +183,17 @@ class QgsLayoutItem : QgsLayoutObject, QGraphicsRectItem, QgsLayoutUndoObjectInt
|
||||
.. seealso:: parentGroup()
|
||||
%End
|
||||
|
||||
virtual int numberExportLayers() const;
|
||||
%Docstring
|
||||
Returns the number of layers that this item requires for exporting during layered exports (e.g. SVG).
|
||||
Returns 0 if this item is to be placed on the same layer as the previous item,
|
||||
1 if it should be placed on its own layer, and >1 if it requires multiple export layers.
|
||||
|
||||
Items which require multiply layers should check QgsLayoutContext.currentExportLayer() during
|
||||
their rendering to determine which layer should be drawn.
|
||||
:rtype: int
|
||||
%End
|
||||
|
||||
virtual void paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget );
|
||||
|
||||
%Docstring
|
||||
@ -514,6 +525,21 @@ class QgsLayoutItem : QgsLayoutObject, QGraphicsRectItem, QgsLayoutUndoObjectInt
|
||||
:rtype: QRectF
|
||||
%End
|
||||
|
||||
virtual void moveContent( double dx, double dy );
|
||||
%Docstring
|
||||
Moves the content of the item, by a specified ``dx`` and ``dy`` in layout units.
|
||||
The default implementation has no effect.
|
||||
.. seealso:: zoomContent()
|
||||
%End
|
||||
|
||||
virtual void zoomContent( double factor, QPointF point );
|
||||
%Docstring
|
||||
Zooms content of item. Does nothing by default.
|
||||
\param factor zoom factor, where > 1 results in a zoom in and < 1 results in a zoom out
|
||||
\param point item point for zoom center
|
||||
.. seealso:: moveContent()
|
||||
%End
|
||||
|
||||
public slots:
|
||||
|
||||
virtual void refresh();
|
||||
@ -716,6 +742,12 @@ class QgsLayoutItem : QgsLayoutObject, QGraphicsRectItem, QgsLayoutUndoObjectInt
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
bool shouldDrawItem() const;
|
||||
%Docstring
|
||||
Returns whether the item should be drawn in the current context.
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsLayoutItemMap : QgsLayoutItem
|
||||
{
|
||||
%Docstring
|
||||
@ -20,15 +21,33 @@ class QgsLayoutItemMap : QgsLayoutItem
|
||||
%End
|
||||
public:
|
||||
|
||||
enum AtlasScalingMode
|
||||
{
|
||||
Fixed,
|
||||
|
||||
Predefined,
|
||||
|
||||
Auto
|
||||
};
|
||||
|
||||
explicit QgsLayoutItemMap( QgsLayout *layout );
|
||||
%Docstring
|
||||
Constructor for QgsLayoutItemMap, with the specified parent ``layout``.
|
||||
%End
|
||||
~QgsLayoutItemMap();
|
||||
|
||||
virtual int type() const;
|
||||
|
||||
virtual QString stringType() const;
|
||||
|
||||
|
||||
void assignFreeId();
|
||||
%Docstring
|
||||
Sets the map id() to a number not yet used in the layout. The existing id() is kept if it is not in use.
|
||||
%End
|
||||
|
||||
virtual QString displayName() const;
|
||||
|
||||
static QgsLayoutItemMap *create( QgsLayout *layout ) /Factory/;
|
||||
%Docstring
|
||||
Returns a new map item for the specified ``layout``.
|
||||
@ -37,10 +56,410 @@ class QgsLayoutItemMap : QgsLayoutItem
|
||||
:rtype: QgsLayoutItemMap
|
||||
%End
|
||||
|
||||
virtual void paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget );
|
||||
|
||||
virtual int numberExportLayers() const;
|
||||
|
||||
virtual void setFrameStrokeWidth( const QgsLayoutMeasurement &width );
|
||||
|
||||
|
||||
|
||||
double scale() const;
|
||||
%Docstring
|
||||
Returns the map scale.
|
||||
The scale value indicates the scale denominator, e.g. 1000.0 for a 1:1000 map.
|
||||
.. seealso:: setScale()
|
||||
:rtype: float
|
||||
%End
|
||||
|
||||
void setScale( double scale, bool forceUpdate = true );
|
||||
%Docstring
|
||||
Sets new map ``scale`` and changes only the map extent.
|
||||
|
||||
The ``scale`` value indicates the scale denominator, e.g. 1000.0 for a 1:1000 map.
|
||||
|
||||
.. seealso:: scale()
|
||||
%End
|
||||
|
||||
void setExtent( const QgsRectangle &extent );
|
||||
%Docstring
|
||||
Sets a new ``extent`` for the map. This method may change the width or height of the map
|
||||
item to ensure that the extent exactly matches the specified extent, with no
|
||||
overlap or margin. This method implicitly alters the map scale.
|
||||
.. seealso:: zoomToExtent()
|
||||
%End
|
||||
|
||||
void zoomToExtent( const QgsRectangle &extent );
|
||||
%Docstring
|
||||
Zooms the map so that the specified ``extent`` is fully visible within the map item.
|
||||
This method will not change the width or height of the map, and may result in
|
||||
an overlap or margin from the specified extent. This method implicitly alters the
|
||||
map scale.
|
||||
.. seealso:: setExtent()
|
||||
%End
|
||||
|
||||
QgsRectangle extent() const;
|
||||
%Docstring
|
||||
Returns the current map extent.
|
||||
.. seealso:: visibleExtentPolygon()
|
||||
:rtype: QgsRectangle
|
||||
%End
|
||||
|
||||
|
||||
QPolygonF visibleExtentPolygon() const;
|
||||
%Docstring
|
||||
Returns a polygon representing the current visible map extent, considering map extents and rotation.
|
||||
If the map rotation is 0, the result is the same as currentMapExtent
|
||||
:return: polygon with the four corner points representing the visible map extent. The points are
|
||||
clockwise, starting at the top-left point
|
||||
.. seealso:: extent()
|
||||
:rtype: QPolygonF
|
||||
%End
|
||||
|
||||
QgsCoordinateReferenceSystem crs() const;
|
||||
%Docstring
|
||||
Returns coordinate reference system used for rendering the map.
|
||||
This will match the presetCrs() if that is set, or if a preset
|
||||
CRS is not set then the map's CRS will follow the composition's
|
||||
project's CRS.
|
||||
.. seealso:: presetCrs()
|
||||
.. seealso:: setCrs()
|
||||
:rtype: QgsCoordinateReferenceSystem
|
||||
%End
|
||||
|
||||
QgsCoordinateReferenceSystem presetCrs() const;
|
||||
%Docstring
|
||||
Returns the map's preset coordinate reference system. If set, this
|
||||
CRS will be used to render the map regardless of any project CRS
|
||||
setting. If the returned CRS is not valid then the project CRS
|
||||
will be used to render the map.
|
||||
.. seealso:: crs()
|
||||
.. seealso:: setCrs()
|
||||
:rtype: QgsCoordinateReferenceSystem
|
||||
%End
|
||||
|
||||
void setCrs( const QgsCoordinateReferenceSystem &crs );
|
||||
%Docstring
|
||||
Sets the map's preset ``crs`` (coordinate reference system). If a valid CRS is
|
||||
set, this CRS will be used to render the map regardless of any project CRS
|
||||
setting. If the CRS is not valid then the project CRS will be used to render the map.
|
||||
.. seealso:: crs()
|
||||
.. seealso:: presetCrs()
|
||||
%End
|
||||
|
||||
bool keepLayerSet() const;
|
||||
%Docstring
|
||||
Returns whether a stored layer set should be used
|
||||
or the current layer set from the project associated with the layout. This is just a GUI flag,
|
||||
and itself does not change which layers are rendered in the map.
|
||||
Instead, use setLayers() to control which layers are rendered.
|
||||
.. seealso:: setKeepLayerSet()
|
||||
.. seealso:: layers()
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
void setKeepLayerSet( bool enabled );
|
||||
%Docstring
|
||||
Sets whether the stored layer set should be used
|
||||
or the current layer set of the associated project. This is just a GUI flag,
|
||||
and itself does not change which layers are rendered in the map.
|
||||
Instead, use setLayers() to control which layers are rendered.
|
||||
.. seealso:: keepLayerSet()
|
||||
.. seealso:: layers()
|
||||
%End
|
||||
|
||||
QList<QgsMapLayer *> layers() const;
|
||||
%Docstring
|
||||
Returns the stored layer set. If empty, the current project layers will
|
||||
be used instead.
|
||||
.. seealso:: setLayers()
|
||||
.. seealso:: keepLayerSet()
|
||||
:rtype: list of QgsMapLayer
|
||||
%End
|
||||
|
||||
void setLayers( const QList<QgsMapLayer *> &layers );
|
||||
%Docstring
|
||||
Sets the stored ``layers`` set. If empty, the current project layers will
|
||||
be used instead.
|
||||
.. seealso:: layers()
|
||||
.. seealso:: keepLayerSet()
|
||||
%End
|
||||
|
||||
bool keepLayerStyles() const;
|
||||
%Docstring
|
||||
Returns whether current styles of layers should be overridden by previously stored styles.
|
||||
.. seealso:: setKeepLayerStyles()
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
void setKeepLayerStyles( bool enabled );
|
||||
%Docstring
|
||||
Sets whether current styles of layers should be overridden by previously stored styles.
|
||||
.. seealso:: keepLayerStyles()
|
||||
%End
|
||||
|
||||
QMap<QString, QString> layerStyleOverrides() const;
|
||||
%Docstring
|
||||
Returns stored overrides of styles for layers.
|
||||
.. seealso:: setLayerStyleOverrides()
|
||||
:rtype: QMap<str, QString>
|
||||
%End
|
||||
|
||||
void setLayerStyleOverrides( const QMap<QString, QString> &overrides );
|
||||
%Docstring
|
||||
Sets the stored overrides of styles for layers.
|
||||
.. seealso:: layerStyleOverrides()
|
||||
%End
|
||||
|
||||
void storeCurrentLayerStyles();
|
||||
%Docstring
|
||||
Stores the current project layer styles into style overrides.
|
||||
%End
|
||||
|
||||
bool followVisibilityPreset() const;
|
||||
%Docstring
|
||||
Returns whether the map should follow a map theme. If true, the layers and layer styles
|
||||
will be used from given preset name (configured with setFollowVisibilityPresetName() method).
|
||||
This means when preset's settings are changed, the new settings are automatically
|
||||
picked up next time when rendering, without having to explicitly update them.
|
||||
At most one of the flags keepLayerSet() and followVisibilityPreset() should be enabled
|
||||
at any time since they are alternative approaches - if both are enabled,
|
||||
following map theme has higher priority. If neither is enabled (or if preset name is not set),
|
||||
map will use the same configuration as the map canvas uses.
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
void setFollowVisibilityPreset( bool follow );
|
||||
%Docstring
|
||||
Sets whether the map should follow a map theme. See followVisibilityPreset() for more details.
|
||||
%End
|
||||
|
||||
QString followVisibilityPresetName() const;
|
||||
%Docstring
|
||||
Preset name that decides which layers and layer styles are used for map rendering. It is only
|
||||
used when followVisibilityPreset() returns true.
|
||||
.. seealso:: setFollowVisibilityPresetName()
|
||||
:rtype: str
|
||||
%End
|
||||
|
||||
void setFollowVisibilityPresetName( const QString &name );
|
||||
%Docstring
|
||||
Sets preset name for map rendering. See followVisibilityPresetName() for more details.
|
||||
.. seealso:: followVisibilityPresetName()
|
||||
%End
|
||||
|
||||
virtual void moveContent( double dx, double dy );
|
||||
|
||||
virtual void zoomContent( double factor, QPointF point );
|
||||
|
||||
|
||||
|
||||
bool containsWmsLayer() const;
|
||||
%Docstring
|
||||
Returns true if the map contains a WMS layer.
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
bool containsAdvancedEffects() const;
|
||||
%Docstring
|
||||
Returns true if the map contains layers with blend modes or flattened layers for vectors
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
void setMapRotation( double rotation );
|
||||
%Docstring
|
||||
Sets the ``rotation`` for the map - this does not affect the composer item shape, only the
|
||||
way the map is drawn within the item. Rotation is in degrees, clockwise.
|
||||
.. seealso:: mapRotation()
|
||||
%End
|
||||
|
||||
double mapRotation( QgsLayoutObject::PropertyValueType valueType = QgsLayoutObject::EvaluatedValue ) const;
|
||||
%Docstring
|
||||
Returns the rotation used for drawing the map within the composer item, in degrees clockwise.
|
||||
\param valueType controls whether the returned value is the user specified rotation,
|
||||
or the current evaluated rotation (which may be affected by data driven rotation
|
||||
settings).
|
||||
.. seealso:: setMapRotation()
|
||||
:rtype: float
|
||||
%End
|
||||
|
||||
void setDrawAnnotations( bool draw );
|
||||
%Docstring
|
||||
Sets whether annotations are drawn within the composer map.
|
||||
.. seealso:: drawAnnotations()
|
||||
%End
|
||||
|
||||
bool drawAnnotations() const;
|
||||
%Docstring
|
||||
Returns whether annotations are drawn within the composer map.
|
||||
.. seealso:: setDrawAnnotations()
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
|
||||
bool atlasDriven() const;
|
||||
%Docstring
|
||||
Returns whether the map extent is set to follow the current atlas feature.
|
||||
:return: true if map will follow the current atlas feature.
|
||||
.. seealso:: setAtlasDriven
|
||||
.. seealso:: atlasScalingMode
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
void setAtlasDriven( bool enabled );
|
||||
%Docstring
|
||||
Sets whether the map extent will follow the current atlas feature.
|
||||
\param enabled set to true if the map extents should be set by the current atlas feature.
|
||||
.. seealso:: atlasDriven
|
||||
.. seealso:: setAtlasScalingMode
|
||||
%End
|
||||
|
||||
AtlasScalingMode atlasScalingMode() const;
|
||||
%Docstring
|
||||
Returns the current atlas scaling mode. This controls how the map's extents
|
||||
are calculated for the current atlas feature when an atlas composition
|
||||
is enabled.
|
||||
:return: the current scaling mode
|
||||
.. note::
|
||||
|
||||
this parameter is only used if atlasDriven() is true
|
||||
.. seealso:: setAtlasScalingMode
|
||||
.. seealso:: atlasDriven
|
||||
:rtype: AtlasScalingMode
|
||||
%End
|
||||
|
||||
void setAtlasScalingMode( AtlasScalingMode mode );
|
||||
%Docstring
|
||||
Sets the current atlas scaling mode. This controls how the map's extents
|
||||
are calculated for the current atlas feature when an atlas composition
|
||||
is enabled.
|
||||
\param mode atlas scaling mode to set
|
||||
.. note::
|
||||
|
||||
this parameter is only used if atlasDriven() is true
|
||||
.. seealso:: atlasScalingMode
|
||||
.. seealso:: atlasDriven
|
||||
%End
|
||||
|
||||
double atlasMargin( const QgsLayoutObject::PropertyValueType valueType = QgsLayoutObject::EvaluatedValue );
|
||||
%Docstring
|
||||
Returns the margin size (percentage) used when the map is in atlas mode.
|
||||
\param valueType controls whether the returned value is the user specified atlas margin,
|
||||
or the current evaluated atlas margin (which may be affected by data driven atlas margin
|
||||
settings).
|
||||
:return: margin size in percentage to leave around the atlas feature's extent
|
||||
.. note::
|
||||
|
||||
this is only used if atlasScalingMode() is Auto.
|
||||
.. seealso:: atlasScalingMode
|
||||
.. seealso:: setAtlasMargin
|
||||
:rtype: float
|
||||
%End
|
||||
|
||||
void setAtlasMargin( double margin );
|
||||
%Docstring
|
||||
Sets the margin size (percentage) used when the map is in atlas mode.
|
||||
\param margin size in percentage to leave around the atlas feature's extent
|
||||
.. note::
|
||||
|
||||
this is only used if atlasScalingMode() is Auto.
|
||||
.. seealso:: atlasScalingMode
|
||||
.. seealso:: atlasMargin
|
||||
%End
|
||||
|
||||
protected:
|
||||
|
||||
virtual void draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle = 0 );
|
||||
|
||||
|
||||
QgsMapSettings mapSettings( const QgsRectangle &extent, QSizeF size, int dpi ) const;
|
||||
%Docstring
|
||||
Return map settings that will be used for drawing of the map.
|
||||
:rtype: QgsMapSettings
|
||||
%End
|
||||
|
||||
bool isDrawing() const;
|
||||
%Docstring
|
||||
True if a draw is already in progress
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
|
||||
|
||||
void setOffset( double xOffset, double yOffset );
|
||||
%Docstring
|
||||
Sets offset values to shift image (useful for live updates when moving item content)
|
||||
%End
|
||||
|
||||
|
||||
virtual QRectF boundingRect() const;
|
||||
|
||||
|
||||
virtual QgsExpressionContext createExpressionContext() const;
|
||||
|
||||
|
||||
double mapUnitsToLayoutUnits() const;
|
||||
%Docstring
|
||||
Returns the conversion factor from map units to layout units.
|
||||
This is calculated using the width of the map item and the width of the
|
||||
current visible map extent.
|
||||
:rtype: float
|
||||
%End
|
||||
|
||||
|
||||
QPolygonF transformedMapPolygon() const;
|
||||
%Docstring
|
||||
Returns extent that considers rotation and shift with mOffsetX / mOffsetY
|
||||
:rtype: QPolygonF
|
||||
%End
|
||||
|
||||
QPointF mapToItemCoords( QPointF mapCoords ) const;
|
||||
%Docstring
|
||||
Transforms map coordinates to item coordinates (considering rotation and move offset)
|
||||
:rtype: QPointF
|
||||
%End
|
||||
|
||||
QgsRectangle requestedExtent() const;
|
||||
%Docstring
|
||||
Calculates the extent to request and the yShift of the top-left point in case of rotation.
|
||||
:rtype: QgsRectangle
|
||||
%End
|
||||
|
||||
signals:
|
||||
void extentChanged();
|
||||
|
||||
void mapRotationChanged( double newRotation );
|
||||
%Docstring
|
||||
Is emitted on rotation change to notify north arrow pictures
|
||||
%End
|
||||
|
||||
void preparedForAtlas();
|
||||
%Docstring
|
||||
Is emitted when the map has been prepared for atlas rendering, just before actual rendering
|
||||
%End
|
||||
|
||||
void layerStyleOverridesChanged();
|
||||
%Docstring
|
||||
Emitted when layer style overrides are changed... a means to let
|
||||
associated legend items know they should update
|
||||
%End
|
||||
|
||||
|
||||
public slots:
|
||||
|
||||
void invalidateCache();
|
||||
%Docstring
|
||||
Forces a deferred update of the cached map image on next paint.
|
||||
%End
|
||||
|
||||
void updateBoundingRect();
|
||||
%Docstring
|
||||
Updates the bounding rect of this item. Call this function before doing any changes related to annotation out of the map rectangle
|
||||
%End
|
||||
|
||||
virtual void refreshDataDefinedProperty( const QgsLayoutObject::DataDefinedProperty property = QgsLayoutObject::AllProperties );
|
||||
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
|
@ -72,6 +72,12 @@ class QgsLayoutObject: QObject, QgsExpressionContextGenerator
|
||||
ScalebarLineWidth,
|
||||
};
|
||||
|
||||
enum PropertyValueType
|
||||
{
|
||||
EvaluatedValue,
|
||||
OriginalValue
|
||||
};
|
||||
|
||||
static const QgsPropertiesDefinition &propertyDefinitions();
|
||||
%Docstring
|
||||
Returns the layout object property definitions.
|
||||
|
@ -21,6 +21,14 @@ class QgsLayoutUtils
|
||||
%End
|
||||
public:
|
||||
|
||||
static void rotate( double angle, double &x, double &y );
|
||||
%Docstring
|
||||
Rotates a point / vector around the origin.
|
||||
\param angle rotation angle in degrees, counterclockwise
|
||||
\param x in/out: x coordinate before / after the rotation
|
||||
\param y in/out: y coordinate before / after the rotation
|
||||
%End
|
||||
|
||||
static double normalizedAngle( const double angle, const bool allowNegative = false );
|
||||
%Docstring
|
||||
Ensures that an ``angle`` (in degrees) is in the range 0 <= angle < 360.
|
||||
|
@ -203,6 +203,16 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
|
||||
*/
|
||||
void setParentGroup( QgsLayoutItemGroup *group );
|
||||
|
||||
/**
|
||||
* Returns the number of layers that this item requires for exporting during layered exports (e.g. SVG).
|
||||
* Returns 0 if this item is to be placed on the same layer as the previous item,
|
||||
* 1 if it should be placed on its own layer, and >1 if it requires multiple export layers.
|
||||
*
|
||||
* Items which require multiply layers should check QgsLayoutContext::currentExportLayer() during
|
||||
* their rendering to determine which layer should be drawn.
|
||||
*/
|
||||
virtual int numberExportLayers() const { return 0; }
|
||||
|
||||
/**
|
||||
* Handles preparing a paint surface for the layout item and painting the item's
|
||||
* content. Derived classes must not override this method, but instead implement
|
||||
@ -724,6 +734,11 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
|
||||
*/
|
||||
virtual bool readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context );
|
||||
|
||||
/**
|
||||
* Returns whether the item should be drawn in the current context.
|
||||
*/
|
||||
bool shouldDrawItem() const;
|
||||
|
||||
private:
|
||||
|
||||
// true if layout manages the z value for this item
|
||||
@ -800,11 +815,6 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
|
||||
void setScenePos( const QPointF &destinationPos );
|
||||
bool shouldBlockUndoCommands() const;
|
||||
|
||||
/**
|
||||
* Returns whether the item should be drawn in the current context.
|
||||
*/
|
||||
bool shouldDrawItem() const;
|
||||
|
||||
friend class TestQgsLayoutItem;
|
||||
friend class TestQgsLayoutView;
|
||||
friend class QgsLayoutItemGroup;
|
||||
|
@ -69,6 +69,12 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
|
||||
|
||||
int type() const override;
|
||||
QString stringType() const override;
|
||||
|
||||
/**
|
||||
* Sets the map id() to a number not yet used in the layout. The existing id() is kept if it is not in use.
|
||||
*/
|
||||
void assignFreeId();
|
||||
|
||||
//overridden to show "Map 1" type names
|
||||
virtual QString displayName() const override;
|
||||
|
||||
@ -79,6 +85,11 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
|
||||
*/
|
||||
static QgsLayoutItemMap *create( QgsLayout *layout ) SIP_FACTORY;
|
||||
|
||||
// for now, map items behave a bit differently and don't implement draw. TODO - see if we can avoid this
|
||||
void paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget ) override;
|
||||
int numberExportLayers() const override;
|
||||
void setFrameStrokeWidth( const QgsLayoutMeasurement &width ) override;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the map scale.
|
||||
@ -351,26 +362,12 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
|
||||
*/
|
||||
void setAtlasMargin( double margin ) { mAtlasMargin = margin; }
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
void draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle = nullptr ) override;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Draw to paint device
|
||||
* \param painter painter
|
||||
* \param extent map extent
|
||||
* \param size size in scene coordinates
|
||||
* \param dpi scene dpi
|
||||
* \param forceWidthScale force wysiwyg line widths / marker sizes
|
||||
*/
|
||||
void draw( QPainter *painter, const QgsRectangle &extent, QSizeF size, double dpi, double *forceWidthScale = nullptr );
|
||||
|
||||
void paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget ) override;
|
||||
|
||||
/**
|
||||
* Return map settings that would be used for drawing of the map
|
||||
* Return map settings that will be used for drawing of the map.
|
||||
*/
|
||||
QgsMapSettings mapSettings( const QgsRectangle &extent, QSizeF size, int dpi ) const;
|
||||
|
||||
@ -397,6 +394,7 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
|
||||
void setOffset( double xOffset, double yOffset );
|
||||
|
||||
#if 0
|
||||
|
||||
/**
|
||||
* Stores state in Dom node
|
||||
* \param elem is Dom element corresponding to 'Composer' tag
|
||||
@ -451,32 +449,15 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
|
||||
#endif
|
||||
QgsExpressionContext createExpressionContext() const override;
|
||||
|
||||
|
||||
signals:
|
||||
void extentChanged();
|
||||
|
||||
//! Is emitted on rotation change to notify north arrow pictures
|
||||
void mapRotationChanged( double newRotation );
|
||||
|
||||
//! Is emitted when the map has been prepared for atlas rendering, just before actual rendering
|
||||
void preparedForAtlas();
|
||||
|
||||
/**
|
||||
* Emitted when layer style overrides are changed... a means to let
|
||||
* associated legend items know they should update
|
||||
* Returns the conversion factor from map units to layout units.
|
||||
* This is calculated using the width of the map item and the width of the
|
||||
* current visible map extent.
|
||||
*/
|
||||
void layerStyleOverridesChanged();
|
||||
double mapUnitsToLayoutUnits() const;
|
||||
|
||||
#if 0
|
||||
|
||||
//! Returns the conversion factor map units -> mm
|
||||
double mapUnitsToMM() const;
|
||||
|
||||
/**
|
||||
* Sets mId to a number not yet used in the composition. mId is kept if it is not in use.
|
||||
Usually, this function is called before adding the composer map to the composition*/
|
||||
void assignFreeId();
|
||||
|
||||
/**
|
||||
* Get the number of layers that this item requires for exporting as layers
|
||||
* \returns 0 if this item is to be placed on the same layer as the previous item,
|
||||
@ -494,7 +475,23 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
|
||||
/**
|
||||
* Calculates the extent to request and the yShift of the top-left point in case of rotation.
|
||||
*/
|
||||
void requestedExtent( QgsRectangle &extent ) const;
|
||||
QgsRectangle requestedExtent() const;
|
||||
|
||||
signals:
|
||||
void extentChanged();
|
||||
|
||||
//! Is emitted on rotation change to notify north arrow pictures
|
||||
void mapRotationChanged( double newRotation );
|
||||
|
||||
//! Is emitted when the map has been prepared for atlas rendering, just before actual rendering
|
||||
void preparedForAtlas();
|
||||
|
||||
/**
|
||||
* Emitted when layer style overrides are changed... a means to let
|
||||
* associated legend items know they should update
|
||||
*/
|
||||
void layerStyleOverridesChanged();
|
||||
|
||||
|
||||
public slots:
|
||||
|
||||
@ -505,18 +502,19 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
|
||||
|
||||
//! Updates the bounding rect of this item. Call this function before doing any changes related to annotation out of the map rectangle
|
||||
void updateBoundingRect();
|
||||
#if 0
|
||||
virtual void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties, const QgsExpressionContext *context = nullptr ) override;
|
||||
#endif
|
||||
|
||||
void refreshDataDefinedProperty( const QgsLayoutObject::DataDefinedProperty property = QgsLayoutObject::AllProperties ) override;
|
||||
|
||||
private slots:
|
||||
void layersAboutToBeRemoved( QList<QgsMapLayer *> layers );
|
||||
void layersAboutToBeRemoved( const QList<QgsMapLayer *> &layers );
|
||||
|
||||
void painterJobFinished();
|
||||
|
||||
private:
|
||||
|
||||
|
||||
//! Unique identifier
|
||||
int mId = 0;
|
||||
int mMapId = 1;
|
||||
#if 0
|
||||
QgsComposerMapGridStack *mGridStack = nullptr;
|
||||
|
||||
@ -544,6 +542,7 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
|
||||
// background
|
||||
std::unique_ptr< QImage > mCacheFinalImage;
|
||||
std::unique_ptr< QImage > mCacheRenderingImage;
|
||||
bool mUpdatesEnabled = true;
|
||||
|
||||
//! True if cached map image must be recreated
|
||||
bool mCacheInvalidated = true;
|
||||
@ -591,8 +590,18 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
|
||||
* is true. May be overridden by data-defined expression. */
|
||||
QString mFollowVisibilityPresetName;
|
||||
|
||||
//! \brief Create cache image
|
||||
void recreateCachedImageInBackground();
|
||||
/**
|
||||
* \brief Draw to paint device
|
||||
* \param painter painter
|
||||
* \param extent map extent
|
||||
* \param size size in scene coordinates
|
||||
* \param dpi scene dpi
|
||||
*/
|
||||
void drawMap( QPainter *painter, const QgsRectangle &extent, QSizeF size, double dpi );
|
||||
|
||||
|
||||
//! Create cache image
|
||||
void recreateCachedImageInBackground( double viewScaleFactor );
|
||||
|
||||
//! Establishes signal/slot connection for update in case of layer change
|
||||
void connectUpdateSlot();
|
||||
@ -647,14 +656,18 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
|
||||
void mapPolygon( const QgsRectangle &extent, QPolygonF &poly ) const;
|
||||
|
||||
/**
|
||||
* Scales a composer map shift (in MM) and rotates it by mRotation
|
||||
\param xShift in: shift in x direction (in item units), out: xShift in map units
|
||||
\param yShift in: shift in y direction (in item units), out: yShift in map units*/
|
||||
* Scales a layout map shift (in layout units) and rotates it by mRotation
|
||||
* \param xShift in: shift in x direction (in item units), out: xShift in map units
|
||||
* \param yShift in: shift in y direction (in item units), out: yShift in map units
|
||||
*/
|
||||
void transformShift( double &xShift, double &yShift ) const;
|
||||
|
||||
void drawAnnotations( QPainter *painter );
|
||||
void drawAnnotation( const QgsAnnotation *item, QgsRenderContext &context );
|
||||
QPointF composerMapPosForItem( const QgsAnnotation *item ) const;
|
||||
QPointF layoutMapPosForItem( const QgsAnnotation *item ) const;
|
||||
|
||||
void drawMapFrame( QPainter *p );
|
||||
void drawMapBackground( QPainter *p );
|
||||
|
||||
enum PartType
|
||||
{
|
||||
@ -666,7 +679,7 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
|
||||
SelectionBoxes
|
||||
};
|
||||
|
||||
//! Test if a part of the copmosermap needs to be drawn, considering mCurrentExportLayer
|
||||
//! Test if a part of the item needs to be drawn, considering the context's current export layer
|
||||
bool shouldDrawPart( PartType part ) const;
|
||||
|
||||
/**
|
||||
@ -675,8 +688,8 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
|
||||
*/
|
||||
void refreshMapExtents( const QgsExpressionContext *context = nullptr );
|
||||
|
||||
friend class QgsComposerMapOverview; //to access mXOffset, mYOffset
|
||||
friend class TestQgsComposerMap;
|
||||
friend class QgsLayoutMapOverview; //to access mXOffset, mYOffset
|
||||
friend class TestQgsLayoutMap;
|
||||
|
||||
};
|
||||
|
||||
|
@ -22,6 +22,16 @@
|
||||
#include <QPainter>
|
||||
#include <cmath>
|
||||
|
||||
void QgsLayoutUtils::rotate( double angle, double &x, double &y )
|
||||
{
|
||||
double rotToRad = angle * M_PI / 180.0;
|
||||
double xRot, yRot;
|
||||
xRot = x * std::cos( rotToRad ) - y * std::sin( rotToRad );
|
||||
yRot = x * std::sin( rotToRad ) + y * std::cos( rotToRad );
|
||||
x = xRot;
|
||||
y = yRot;
|
||||
}
|
||||
|
||||
double QgsLayoutUtils::normalizedAngle( const double angle, const bool allowNegative )
|
||||
{
|
||||
double clippedAngle = angle;
|
||||
|
@ -34,6 +34,14 @@ class CORE_EXPORT QgsLayoutUtils
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Rotates a point / vector around the origin.
|
||||
* \param angle rotation angle in degrees, counterclockwise
|
||||
* \param x in/out: x coordinate before / after the rotation
|
||||
* \param y in/out: y coordinate before / after the rotation
|
||||
*/
|
||||
static void rotate( double angle, double &x, double &y );
|
||||
|
||||
/**
|
||||
* Ensures that an \a angle (in degrees) is in the range 0 <= angle < 360.
|
||||
* If \a allowNegative is true then angles between (-360, 360) are allowed. If false,
|
||||
|
@ -135,6 +135,7 @@ SET(TESTS
|
||||
testqgslayoutcontext.cpp
|
||||
testqgslayoutitem.cpp
|
||||
testqgslayoutitemgroup.cpp
|
||||
testqgslayoutmap.cpp
|
||||
testqgslayoutmodel.cpp
|
||||
testqgslayoutobject.cpp
|
||||
testqgslayoutpage.cpp
|
||||
|
433
tests/src/core/testqgslayoutmap.cpp
Normal file
@ -0,0 +1,433 @@
|
||||
/***************************************************************************
|
||||
testqgslayoutmap.cpp
|
||||
----------------------
|
||||
begin : October 2017
|
||||
copyright : (C) 2017 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsapplication.h"
|
||||
#include "qgslayout.h"
|
||||
#include "qgsmultirenderchecker.h"
|
||||
#include "qgslayoutitemmap.h"
|
||||
#include "qgsmultibandcolorrenderer.h"
|
||||
#include "qgsrasterlayer.h"
|
||||
#include "qgsrasterdataprovider.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsproject.h"
|
||||
#include "qgsmapthemecollection.h"
|
||||
#include "qgsproperty.h"
|
||||
#include <QObject>
|
||||
#include "qgstest.h"
|
||||
|
||||
class TestQgsLayoutMap : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TestQgsLayoutMap() = default;
|
||||
|
||||
private slots:
|
||||
void initTestCase();// will be called before the first testfunction is executed.
|
||||
void cleanupTestCase();// will be called after the last testfunction was executed.
|
||||
void init();// will be called before each testfunction is executed.
|
||||
void cleanup();// will be called after every testfunction.
|
||||
void id();
|
||||
void render();
|
||||
#if 0
|
||||
void uniqueId(); //test if map id is adapted when doing copy paste
|
||||
void worldFileGeneration(); // test world file generation
|
||||
#endif
|
||||
void mapPolygonVertices(); // test mapPolygon function with no map rotation
|
||||
void dataDefinedLayers(); //test data defined layer string
|
||||
void dataDefinedStyles(); //test data defined styles
|
||||
|
||||
private:
|
||||
QgsRasterLayer *mRasterLayer = nullptr;
|
||||
QgsVectorLayer *mPointsLayer = nullptr;
|
||||
QgsVectorLayer *mPolysLayer = nullptr;
|
||||
QgsVectorLayer *mLinesLayer = nullptr;
|
||||
QString mReport;
|
||||
};
|
||||
|
||||
void TestQgsLayoutMap::initTestCase()
|
||||
{
|
||||
QgsApplication::init();
|
||||
QgsApplication::initQgis();
|
||||
|
||||
//create maplayers from testdata and add to layer registry
|
||||
QFileInfo rasterFileInfo( QStringLiteral( TEST_DATA_DIR ) + "/landsat.tif" );
|
||||
mRasterLayer = new QgsRasterLayer( rasterFileInfo.filePath(),
|
||||
rasterFileInfo.completeBaseName() );
|
||||
QgsMultiBandColorRenderer *rasterRenderer = new QgsMultiBandColorRenderer( mRasterLayer->dataProvider(), 2, 3, 4 );
|
||||
mRasterLayer->setRenderer( rasterRenderer );
|
||||
|
||||
QFileInfo pointFileInfo( QStringLiteral( TEST_DATA_DIR ) + "/points.shp" );
|
||||
mPointsLayer = new QgsVectorLayer( pointFileInfo.filePath(),
|
||||
pointFileInfo.completeBaseName(), QStringLiteral( "ogr" ) );
|
||||
|
||||
QFileInfo polyFileInfo( QStringLiteral( TEST_DATA_DIR ) + "/polys.shp" );
|
||||
mPolysLayer = new QgsVectorLayer( polyFileInfo.filePath(),
|
||||
polyFileInfo.completeBaseName(), QStringLiteral( "ogr" ) );
|
||||
|
||||
QFileInfo lineFileInfo( QStringLiteral( TEST_DATA_DIR ) + "/lines.shp" );
|
||||
mLinesLayer = new QgsVectorLayer( lineFileInfo.filePath(),
|
||||
lineFileInfo.completeBaseName(), QStringLiteral( "ogr" ) );
|
||||
|
||||
// some layers need to be in project for data-defined layers functionality
|
||||
QgsProject::instance()->addMapLayers( QList<QgsMapLayer *>() << mRasterLayer << mPointsLayer << mPolysLayer << mLinesLayer );
|
||||
}
|
||||
|
||||
void TestQgsLayoutMap::cleanupTestCase()
|
||||
{
|
||||
QString myReportFile = QDir::tempPath() + "/qgistest.html";
|
||||
QFile myFile( myReportFile );
|
||||
if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
|
||||
{
|
||||
QTextStream myQTextStream( &myFile );
|
||||
myQTextStream << mReport;
|
||||
myFile.close();
|
||||
}
|
||||
|
||||
QgsApplication::exitQgis();
|
||||
}
|
||||
|
||||
void TestQgsLayoutMap::init()
|
||||
{
|
||||
#if 0
|
||||
//create composition with composer map
|
||||
mComposition = new QgsComposition( QgsProject::instance() );
|
||||
mComposition->setPaperSize( 297, 210 ); //A4 landscape
|
||||
mComposerMap = new QgsComposerMap( mComposition, 20, 20, 200, 100 );
|
||||
mComposerMap->setFrameEnabled( true );
|
||||
mComposerMap->setLayers( QList<QgsMapLayer *>() << mRasterLayer );
|
||||
mComposition->addComposerMap( mComposerMap );
|
||||
#endif
|
||||
mReport = QStringLiteral( "<h1>Composer Map Tests</h1>\n" );
|
||||
}
|
||||
|
||||
void TestQgsLayoutMap::cleanup()
|
||||
{
|
||||
}
|
||||
|
||||
void TestQgsLayoutMap::id()
|
||||
{
|
||||
QgsLayout l( QgsProject::instance( ) );
|
||||
QgsLayoutItemMap *map1 = new QgsLayoutItemMap( &l );
|
||||
QCOMPARE( map1->displayName(), QStringLiteral( "Map 1" ) );
|
||||
l.addLayoutItem( map1 );
|
||||
|
||||
QgsLayoutItemMap *map2 = new QgsLayoutItemMap( &l );
|
||||
QCOMPARE( map2->displayName(), QStringLiteral( "Map 2" ) );
|
||||
l.addLayoutItem( map2 );
|
||||
|
||||
map1->setId( "my map" );
|
||||
QCOMPARE( map1->displayName(), QStringLiteral( "my map" ) );
|
||||
|
||||
// existing name should be recycled
|
||||
l.removeLayoutItem( map1 );
|
||||
QgsLayoutItemMap *map3 = new QgsLayoutItemMap( &l );
|
||||
QCOMPARE( map3->displayName(), QStringLiteral( "Map 1" ) );
|
||||
l.addLayoutItem( map3 );
|
||||
|
||||
}
|
||||
|
||||
|
||||
void TestQgsLayoutMap::render()
|
||||
{
|
||||
QgsLayout l( QgsProject::instance() );
|
||||
l.initializeDefaults();
|
||||
QgsLayoutItemMap *map = new QgsLayoutItemMap( &l );
|
||||
map->attemptSetSceneRect( QRectF( 20, 20, 200, 100 ) );
|
||||
map->setFrameEnabled( true );
|
||||
map->setLayers( QList<QgsMapLayer *>() << mRasterLayer );
|
||||
l.addLayoutItem( map );
|
||||
|
||||
map->setExtent( QgsRectangle( 781662.375, 3339523.125, 793062.375, 3345223.125 ) );
|
||||
QgsLayoutChecker checker( QStringLiteral( "composermap_render" ), &l );
|
||||
checker.setControlPathPrefix( QStringLiteral( "composer_map" ) );
|
||||
|
||||
QVERIFY( checker.testLayout( mReport, 0, 0 ) );
|
||||
}
|
||||
#if 0
|
||||
void TestQgsLayoutMap::uniqueId()
|
||||
{
|
||||
QDomDocument doc;
|
||||
QDomElement documentElement = doc.createElement( QStringLiteral( "ComposerItemClipboard" ) );
|
||||
mComposerMap->writeXml( documentElement, doc );
|
||||
mComposition->addItemsFromXml( documentElement, doc, false );
|
||||
|
||||
//test if both composer maps have different ids
|
||||
const QgsComposerMap *newMap = 0;
|
||||
QList<const QgsComposerMap *> mapList = mComposition->composerMapItems();
|
||||
QList<const QgsComposerMap *>::const_iterator mapIt = mapList.constBegin();
|
||||
for ( ; mapIt != mapList.constEnd(); ++mapIt )
|
||||
{
|
||||
if ( *mapIt != mComposerMap )
|
||||
{
|
||||
newMap = *mapIt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QVERIFY( newMap );
|
||||
|
||||
int oldId = mComposerMap->id();
|
||||
int newId = newMap->id();
|
||||
|
||||
mComposition->removeComposerItem( const_cast<QgsComposerMap *>( newMap ) );
|
||||
|
||||
QVERIFY( oldId != newId );
|
||||
}
|
||||
|
||||
void TestQgsLayoutMap::worldFileGeneration()
|
||||
{
|
||||
mComposerMap->setNewExtent( QgsRectangle( 781662.375, 3339523.125, 793062.375, 3345223.125 ) );
|
||||
mComposerMap->setMapRotation( 30.0 );
|
||||
|
||||
mComposition->setGenerateWorldFile( true );
|
||||
mComposition->setReferenceMap( mComposerMap );
|
||||
|
||||
double a, b, c, d, e, f;
|
||||
mComposition->computeWorldFileParameters( a, b, c, d, e, f );
|
||||
|
||||
QGSCOMPARENEAR( a, 4.18048, 0.001 );
|
||||
QGSCOMPARENEAR( b, 2.41331, 0.001 );
|
||||
QGSCOMPARENEAR( c, 779444, 1 );
|
||||
QGSCOMPARENEAR( d, 2.4136, 0.001 );
|
||||
QGSCOMPARENEAR( e, -4.17997, 0.001 );
|
||||
QGSCOMPARENEAR( f, 3.34241e+06, 1e+03 );
|
||||
|
||||
//test with map on second page. Parameters should be the same
|
||||
mComposerMap->setItemPosition( 20, 20, QgsComposerItem::UpperLeft, 2 );
|
||||
mComposition->computeWorldFileParameters( a, b, c, d, e, f );
|
||||
|
||||
QGSCOMPARENEAR( a, 4.18048, 0.001 );
|
||||
QGSCOMPARENEAR( b, 2.41331, 0.001 );
|
||||
QGSCOMPARENEAR( c, 779444, 1 );
|
||||
QGSCOMPARENEAR( d, 2.4136, 0.001 );
|
||||
QGSCOMPARENEAR( e, -4.17997, 0.001 );
|
||||
QGSCOMPARENEAR( f, 3.34241e+06, 1e+03 );
|
||||
|
||||
//test computing parameters for specific region
|
||||
mComposerMap->setItemPosition( 20, 20, QgsComposerItem::UpperLeft, 2 );
|
||||
mComposition->computeWorldFileParameters( QRectF( 10, 5, 260, 200 ), a, b, c, d, e, f );
|
||||
|
||||
QGSCOMPARENEAR( a, 4.18061, 0.001 );
|
||||
QGSCOMPARENEAR( b, 2.41321, 0.001 );
|
||||
QGSCOMPARENEAR( c, 773810, 1 );
|
||||
QGSCOMPARENEAR( d, 2.4137, 0.001 );
|
||||
QGSCOMPARENEAR( e, -4.1798, 0.001 );
|
||||
QGSCOMPARENEAR( f, 3.35331e+06, 1e+03 );
|
||||
|
||||
mComposition->setGenerateWorldFile( false );
|
||||
mComposerMap->setMapRotation( 0.0 );
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void TestQgsLayoutMap::mapPolygonVertices()
|
||||
{
|
||||
QgsLayout l( QgsProject::instance() );
|
||||
l.initializeDefaults();
|
||||
QgsLayoutItemMap *map = new QgsLayoutItemMap( &l );
|
||||
map->attemptSetSceneRect( QRectF( 20, 20, 200, 100 ) );
|
||||
map->setFrameEnabled( true );
|
||||
map->setLayers( QList<QgsMapLayer *>() << mRasterLayer );
|
||||
l.addLayoutItem( map );
|
||||
|
||||
map->setExtent( QgsRectangle( 781662.375, 3339523.125, 793062.375, 3345223.125 ) );
|
||||
QPolygonF visibleExtent = map->visibleExtentPolygon();
|
||||
|
||||
//vertices should be returned in clockwise order starting at the top-left point
|
||||
QVERIFY( std::fabs( visibleExtent[0].x() - 781662.375 ) < 0.001 );
|
||||
QVERIFY( std::fabs( visibleExtent[0].y() - 3345223.125 ) < 0.001 );
|
||||
QVERIFY( std::fabs( visibleExtent[1].x() - 793062.375 ) < 0.001 );
|
||||
QVERIFY( std::fabs( visibleExtent[1].y() - 3345223.125 ) < 0.001 );
|
||||
QVERIFY( std::fabs( visibleExtent[2].x() - 793062.375 ) < 0.001 );
|
||||
QVERIFY( std::fabs( visibleExtent[2].y() - 3339523.125 ) < 0.001 );
|
||||
QVERIFY( std::fabs( visibleExtent[3].x() - 781662.375 ) < 0.001 );
|
||||
QVERIFY( std::fabs( visibleExtent[3].y() - 3339523.125 ) < 0.001 );
|
||||
|
||||
//polygon should be closed
|
||||
QVERIFY( visibleExtent.isClosed() );
|
||||
|
||||
//now test with rotated map
|
||||
map->setMapRotation( 10 );
|
||||
visibleExtent = map->visibleExtentPolygon();
|
||||
|
||||
//vertices should be returned in clockwise order starting at the top-left point
|
||||
QVERIFY( std::fabs( visibleExtent[0].x() - 781254.0735015 ) < 0.001 );
|
||||
QVERIFY( std::fabs( visibleExtent[0].y() - 3344190.0324834 ) < 0.001 );
|
||||
QVERIFY( std::fabs( visibleExtent[1].x() - 792480.881886 ) < 0.001 );
|
||||
QVERIFY( std::fabs( visibleExtent[1].y() - 3346169.62171 ) < 0.001 );
|
||||
QVERIFY( std::fabs( visibleExtent[2].x() - 793470.676499 ) < 0.001 );
|
||||
QVERIFY( std::fabs( visibleExtent[2].y() - 3340556.21752 ) < 0.001 );
|
||||
QVERIFY( std::fabs( visibleExtent[3].x() - 782243.868114 ) < 0.001 );
|
||||
QVERIFY( std::fabs( visibleExtent[3].y() - 3338576.62829 ) < 0.001 );
|
||||
|
||||
//polygon should be closed
|
||||
QVERIFY( visibleExtent.isClosed() );
|
||||
|
||||
map->setMapRotation( 0 );
|
||||
|
||||
}
|
||||
|
||||
void TestQgsLayoutMap::dataDefinedLayers()
|
||||
{
|
||||
QgsLayout l( QgsProject::instance() );
|
||||
l.initializeDefaults();
|
||||
QgsLayoutItemMap *map = new QgsLayoutItemMap( &l );
|
||||
map->attemptMove( QgsLayoutPoint( 20, 20 ) );
|
||||
map->attemptResize( QgsLayoutSize( 200, 100 ) );
|
||||
|
||||
map->setFrameEnabled( true );
|
||||
l.addLayoutItem( map );
|
||||
|
||||
//test malformed layer set string
|
||||
map->dataDefinedProperties().setProperty( QgsLayoutObject::MapLayers, QgsProperty::fromExpression( QStringLiteral( "'x'" ) ) );
|
||||
QList<QgsMapLayer *> result = map->layersToRender();
|
||||
QVERIFY( result.isEmpty() );
|
||||
|
||||
map->dataDefinedProperties().setProperty( QgsLayoutObject::MapLayers, QgsProperty::fromExpression( QStringLiteral( "'x|'" ) ) );
|
||||
result = map->layersToRender();
|
||||
QVERIFY( result.isEmpty() );
|
||||
|
||||
//test subset of valid layers
|
||||
map->dataDefinedProperties().setProperty( QgsLayoutObject::MapLayers, QgsProperty::fromExpression(
|
||||
QStringLiteral( "'%1|%2'" ).arg( mPolysLayer->name(), mRasterLayer->name() ) ) );
|
||||
result = map->layersToRender();
|
||||
QCOMPARE( result.count(), 2 );
|
||||
QVERIFY( result.contains( mPolysLayer ) );
|
||||
QVERIFY( result.contains( mRasterLayer ) );
|
||||
|
||||
//test non-existent layer
|
||||
map->dataDefinedProperties().setProperty( QgsLayoutObject::MapLayers, QgsProperty::fromExpression(
|
||||
QStringLiteral( "'x|%1|%2'" ).arg( mLinesLayer->name(), mPointsLayer->name() ) ) );
|
||||
result = map->layersToRender();
|
||||
QCOMPARE( result.count(), 2 );
|
||||
QVERIFY( result.contains( mLinesLayer ) );
|
||||
QVERIFY( result.contains( mPointsLayer ) );
|
||||
|
||||
//test no layers
|
||||
map->dataDefinedProperties().setProperty( QgsLayoutObject::MapLayers, QgsProperty::fromExpression(
|
||||
QStringLiteral( "''" ) ) );
|
||||
result = map->layersToRender();
|
||||
QVERIFY( result.isEmpty() );
|
||||
|
||||
|
||||
//test with atlas feature evaluation
|
||||
QgsVectorLayer *atlasLayer = new QgsVectorLayer( QStringLiteral( "Point?field=col1:string" ), QStringLiteral( "atlas" ), QStringLiteral( "memory" ) );
|
||||
QVERIFY( atlasLayer->isValid() );
|
||||
QgsFeature f1( atlasLayer->dataProvider()->fields(), 1 );
|
||||
f1.setAttribute( QStringLiteral( "col1" ), mLinesLayer->name() );
|
||||
QgsFeature f2( atlasLayer->dataProvider()->fields(), 1 );
|
||||
f2.setAttribute( QStringLiteral( "col1" ), mPointsLayer->name() );
|
||||
atlasLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 );
|
||||
#if 0 //TODO
|
||||
mComposition->atlasComposition().setCoverageLayer( atlasLayer );
|
||||
mComposition->atlasComposition().setEnabled( true );
|
||||
mComposition->setAtlasMode( QgsComposition::ExportAtlas );
|
||||
mComposition->atlasComposition().beginRender();
|
||||
mComposition->atlasComposition().prepareForFeature( 0 );
|
||||
|
||||
map->dataDefinedProperties().setProperty( QgsLayoutObject::MapLayers, QgsProperty::fromField( QStringLiteral( "col1" ) ) );
|
||||
result = map->layersToRender();
|
||||
QCOMPARE( result.count(), 1 );
|
||||
QCOMPARE( result.at( 0 ), mLinesLayer );
|
||||
mComposition->atlasComposition().prepareForFeature( 1 );
|
||||
result = map->layersToRender();
|
||||
QCOMPARE( result.count(), 1 );
|
||||
QCOMPARE( result.at( 0 ), mPointsLayer );
|
||||
mComposition->atlasComposition().setEnabled( false );
|
||||
delete atlasLayer;
|
||||
|
||||
#endif
|
||||
|
||||
//render test
|
||||
map->dataDefinedProperties().setProperty( QgsLayoutObject::MapLayers, QgsProperty::fromExpression(
|
||||
QStringLiteral( "'%1|%2'" ).arg( mPolysLayer->name(), mPointsLayer->name() ) ) );
|
||||
map->setExtent( QgsRectangle( -110.0, 25.0, -90, 40.0 ) );
|
||||
|
||||
QgsLayoutChecker checker( QStringLiteral( "composermap_ddlayers" ), &l );
|
||||
checker.setControlPathPrefix( QStringLiteral( "composer_map" ) );
|
||||
QVERIFY( checker.testLayout( mReport, 0, 0 ) );
|
||||
}
|
||||
|
||||
void TestQgsLayoutMap::dataDefinedStyles()
|
||||
{
|
||||
QList<QgsMapLayer *> layers = QList<QgsMapLayer *>() << mRasterLayer << mPolysLayer << mPointsLayer << mLinesLayer;
|
||||
|
||||
QgsLayout l( QgsProject::instance() );
|
||||
l.initializeDefaults();
|
||||
|
||||
QgsLayoutItemMap *map = new QgsLayoutItemMap( &l );
|
||||
map->attemptMove( QgsLayoutPoint( 20, 20 ) );
|
||||
map->attemptResize( QgsLayoutSize( 200, 100 ) );
|
||||
map->setFrameEnabled( true );
|
||||
map->setLayers( layers );
|
||||
l.addLayoutItem( map );
|
||||
|
||||
QgsMapThemeCollection::MapThemeRecord rec;
|
||||
rec.setLayerRecords( QList<QgsMapThemeCollection::MapThemeLayerRecord>()
|
||||
<< QgsMapThemeCollection::MapThemeLayerRecord( mPointsLayer )
|
||||
<< QgsMapThemeCollection::MapThemeLayerRecord( mLinesLayer )
|
||||
);
|
||||
|
||||
QgsProject::instance()->mapThemeCollection()->insert( QStringLiteral( "test preset" ), rec );
|
||||
|
||||
// test following of preset
|
||||
map->setFollowVisibilityPreset( true );
|
||||
map->setFollowVisibilityPresetName( QStringLiteral( "test preset" ) );
|
||||
QSet<QgsMapLayer *> result = map->layersToRender().toSet();
|
||||
QCOMPARE( result.count(), 2 );
|
||||
map->setFollowVisibilityPresetName( QString() );
|
||||
|
||||
//test malformed style string
|
||||
map->dataDefinedProperties().setProperty( QgsLayoutObject::MapStylePreset, QgsProperty::fromExpression( QStringLiteral( "5" ) ) );
|
||||
result = map->layersToRender().toSet();
|
||||
QCOMPARE( result, layers.toSet() );
|
||||
|
||||
//test valid preset
|
||||
map->dataDefinedProperties().setProperty( QgsLayoutObject::MapStylePreset, QgsProperty::fromExpression( QStringLiteral( "'test preset'" ) ) );
|
||||
result = map->layersToRender().toSet();
|
||||
QCOMPARE( result.count(), 2 );
|
||||
QVERIFY( result.contains( mLinesLayer ) );
|
||||
QVERIFY( result.contains( mPointsLayer ) );
|
||||
|
||||
//test non-existent preset
|
||||
map->dataDefinedProperties().setProperty( QgsLayoutObject::MapStylePreset, QgsProperty::fromExpression( QStringLiteral( "'bad preset'" ) ) );
|
||||
result = map->layersToRender().toSet();
|
||||
QCOMPARE( result, layers.toSet() );
|
||||
|
||||
//test that dd layer set overrides style layers
|
||||
map->dataDefinedProperties().setProperty( QgsLayoutObject::MapStylePreset, QgsProperty::fromExpression( QStringLiteral( "'test preset'" ) ) );
|
||||
map->dataDefinedProperties().setProperty( QgsLayoutObject::MapLayers, QgsProperty::fromExpression(
|
||||
QStringLiteral( "'%1'" ).arg( mPolysLayer->name() ) ) );
|
||||
result = map->layersToRender().toSet();
|
||||
QCOMPARE( result.count(), 1 );
|
||||
QVERIFY( result.contains( mPolysLayer ) );
|
||||
map->dataDefinedProperties().setProperty( QgsLayoutObject::MapLayers, QgsProperty() );
|
||||
|
||||
//render test
|
||||
map->dataDefinedProperties().setProperty( QgsLayoutObject::MapStylePreset, QgsProperty::fromExpression( QStringLiteral( "'test preset'" ) ) );
|
||||
map->setExtent( QgsRectangle( -110.0, 25.0, -90, 40.0 ) );
|
||||
|
||||
QgsLayoutChecker checker( QStringLiteral( "composermap_ddstyles" ), &l );
|
||||
checker.setControlPathPrefix( QStringLiteral( "composer_map" ) );
|
||||
QVERIFY( checker.testLayout( mReport, 0, 0 ) );
|
||||
}
|
||||
|
||||
QGSTEST_MAIN( TestQgsLayoutMap )
|
||||
#include "testqgslayoutmap.moc"
|
@ -30,6 +30,7 @@ class TestQgsLayoutUtils: public QObject
|
||||
void cleanupTestCase();// will be called after the last testfunction was executed.
|
||||
void init();// will be called before each testfunction is executed.
|
||||
void cleanup();// will be called after every testfunction.
|
||||
void rotate();
|
||||
void normalizedAngle(); //test normalised angle function
|
||||
void snappedAngle();
|
||||
void createRenderContextFromLayout();
|
||||
@ -69,6 +70,28 @@ void TestQgsLayoutUtils::cleanup()
|
||||
|
||||
}
|
||||
|
||||
void TestQgsLayoutUtils::rotate()
|
||||
{
|
||||
// pairs of lines from before -> expected after position and angle to rotate
|
||||
QList< QPair< QLineF, double > > testVals;
|
||||
testVals << qMakePair( QLineF( 0, 1, 0, 1 ), 0.0 );
|
||||
testVals << qMakePair( QLineF( 0, 1, -1, 0 ), 90.0 );
|
||||
testVals << qMakePair( QLineF( 0, 1, 0, -1 ), 180.0 );
|
||||
testVals << qMakePair( QLineF( 0, 1, 1, 0 ), 270.0 );
|
||||
testVals << qMakePair( QLineF( 0, 1, 0, 1 ), 360.0 );
|
||||
|
||||
//test rotate helper function
|
||||
QList< QPair< QLineF, double > >::const_iterator it = testVals.constBegin();
|
||||
for ( ; it != testVals.constEnd(); ++it )
|
||||
{
|
||||
double x = ( *it ).first.x1();
|
||||
double y = ( *it ).first.y1();
|
||||
QgsLayoutUtils::rotate( ( *it ).second, x, y );
|
||||
QGSCOMPARENEAR( x, ( *it ).first.x2(), 4 * DBL_EPSILON );
|
||||
QGSCOMPARENEAR( y, ( *it ).first.y2(), 4 * DBL_EPSILON );
|
||||
}
|
||||
}
|
||||
|
||||
void TestQgsLayoutUtils::normalizedAngle()
|
||||
{
|
||||
QList< QPair< double, double > > testVals;
|
||||
|
@ -86,6 +86,7 @@ ADD_PYTHON_TEST(PyQgsLayoutGridSettings test_qgslayoutgridsettings.py)
|
||||
ADD_PYTHON_TEST(PyQgsLayoutGuide test_qgslayoutguides.py)
|
||||
ADD_PYTHON_TEST(PyQgsLayoutItem test_qgslayoutitem.py)
|
||||
ADD_PYTHON_TEST(PyQgsLayoutItemPropertiesDialog test_qgslayoutitempropertiesdialog.py)
|
||||
ADD_PYTHON_TEST(PyQgsLayoutMap test_qgslayoutmap.py)
|
||||
ADD_PYTHON_TEST(PyQgsLayoutPolygon test_qgslayoutpolygon.py)
|
||||
ADD_PYTHON_TEST(PyQgsLayoutPolyline test_qgslayoutpolyline.py)
|
||||
ADD_PYTHON_TEST(PyQgsLayoutSnapper test_qgslayoutsnapper.py)
|
||||
|
237
tests/src/python/test_qgslayoutmap.py
Normal file
@ -0,0 +1,237 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""QGIS Unit tests for QgsLayoutItemMap.
|
||||
|
||||
.. note:: This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
"""
|
||||
__author__ = '(C) 2017 Nyall Dawson'
|
||||
__date__ = '20/10/2017'
|
||||
__copyright__ = 'Copyright 2017, The QGIS Project'
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import qgis # NOQA
|
||||
|
||||
import os
|
||||
|
||||
from qgis.PyQt.QtCore import QFileInfo, QRectF
|
||||
from qgis.PyQt.QtXml import QDomDocument
|
||||
from qgis.PyQt.QtGui import QPainter
|
||||
|
||||
from qgis.core import (QgsLayoutItemMap,
|
||||
QgsRectangle,
|
||||
QgsRasterLayer,
|
||||
QgsVectorLayer,
|
||||
QgsLayout,
|
||||
QgsMapSettings,
|
||||
QgsProject,
|
||||
QgsMultiBandColorRenderer,
|
||||
QgsCoordinateReferenceSystem
|
||||
)
|
||||
|
||||
from qgis.testing import start_app, unittest
|
||||
from utilities import unitTestDataPath
|
||||
from qgslayoutchecker import QgsLayoutChecker
|
||||
|
||||
start_app()
|
||||
TEST_DATA_DIR = unitTestDataPath()
|
||||
|
||||
|
||||
class TestQgsComposerMap(unittest.TestCase):
|
||||
|
||||
def __init__(self, methodName):
|
||||
"""Run once on class initialization."""
|
||||
unittest.TestCase.__init__(self, methodName)
|
||||
myPath = os.path.join(TEST_DATA_DIR, 'rgb256x256.png')
|
||||
rasterFileInfo = QFileInfo(myPath)
|
||||
self.raster_layer = QgsRasterLayer(rasterFileInfo.filePath(),
|
||||
rasterFileInfo.completeBaseName())
|
||||
rasterRenderer = QgsMultiBandColorRenderer(
|
||||
self.raster_layer.dataProvider(), 1, 2, 3)
|
||||
self.raster_layer.setRenderer(rasterRenderer)
|
||||
|
||||
myPath = os.path.join(TEST_DATA_DIR, 'points.shp')
|
||||
vector_file_info = QFileInfo(myPath)
|
||||
self.vector_layer = QgsVectorLayer(vector_file_info.filePath(),
|
||||
vector_file_info.completeBaseName(), 'ogr')
|
||||
assert self.vector_layer.isValid()
|
||||
|
||||
# pipe = mRasterLayer.pipe()
|
||||
# assert pipe.set(rasterRenderer), 'Cannot set pipe renderer'
|
||||
QgsProject.instance().addMapLayers([self.raster_layer, self.vector_layer])
|
||||
|
||||
# create composition with composer map
|
||||
self.layout = QgsLayout(QgsProject.instance())
|
||||
self.layout.initializeDefaults()
|
||||
self.map = QgsLayoutItemMap(self.layout)
|
||||
self.map.setFrameEnabled(True)
|
||||
self.map.setLayers([self.raster_layer])
|
||||
self.layout.addLayoutItem(self.map)
|
||||
|
||||
def testOverviewMap(self):
|
||||
return
|
||||
|
||||
overviewMap = QgsLayoutItemMap(self.layout) # , 20, 130, 70, 70)
|
||||
overviewMap.setFrameEnabled(True)
|
||||
overviewMap.setLayers([self.raster_layer])
|
||||
self.layout.addComposerMap(overviewMap)
|
||||
# zoom in
|
||||
myRectangle = QgsRectangle(96, -152, 160, -120)
|
||||
self.map.setNewExtent(myRectangle)
|
||||
myRectangle2 = QgsRectangle(0, -256, 256, 0)
|
||||
overviewMap.setNewExtent(myRectangle2)
|
||||
overviewMap.overview().setFrameMap(self.map.id())
|
||||
checker = QgsLayoutChecker('composermap_overview', self.layout)
|
||||
checker.setControlPathPrefix("composer_mapoverview")
|
||||
myTestResult, myMessage = checker.testComposition()
|
||||
self.layout.removeComposerItem(overviewMap)
|
||||
assert myTestResult, myMessage
|
||||
|
||||
def testOverviewMapBlend(self):
|
||||
return
|
||||
overviewMap = QgsComposerMap(self.layout, 20, 130, 70, 70)
|
||||
overviewMap.setFrameEnabled(True)
|
||||
overviewMap.setLayers([self.raster_layer])
|
||||
self.layout.addComposerMap(overviewMap)
|
||||
# zoom in
|
||||
myRectangle = QgsRectangle(96, -152, 160, -120)
|
||||
self.map.setNewExtent(myRectangle)
|
||||
myRectangle2 = QgsRectangle(0, -256, 256, 0)
|
||||
overviewMap.setNewExtent(myRectangle2)
|
||||
overviewMap.overview().setFrameMap(self.map.id())
|
||||
overviewMap.overview().setBlendMode(QPainter.CompositionMode_Multiply)
|
||||
checker = QgsLayoutChecker('composermap_overview_blending', self.layout)
|
||||
checker.setControlPathPrefix("composer_mapoverview")
|
||||
myTestResult, myMessage = checker.testComposition()
|
||||
self.layout.removeComposerItem(overviewMap)
|
||||
assert myTestResult, myMessage
|
||||
|
||||
def testOverviewMapInvert(self):
|
||||
return
|
||||
overviewMap = QgsComposerMap(self.layout, 20, 130, 70, 70)
|
||||
overviewMap.setFrameEnabled(True)
|
||||
overviewMap.setLayers([self.raster_layer])
|
||||
self.layout.addComposerMap(overviewMap)
|
||||
# zoom in
|
||||
myRectangle = QgsRectangle(96, -152, 160, -120)
|
||||
self.map.setNewExtent(myRectangle)
|
||||
myRectangle2 = QgsRectangle(0, -256, 256, 0)
|
||||
overviewMap.setNewExtent(myRectangle2)
|
||||
overviewMap.overview().setFrameMap(self.map.id())
|
||||
overviewMap.overview().setInverted(True)
|
||||
checker = QgsLayoutChecker('composermap_overview_invert', self.layout)
|
||||
checker.setControlPathPrefix("composer_mapoverview")
|
||||
myTestResult, myMessage = checker.testComposition()
|
||||
self.layout.removeComposerItem(overviewMap)
|
||||
assert myTestResult, myMessage
|
||||
|
||||
def testOverviewMapCenter(self):
|
||||
return
|
||||
overviewMap = QgsComposerMap(self.layout, 20, 130, 70, 70)
|
||||
overviewMap.setFrameEnabled(True)
|
||||
overviewMap.setLayers([self.raster_layer])
|
||||
self.layout.addComposerMap(overviewMap)
|
||||
# zoom in
|
||||
myRectangle = QgsRectangle(192, -288, 320, -224)
|
||||
self.map.setNewExtent(myRectangle)
|
||||
myRectangle2 = QgsRectangle(0, -256, 256, 0)
|
||||
overviewMap.setNewExtent(myRectangle2)
|
||||
overviewMap.overview().setFrameMap(self.map.id())
|
||||
overviewMap.overview().setInverted(False)
|
||||
overviewMap.overview().setCentered(True)
|
||||
checker = QgsLayoutChecker('composermap_overview_center', self.layout)
|
||||
checker.setControlPathPrefix("composer_mapoverview")
|
||||
myTestResult, myMessage = checker.testComposition()
|
||||
self.layout.removeComposerItem(overviewMap)
|
||||
assert myTestResult, myMessage
|
||||
|
||||
def testMapCrs(self):
|
||||
# create composition with composer map
|
||||
map_settings = QgsMapSettings()
|
||||
map_settings.setLayers([self.vector_layer])
|
||||
layout = QgsLayout(QgsProject.instance())
|
||||
layout.initializeDefaults()
|
||||
|
||||
# check that new maps inherit project CRS
|
||||
QgsProject.instance().setCrs(QgsCoordinateReferenceSystem('EPSG:4326'))
|
||||
map = QgsLayoutItemMap(layout)
|
||||
map.attemptSetSceneRect(QRectF(20, 20, 200, 100))
|
||||
map.setFrameEnabled(True)
|
||||
rectangle = QgsRectangle(-13838977, 2369660, -8672298, 6250909)
|
||||
map.setExtent(rectangle)
|
||||
map.setLayers([self.vector_layer])
|
||||
layout.addLayoutItem(map)
|
||||
|
||||
self.assertEqual(map.crs().authid(), 'EPSG:4326')
|
||||
self.assertFalse(map.presetCrs().isValid())
|
||||
|
||||
# overwrite CRS
|
||||
map.setCrs(QgsCoordinateReferenceSystem('EPSG:3857'))
|
||||
self.assertEqual(map.crs().authid(), 'EPSG:3857')
|
||||
self.assertEqual(map.presetCrs().authid(), 'EPSG:3857')
|
||||
|
||||
checker = QgsLayoutChecker('composermap_crs3857', layout)
|
||||
checker.setControlPathPrefix("composer_map")
|
||||
result, message = checker.testLayout()
|
||||
self.assertTrue(result, message)
|
||||
|
||||
# overwrite CRS
|
||||
map.setCrs(QgsCoordinateReferenceSystem('EPSG:4326'))
|
||||
self.assertEqual(map.presetCrs().authid(), 'EPSG:4326')
|
||||
self.assertEqual(map.crs().authid(), 'EPSG:4326')
|
||||
rectangle = QgsRectangle(-124, 17, -78, 52)
|
||||
map.zoomToExtent(rectangle)
|
||||
checker = QgsLayoutChecker('composermap_crs4326', layout)
|
||||
checker.setControlPathPrefix("composer_map")
|
||||
result, message = checker.testLayout()
|
||||
self.assertTrue(result, message)
|
||||
|
||||
# change back to project CRS
|
||||
map.setCrs(QgsCoordinateReferenceSystem())
|
||||
self.assertEqual(map.crs().authid(), 'EPSG:4326')
|
||||
self.assertFalse(map.presetCrs().isValid())
|
||||
|
||||
def testuniqueId(self):
|
||||
return
|
||||
doc = QDomDocument()
|
||||
documentElement = doc.createElement('ComposerItemClipboard')
|
||||
self.layout.writeXml(documentElement, doc)
|
||||
self.layout.addItemsFromXml(documentElement, doc)
|
||||
|
||||
# test if both composer maps have different ids
|
||||
newMap = QgsComposerMap(self.layout, 0, 0, 10, 10)
|
||||
mapList = self.layout.composerMapItems()
|
||||
|
||||
for mapIt in mapList:
|
||||
if mapIt != self.map:
|
||||
newMap = mapIt
|
||||
break
|
||||
|
||||
oldId = self.map.id()
|
||||
newId = newMap.id()
|
||||
|
||||
self.layout.removeComposerItem(newMap)
|
||||
myMessage = 'old: %s new: %s' % (oldId, newId)
|
||||
assert oldId != newId, myMessage
|
||||
|
||||
def testWorldFileGeneration(self):
|
||||
return
|
||||
myRectangle = QgsRectangle(781662.375, 3339523.125, 793062.375, 3345223.125)
|
||||
self.map.setNewExtent(myRectangle)
|
||||
self.map.setMapRotation(30.0)
|
||||
|
||||
self.layout.setGenerateWorldFile(True)
|
||||
self.layout.setReferenceMap(self.map)
|
||||
|
||||
p = self.layout.computeWorldFileParameters()
|
||||
pexpected = (4.180480199790922, 2.4133064516129026, 779443.7612381146,
|
||||
2.4136013686911886, -4.179969388427311, 3342408.5663611)
|
||||
ptolerance = (0.001, 0.001, 1, 0.001, 0.001, 1e+03)
|
||||
for i in range(0, 6):
|
||||
assert abs(p[i] - pexpected[i]) < ptolerance[i]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 61 KiB |