Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsellipsesymbollayer.cpp
3 : : ---------------------
4 : : begin : June 2011
5 : : copyright : (C) 2011 by Marco Hugentobler
6 : : email : marco dot hugentobler at sourcepole dot ch
7 : : ***************************************************************************
8 : : * *
9 : : * This program is free software; you can redistribute it and/or modify *
10 : : * it under the terms of the GNU General Public License as published by *
11 : : * the Free Software Foundation; either version 2 of the License, or *
12 : : * (at your option) any later version. *
13 : : * *
14 : : ***************************************************************************/
15 : : #include "qgsellipsesymbollayer.h"
16 : : #include "qgsdxfexport.h"
17 : : #include "qgsexpression.h"
18 : : #include "qgsfeature.h"
19 : : #include "qgsrendercontext.h"
20 : : #include "qgsvectorlayer.h"
21 : : #include "qgslogger.h"
22 : : #include "qgsunittypes.h"
23 : : #include "qgsproperty.h"
24 : : #include "qgssymbollayerutils.h"
25 : :
26 : : #include <QPainter>
27 : : #include <QSet>
28 : : #include <QDomDocument>
29 : : #include <QDomElement>
30 : :
31 : 0 : QgsEllipseSymbolLayer::QgsEllipseSymbolLayer()
32 : 0 : : mStrokeColor( QColor( 35, 35, 35 ) )
33 : 0 : {
34 : 0 : mColor = Qt::white;
35 : 0 : mPen.setColor( mStrokeColor );
36 : 0 : mPen.setStyle( mStrokeStyle );
37 : 0 : mPen.setJoinStyle( mPenJoinStyle );
38 : 0 : mPen.setWidth( 1.0 );
39 : 0 : mBrush.setColor( mColor );
40 : 0 : mBrush.setStyle( Qt::SolidPattern );
41 : 0 : mOffset = QPointF( 0, 0 );
42 : 0 : mAngle = 0;
43 : 0 : }
44 : :
45 : 0 : QgsSymbolLayer *QgsEllipseSymbolLayer::create( const QVariantMap &properties )
46 : : {
47 : 0 : QgsEllipseSymbolLayer *layer = new QgsEllipseSymbolLayer();
48 : 0 : if ( properties.contains( QStringLiteral( "symbol_name" ) ) )
49 : : {
50 : 0 : layer->setShape( decodeShape( properties[ QStringLiteral( "symbol_name" )].toString() ) );
51 : 0 : }
52 : 0 : if ( properties.contains( QStringLiteral( "size" ) ) )
53 : : {
54 : 0 : layer->setSize( properties[QStringLiteral( "size" )].toDouble() );
55 : 0 : }
56 : 0 : if ( properties.contains( QStringLiteral( "size_unit" ) ) )
57 : : {
58 : 0 : layer->setSizeUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "size_unit" )].toString() ) );
59 : 0 : }
60 : 0 : if ( properties.contains( QStringLiteral( "size_map_unit_scale" ) ) )
61 : : {
62 : 0 : layer->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "size_map_unit_scale" )].toString() ) );
63 : 0 : }
64 : 0 : if ( properties.contains( QStringLiteral( "symbol_width" ) ) )
65 : : {
66 : 0 : layer->setSymbolWidth( properties[QStringLiteral( "symbol_width" )].toDouble() );
67 : 0 : }
68 : 0 : if ( properties.contains( QStringLiteral( "symbol_width_unit" ) ) )
69 : : {
70 : 0 : layer->setSymbolWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "symbol_width_unit" )].toString() ) );
71 : 0 : }
72 : 0 : if ( properties.contains( QStringLiteral( "symbol_width_map_unit_scale" ) ) )
73 : : {
74 : 0 : layer->setSymbolWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "symbol_width_map_unit_scale" )].toString() ) );
75 : 0 : }
76 : 0 : if ( properties.contains( QStringLiteral( "symbol_height" ) ) )
77 : : {
78 : 0 : layer->setSymbolHeight( properties[QStringLiteral( "symbol_height" )].toDouble() );
79 : 0 : }
80 : 0 : if ( properties.contains( QStringLiteral( "symbol_height_unit" ) ) )
81 : : {
82 : 0 : layer->setSymbolHeightUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "symbol_height_unit" )].toString() ) );
83 : 0 : }
84 : 0 : if ( properties.contains( QStringLiteral( "symbol_height_map_unit_scale" ) ) )
85 : : {
86 : 0 : layer->setSymbolHeightMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "symbol_height_map_unit_scale" )].toString() ) );
87 : 0 : }
88 : 0 : if ( properties.contains( QStringLiteral( "angle" ) ) )
89 : : {
90 : 0 : layer->setAngle( properties[QStringLiteral( "angle" )].toDouble() );
91 : 0 : }
92 : 0 : if ( properties.contains( QStringLiteral( "outline_style" ) ) )
93 : : {
94 : 0 : layer->setStrokeStyle( QgsSymbolLayerUtils::decodePenStyle( properties[QStringLiteral( "outline_style" )].toString() ) );
95 : 0 : }
96 : 0 : else if ( properties.contains( QStringLiteral( "line_style" ) ) )
97 : : {
98 : 0 : layer->setStrokeStyle( QgsSymbolLayerUtils::decodePenStyle( properties[QStringLiteral( "line_style" )].toString() ) );
99 : 0 : }
100 : 0 : if ( properties.contains( QStringLiteral( "joinstyle" ) ) )
101 : : {
102 : 0 : layer->setPenJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( properties[QStringLiteral( "joinstyle" )].toString() ) );
103 : 0 : }
104 : 0 : if ( properties.contains( QStringLiteral( "cap_style" ) ) )
105 : : {
106 : 0 : layer->setPenCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( properties[QStringLiteral( "cap_style" )].toString() ) );
107 : 0 : }
108 : 0 : if ( properties.contains( QStringLiteral( "outline_width" ) ) )
109 : : {
110 : 0 : layer->setStrokeWidth( properties[QStringLiteral( "outline_width" )].toDouble() );
111 : 0 : }
112 : 0 : else if ( properties.contains( QStringLiteral( "line_width" ) ) )
113 : : {
114 : 0 : layer->setStrokeWidth( properties[QStringLiteral( "line_width" )].toDouble() );
115 : 0 : }
116 : 0 : if ( properties.contains( QStringLiteral( "outline_width_unit" ) ) )
117 : : {
118 : 0 : layer->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "outline_width_unit" )].toString() ) );
119 : 0 : }
120 : 0 : else if ( properties.contains( QStringLiteral( "line_width_unit" ) ) )
121 : : {
122 : 0 : layer->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "line_width_unit" )].toString() ) );
123 : 0 : }
124 : 0 : if ( properties.contains( QStringLiteral( "outline_width_map_unit_scale" ) ) )
125 : : {
126 : 0 : layer->setStrokeWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "outline_width_map_unit_scale" )].toString() ) );
127 : 0 : }
128 : 0 : if ( properties.contains( QStringLiteral( "fill_color" ) ) )
129 : : {
130 : : //pre 2.5 projects used "fill_color"
131 : 0 : layer->setFillColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "fill_color" )].toString() ) );
132 : 0 : }
133 : 0 : else if ( properties.contains( QStringLiteral( "color" ) ) )
134 : : {
135 : 0 : layer->setFillColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "color" )].toString() ) );
136 : 0 : }
137 : 0 : if ( properties.contains( QStringLiteral( "outline_color" ) ) )
138 : : {
139 : 0 : layer->setStrokeColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "outline_color" )].toString() ) );
140 : 0 : }
141 : 0 : else if ( properties.contains( QStringLiteral( "line_color" ) ) )
142 : : {
143 : 0 : layer->setStrokeColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "line_color" )].toString() ) );
144 : 0 : }
145 : 0 : if ( properties.contains( QStringLiteral( "offset" ) ) )
146 : : {
147 : 0 : layer->setOffset( QgsSymbolLayerUtils::decodePoint( properties[QStringLiteral( "offset" )].toString() ) );
148 : 0 : }
149 : 0 : if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
150 : : {
151 : 0 : layer->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )].toString() ) );
152 : 0 : }
153 : 0 : if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
154 : : {
155 : 0 : layer->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
156 : 0 : }
157 : 0 : if ( properties.contains( QStringLiteral( "horizontal_anchor_point" ) ) )
158 : : {
159 : 0 : layer->setHorizontalAnchorPoint( QgsMarkerSymbolLayer::HorizontalAnchorPoint( properties[ QStringLiteral( "horizontal_anchor_point" )].toInt() ) );
160 : 0 : }
161 : 0 : if ( properties.contains( QStringLiteral( "vertical_anchor_point" ) ) )
162 : : {
163 : 0 : layer->setVerticalAnchorPoint( QgsMarkerSymbolLayer::VerticalAnchorPoint( properties[ QStringLiteral( "vertical_anchor_point" )].toInt() ) );
164 : 0 : }
165 : :
166 : : //data defined properties
167 : 0 : layer->restoreOldDataDefinedProperties( properties );
168 : :
169 : 0 : return layer;
170 : 0 : }
171 : :
172 : 0 : void QgsEllipseSymbolLayer::renderPoint( QPointF point, QgsSymbolRenderContext &context )
173 : : {
174 : 0 : double scaledWidth = mSymbolWidth;
175 : 0 : double scaledHeight = mSymbolHeight;
176 : :
177 : 0 : QColor brushColor = mColor;
178 : 0 : brushColor.setAlphaF( brushColor.alphaF() * context.opacity() );
179 : 0 : mBrush.setColor( brushColor );
180 : :
181 : 0 : QColor penColor = mStrokeColor;
182 : 0 : penColor.setAlphaF( penColor.alphaF() * context.opacity() );
183 : 0 : mPen.setColor( penColor );
184 : :
185 : : bool ok;
186 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
187 : : {
188 : 0 : context.setOriginalValueVariable( mStrokeWidth );
189 : 0 : QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext() );
190 : 0 : if ( exprVal.isValid() )
191 : : {
192 : 0 : double width = exprVal.toDouble( &ok );
193 : 0 : if ( ok )
194 : : {
195 : 0 : width = context.renderContext().convertToPainterUnits( width, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
196 : 0 : mPen.setWidthF( width );
197 : 0 : mSelPen.setWidthF( width );
198 : 0 : }
199 : 0 : }
200 : 0 : }
201 : :
202 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeStyle ) )
203 : : {
204 : 0 : context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePenStyle( mStrokeStyle ) );
205 : 0 : QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyStrokeStyle, context.renderContext().expressionContext() );
206 : 0 : if ( exprVal.isValid() )
207 : : {
208 : 0 : mPen.setStyle( QgsSymbolLayerUtils::decodePenStyle( exprVal.toString() ) );
209 : 0 : mSelPen.setStyle( mPen.style() );
210 : 0 : }
211 : 0 : }
212 : :
213 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyJoinStyle ) )
214 : : {
215 : 0 : context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle ) );
216 : 0 : QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyJoinStyle, context.renderContext().expressionContext() );
217 : 0 : if ( exprVal.isValid() )
218 : : {
219 : 0 : mPen.setJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( exprVal.toString() ) );
220 : 0 : mSelPen.setJoinStyle( mPen.joinStyle() );
221 : 0 : }
222 : 0 : }
223 : :
224 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyCapStyle ) )
225 : : {
226 : 0 : context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePenCapStyle( mPenCapStyle ) );
227 : 0 : QString style = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyCapStyle, context.renderContext().expressionContext(), QString(), &ok );
228 : 0 : if ( ok )
229 : : {
230 : 0 : mPen.setCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( style ) );
231 : 0 : mSelPen.setCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( style ) );
232 : 0 : }
233 : 0 : }
234 : :
235 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFillColor ) )
236 : : {
237 : 0 : context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mColor ) );
238 : 0 : QColor brushColor = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyFillColor, context.renderContext().expressionContext(), mColor );
239 : 0 : brushColor.setAlphaF( brushColor.alphaF() * context.opacity() );
240 : 0 : mBrush.setColor( brushColor );
241 : 0 : }
242 : :
243 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeColor ) )
244 : 0 : {
245 : 0 : context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mStrokeColor ) );
246 : 0 : QColor penColor = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyStrokeColor, context.renderContext().expressionContext(), mStrokeColor );
247 : 0 : penColor.setAlphaF( penColor.alphaF() * context.opacity() );
248 : 0 : mPen.setColor( penColor );
249 : 0 : }
250 : :
251 : 0 : QgsEllipseSymbolLayer::Shape shape = mShape;
252 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) || mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) || mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyName ) )
253 : 0 : {
254 : 0 : context.setOriginalValueVariable( encodeShape( shape ) );
255 : 0 : QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyName, context.renderContext().expressionContext() );
256 : 0 : if ( exprVal.isValid() )
257 : : {
258 : 0 : shape = decodeShape( exprVal.toString() );
259 : 0 : }
260 : 0 : preparePath( shape, context, &scaledWidth, &scaledHeight, context.feature() );
261 : 0 : }
262 : :
263 : : //offset and rotation
264 : 0 : bool hasDataDefinedRotation = false;
265 : 0 : QPointF offset;
266 : 0 : double angle = 0;
267 : 0 : calculateOffsetAndRotation( context, scaledWidth, scaledHeight, hasDataDefinedRotation, offset, angle );
268 : :
269 : 0 : QPainter *p = context.renderContext().painter();
270 : 0 : if ( !p )
271 : : {
272 : 0 : return;
273 : : }
274 : :
275 : 0 : QTransform transform;
276 : 0 : transform.translate( point.x() + offset.x(), point.y() + offset.y() );
277 : 0 : if ( !qgsDoubleNear( angle, 0.0 ) )
278 : : {
279 : 0 : transform.rotate( angle );
280 : 0 : }
281 : :
282 : 0 : if ( shapeIsFilled( shape ) )
283 : : {
284 : 0 : p->setPen( context.selected() ? mSelPen : mPen );
285 : 0 : p->setBrush( context.selected() ? mSelBrush : mBrush );
286 : 0 : }
287 : : else
288 : : {
289 : 0 : p->setPen( context.selected() ? mSelPen : mPen );
290 : 0 : p->setBrush( QBrush() );
291 : : }
292 : 0 : p->drawPath( transform.map( mPainterPath ) );
293 : 0 : }
294 : :
295 : :
296 : 0 : void QgsEllipseSymbolLayer::calculateOffsetAndRotation( QgsSymbolRenderContext &context,
297 : : double scaledWidth,
298 : : double scaledHeight,
299 : : bool &hasDataDefinedRotation,
300 : : QPointF &offset,
301 : : double &angle ) const
302 : : {
303 : 0 : double offsetX = 0;
304 : 0 : double offsetY = 0;
305 : 0 : markerOffset( context, scaledWidth, scaledHeight, mSymbolWidthUnit, mSymbolHeightUnit, offsetX, offsetY, mSymbolWidthMapUnitScale, mSymbolHeightMapUnitScale );
306 : 0 : offset = QPointF( offsetX, offsetY );
307 : :
308 : : //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
309 : 0 : bool ok = true;
310 : 0 : angle = mAngle + mLineAngle;
311 : 0 : bool usingDataDefinedRotation = false;
312 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle ) )
313 : : {
314 : 0 : context.setOriginalValueVariable( angle );
315 : 0 : angle = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyAngle, context.renderContext().expressionContext(), 0 ) + mLineAngle;
316 : 0 : usingDataDefinedRotation = ok;
317 : 0 : }
318 : :
319 : 0 : hasDataDefinedRotation = context.renderHints() & QgsSymbol::DynamicRotation || usingDataDefinedRotation;
320 : 0 : if ( hasDataDefinedRotation )
321 : : {
322 : : // For non-point markers, "dataDefinedRotation" means following the
323 : : // shape (shape-data defined). For them, "field-data defined" does
324 : : // not work at all. TODO: if "field-data defined" ever gets implemented
325 : : // we'll need a way to distinguish here between the two, possibly
326 : : // using another flag in renderHints()
327 : 0 : const QgsFeature *f = context.feature();
328 : 0 : if ( f )
329 : : {
330 : 0 : const QgsGeometry g = f->geometry();
331 : 0 : if ( !g.isNull() && g.type() == QgsWkbTypes::PointGeometry )
332 : : {
333 : 0 : const QgsMapToPixel &m2p = context.renderContext().mapToPixel();
334 : 0 : angle += m2p.mapRotation();
335 : 0 : }
336 : 0 : }
337 : 0 : }
338 : :
339 : 0 : if ( angle )
340 : 0 : offset = _rotatedOffset( offset, angle );
341 : 0 : }
342 : :
343 : 0 : QString QgsEllipseSymbolLayer::layerType() const
344 : : {
345 : 0 : return QStringLiteral( "EllipseMarker" );
346 : : }
347 : :
348 : 0 : void QgsEllipseSymbolLayer::startRender( QgsSymbolRenderContext &context )
349 : : {
350 : 0 : QgsMarkerSymbolLayer::startRender( context ); // get anchor point expressions
351 : 0 : if ( !context.feature() || !dataDefinedProperties().hasActiveProperties() )
352 : : {
353 : 0 : preparePath( mShape, context );
354 : 0 : }
355 : 0 : mPen.setColor( mStrokeColor );
356 : 0 : mPen.setStyle( mStrokeStyle );
357 : 0 : mPen.setJoinStyle( mPenJoinStyle );
358 : 0 : mPen.setCapStyle( mPenCapStyle );
359 : 0 : mPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
360 : 0 : mBrush.setColor( mColor );
361 : :
362 : 0 : QColor selBrushColor = context.renderContext().selectionColor();
363 : 0 : QColor selPenColor = selBrushColor == mColor ? selBrushColor : mStrokeColor;
364 : 0 : if ( context.opacity() < 1 && !SELECTION_IS_OPAQUE )
365 : : {
366 : 0 : selBrushColor.setAlphaF( context.opacity() );
367 : 0 : selPenColor.setAlphaF( context.opacity() );
368 : 0 : }
369 : 0 : mSelBrush = QBrush( selBrushColor );
370 : 0 : mSelPen = QPen( !shapeIsFilled( mShape ) ? selBrushColor : selPenColor );
371 : 0 : mSelPen.setStyle( mStrokeStyle );
372 : 0 : mSelPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
373 : 0 : }
374 : :
375 : 0 : void QgsEllipseSymbolLayer::stopRender( QgsSymbolRenderContext & )
376 : : {
377 : 0 : }
378 : :
379 : 0 : QgsEllipseSymbolLayer *QgsEllipseSymbolLayer::clone() const
380 : : {
381 : 0 : QgsEllipseSymbolLayer *m = new QgsEllipseSymbolLayer();
382 : 0 : m->setShape( mShape );
383 : 0 : m->setSymbolWidth( mSymbolWidth );
384 : 0 : m->setSymbolHeight( mSymbolHeight );
385 : 0 : m->setStrokeStyle( mStrokeStyle );
386 : 0 : m->setOffset( mOffset );
387 : 0 : m->setOffsetUnit( mOffsetUnit );
388 : 0 : m->setOffsetMapUnitScale( mOffsetMapUnitScale );
389 : 0 : m->setStrokeStyle( mStrokeStyle );
390 : 0 : m->setPenJoinStyle( mPenJoinStyle );
391 : 0 : m->setPenCapStyle( mPenCapStyle );
392 : 0 : m->setStrokeWidth( mStrokeWidth );
393 : 0 : m->setColor( color() );
394 : 0 : m->setStrokeColor( mStrokeColor );
395 : 0 : m->setSymbolWidthUnit( mSymbolWidthUnit );
396 : 0 : m->setSymbolWidthMapUnitScale( mSymbolWidthMapUnitScale );
397 : 0 : m->setSymbolHeightUnit( mSymbolHeightUnit );
398 : 0 : m->setSymbolHeightMapUnitScale( mSymbolHeightMapUnitScale );
399 : 0 : m->setStrokeWidthUnit( mStrokeWidthUnit );
400 : 0 : m->setStrokeWidthMapUnitScale( mStrokeWidthMapUnitScale );
401 : 0 : m->setAngle( mAngle );
402 : 0 : m->setHorizontalAnchorPoint( mHorizontalAnchorPoint );
403 : 0 : m->setVerticalAnchorPoint( mVerticalAnchorPoint );
404 : :
405 : 0 : copyDataDefinedProperties( m );
406 : 0 : copyPaintEffect( m );
407 : 0 : return m;
408 : 0 : }
409 : :
410 : 0 : void QgsEllipseSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
411 : : {
412 : 0 : QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PointSymbolizer" ) );
413 : 0 : if ( !props.value( QStringLiteral( "uom" ), QString() ).toString().isEmpty() )
414 : 0 : symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ).toString() );
415 : 0 : element.appendChild( symbolizerElem );
416 : :
417 : : // <Geometry>
418 : 0 : QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ).toString() );
419 : :
420 : 0 : writeSldMarker( doc, symbolizerElem, props );
421 : 0 : }
422 : :
423 : 0 : void QgsEllipseSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
424 : : {
425 : : // <Graphic>
426 : 0 : QDomElement graphicElem = doc.createElement( QStringLiteral( "se:Graphic" ) );
427 : 0 : element.appendChild( graphicElem );
428 : :
429 : 0 : double strokeWidth = QgsSymbolLayerUtils::rescaleUom( mStrokeWidth, mStrokeWidthUnit, props );
430 : 0 : double symbolWidth = QgsSymbolLayerUtils::rescaleUom( mSymbolWidth, mSymbolWidthUnit, props );
431 : 0 : QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, encodeShape( mShape ), mColor, mStrokeColor, mStrokeStyle, strokeWidth, symbolWidth );
432 : :
433 : : // <Rotation>
434 : 0 : QgsProperty ddRotation = mDataDefinedProperties.property( QgsSymbolLayer::PropertyAngle );
435 : :
436 : 0 : QString angleFunc = props.value( QStringLiteral( "angle" ), QString() ).toString();
437 : 0 : if ( angleFunc.isEmpty() ) // symbol has no angle set
438 : : {
439 : 0 : if ( ddRotation && ddRotation.isActive() )
440 : : {
441 : 0 : angleFunc = ddRotation.asExpression();
442 : 0 : }
443 : 0 : else if ( !qgsDoubleNear( mAngle, 0.0 ) )
444 : 0 : angleFunc = QString::number( mAngle );
445 : 0 : }
446 : 0 : else if ( ddRotation && ddRotation.isActive() )
447 : : {
448 : : // the symbol has an angle and the symbol layer have a rotation
449 : : // property set
450 : 0 : angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc, ddRotation.asExpression() );
451 : 0 : }
452 : 0 : else if ( !qgsDoubleNear( mAngle, 0.0 ) )
453 : : {
454 : : // both the symbol and the symbol layer have angle value set
455 : : bool ok;
456 : 0 : double angle = angleFunc.toDouble( &ok );
457 : 0 : if ( !ok )
458 : : {
459 : : // its a string (probably a property name or a function)
460 : 0 : angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc ).arg( mAngle );
461 : 0 : }
462 : 0 : else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
463 : : {
464 : : // it's a double value
465 : 0 : angleFunc = QString::number( angle + mAngle );
466 : 0 : }
467 : 0 : }
468 : 0 : QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );
469 : :
470 : : // <Displacement>
471 : 0 : QPointF offset = QgsSymbolLayerUtils::rescaleUom( mOffset, mOffsetUnit, props );
472 : 0 : QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, offset );
473 : :
474 : : // store w/h factor in a <VendorOption>
475 : 0 : double widthHeightFactor = mSymbolWidth / mSymbolHeight;
476 : 0 : QDomElement factorElem = QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "widthHeightFactor" ), QString::number( widthHeightFactor ) );
477 : 0 : graphicElem.appendChild( factorElem );
478 : 0 : }
479 : :
480 : 0 : QgsSymbolLayer *QgsEllipseSymbolLayer::createFromSld( QDomElement &element )
481 : : {
482 : 0 : QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
483 : :
484 : 0 : QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
485 : 0 : if ( graphicElem.isNull() )
486 : 0 : return nullptr;
487 : :
488 : 0 : QString name = QStringLiteral( "circle" );
489 : 0 : QColor fillColor, strokeColor;
490 : : double strokeWidth, size;
491 : 0 : double widthHeightFactor = 1.0;
492 : : Qt::PenStyle strokeStyle;
493 : :
494 : 0 : QgsStringMap vendorOptions = QgsSymbolLayerUtils::getVendorOptionList( graphicElem );
495 : 0 : for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
496 : : {
497 : 0 : if ( it.key() == QLatin1String( "widthHeightFactor" ) )
498 : : {
499 : : bool ok;
500 : 0 : double v = it.value().toDouble( &ok );
501 : 0 : if ( ok && !qgsDoubleNear( v, 0.0 ) && v > 0 )
502 : 0 : widthHeightFactor = v;
503 : 0 : }
504 : 0 : }
505 : :
506 : 0 : if ( !QgsSymbolLayerUtils::wellKnownMarkerFromSld( graphicElem, name, fillColor, strokeColor, strokeStyle, strokeWidth, size ) )
507 : 0 : return nullptr;
508 : :
509 : 0 : QString uom = element.attribute( QStringLiteral( "uom" ) );
510 : 0 : size = QgsSymbolLayerUtils::sizeInPixelsFromSldUom( uom, size );
511 : 0 : strokeWidth = QgsSymbolLayerUtils::sizeInPixelsFromSldUom( uom, strokeWidth );
512 : :
513 : 0 : double angle = 0.0;
514 : 0 : QString angleFunc;
515 : 0 : if ( QgsSymbolLayerUtils::rotationFromSldElement( graphicElem, angleFunc ) )
516 : : {
517 : : bool ok;
518 : 0 : double d = angleFunc.toDouble( &ok );
519 : 0 : if ( ok )
520 : 0 : angle = d;
521 : 0 : }
522 : :
523 : 0 : QgsEllipseSymbolLayer *m = new QgsEllipseSymbolLayer();
524 : 0 : m->setOutputUnit( QgsUnitTypes::RenderUnit::RenderPixels );
525 : 0 : m->setShape( decodeShape( name ) );
526 : 0 : m->setFillColor( fillColor );
527 : 0 : m->setStrokeColor( strokeColor );
528 : 0 : m->setStrokeStyle( strokeStyle );
529 : 0 : m->setStrokeWidth( strokeWidth );
530 : 0 : m->setSymbolWidth( size );
531 : 0 : m->setSymbolHeight( size / widthHeightFactor );
532 : 0 : m->setAngle( angle );
533 : 0 : return m;
534 : 0 : }
535 : :
536 : 0 : QVariantMap QgsEllipseSymbolLayer::properties() const
537 : : {
538 : 0 : QVariantMap map;
539 : 0 : map[QStringLiteral( "symbol_name" )] = encodeShape( mShape );
540 : 0 : map[QStringLiteral( "symbol_width" )] = QString::number( mSymbolWidth );
541 : 0 : map[QStringLiteral( "symbol_width_unit" )] = QgsUnitTypes::encodeUnit( mSymbolWidthUnit );
542 : 0 : map[QStringLiteral( "symbol_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSymbolWidthMapUnitScale );
543 : 0 : map[QStringLiteral( "symbol_height" )] = QString::number( mSymbolHeight );
544 : 0 : map[QStringLiteral( "symbol_height_unit" )] = QgsUnitTypes::encodeUnit( mSymbolHeightUnit );
545 : 0 : map[QStringLiteral( "symbol_height_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSymbolHeightMapUnitScale );
546 : 0 : map[QStringLiteral( "angle" )] = QString::number( mAngle );
547 : 0 : map[QStringLiteral( "outline_style" )] = QgsSymbolLayerUtils::encodePenStyle( mStrokeStyle );
548 : 0 : map[QStringLiteral( "outline_width" )] = QString::number( mStrokeWidth );
549 : 0 : map[QStringLiteral( "outline_width_unit" )] = QgsUnitTypes::encodeUnit( mStrokeWidthUnit );
550 : 0 : map[QStringLiteral( "outline_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mStrokeWidthMapUnitScale );
551 : 0 : map[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
552 : 0 : map[QStringLiteral( "cap_style" )] = QgsSymbolLayerUtils::encodePenCapStyle( mPenCapStyle );
553 : 0 : map[QStringLiteral( "color" )] = QgsSymbolLayerUtils::encodeColor( mColor );
554 : 0 : map[QStringLiteral( "outline_color" )] = QgsSymbolLayerUtils::encodeColor( mStrokeColor );
555 : 0 : map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
556 : 0 : map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
557 : 0 : map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
558 : 0 : map[QStringLiteral( "size" )] = QString::number( mSize );
559 : 0 : map[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
560 : 0 : map[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
561 : 0 : map[QStringLiteral( "horizontal_anchor_point" )] = QString::number( mHorizontalAnchorPoint );
562 : 0 : map[QStringLiteral( "vertical_anchor_point" )] = QString::number( mVerticalAnchorPoint );
563 : 0 : return map;
564 : 0 : }
565 : :
566 : 0 : QSizeF QgsEllipseSymbolLayer::calculateSize( QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight )
567 : : {
568 : 0 : double width = 0;
569 : :
570 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) ) //1. priority: data defined setting on symbol layer le
571 : : {
572 : 0 : context.setOriginalValueVariable( mSymbolWidth );
573 : 0 : width = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyWidth, context.renderContext().expressionContext(), mSymbolWidth );
574 : 0 : }
575 : : else //2. priority: global width setting
576 : : {
577 : 0 : width = mSymbolWidth;
578 : : }
579 : 0 : if ( scaledWidth )
580 : : {
581 : 0 : *scaledWidth = width;
582 : 0 : }
583 : 0 : width = context.renderContext().convertToPainterUnits( width, mSymbolWidthUnit, mSymbolHeightMapUnitScale );
584 : :
585 : 0 : double height = 0;
586 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) ) //1. priority: data defined setting on symbol layer level
587 : : {
588 : 0 : context.setOriginalValueVariable( mSymbolHeight );
589 : 0 : height = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyHeight, context.renderContext().expressionContext(), mSymbolHeight );
590 : 0 : }
591 : : else //2. priority: global height setting
592 : : {
593 : 0 : height = mSymbolHeight;
594 : : }
595 : 0 : if ( scaledHeight )
596 : : {
597 : 0 : *scaledHeight = height;
598 : 0 : }
599 : 0 : height = context.renderContext().convertToPainterUnits( height, mSymbolHeightUnit, mSymbolHeightMapUnitScale );
600 : 0 : return QSizeF( width, height );
601 : 0 : }
602 : :
603 : 0 : void QgsEllipseSymbolLayer::preparePath( const QgsEllipseSymbolLayer::Shape &shape, QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight, const QgsFeature * )
604 : : {
605 : 0 : mPainterPath = QPainterPath();
606 : :
607 : 0 : QSizeF size = calculateSize( context, scaledWidth, scaledHeight );
608 : :
609 : 0 : switch ( shape )
610 : : {
611 : : case Circle:
612 : 0 : mPainterPath.addEllipse( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
613 : 0 : return;
614 : :
615 : : case SemiCircle:
616 : 0 : mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 0, 180 );
617 : 0 : mPainterPath.lineTo( 0, 0 );
618 : 0 : return;
619 : :
620 : : case Rectangle:
621 : 0 : mPainterPath.addRect( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
622 : 0 : return;
623 : :
624 : : case Diamond:
625 : 0 : mPainterPath.moveTo( -size.width() / 2.0, 0 );
626 : 0 : mPainterPath.lineTo( 0, size.height() / 2.0 );
627 : 0 : mPainterPath.lineTo( size.width() / 2.0, 0 );
628 : 0 : mPainterPath.lineTo( 0, -size.height() / 2.0 );
629 : 0 : mPainterPath.lineTo( -size.width() / 2.0, 0 );
630 : 0 : return;
631 : :
632 : : case Cross:
633 : 0 : mPainterPath.moveTo( 0, -size.height() / 2.0 );
634 : 0 : mPainterPath.lineTo( 0, size.height() / 2.0 );
635 : 0 : mPainterPath.moveTo( -size.width() / 2.0, 0 );
636 : 0 : mPainterPath.lineTo( size.width() / 2.0, 0 );
637 : 0 : return;
638 : :
639 : : case Arrow:
640 : 0 : mPainterPath.moveTo( -size.width() / 2.0, size.height() / 2.0 );
641 : 0 : mPainterPath.lineTo( 0, -size.height() / 2.0 );
642 : 0 : mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
643 : 0 : return;
644 : :
645 : : case HalfArc:
646 : 0 : mPainterPath.moveTo( size.width() / 2.0, 0 );
647 : 0 : mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 0, 180 );
648 : 0 : return;
649 : :
650 : : case Triangle:
651 : 0 : mPainterPath.moveTo( 0, -size.height() / 2.0 );
652 : 0 : mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
653 : 0 : mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
654 : 0 : mPainterPath.lineTo( 0, -size.height() / 2.0 );
655 : 0 : return;
656 : :
657 : : case LeftHalfTriangle:
658 : 0 : mPainterPath.moveTo( 0, size.height() / 2.0 );
659 : 0 : mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
660 : 0 : mPainterPath.lineTo( 0, -size.height() / 2.0 );
661 : 0 : mPainterPath.lineTo( 0, size.height() / 2.0 );
662 : 0 : return;
663 : :
664 : : case RightHalfTriangle:
665 : 0 : mPainterPath.moveTo( -size.width() / 2.0, size.height() / 2.0 );
666 : 0 : mPainterPath.lineTo( 0, size.height() / 2.0 );
667 : 0 : mPainterPath.lineTo( 0, -size.height() / 2.0 );
668 : 0 : mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
669 : 0 : return;
670 : : }
671 : 0 : }
672 : :
673 : 0 : bool QgsEllipseSymbolLayer::shapeIsFilled( const QgsEllipseSymbolLayer::Shape &shape )
674 : : {
675 : 0 : switch ( shape )
676 : : {
677 : : case Circle:
678 : : case Rectangle:
679 : : case Diamond:
680 : : case Triangle:
681 : : case RightHalfTriangle:
682 : : case LeftHalfTriangle:
683 : : case SemiCircle:
684 : 0 : return true;
685 : :
686 : : case Cross:
687 : : case Arrow:
688 : : case HalfArc:
689 : 0 : return false;
690 : : }
691 : :
692 : 0 : return true;
693 : 0 : }
694 : :
695 : 0 : void QgsEllipseSymbolLayer::setSize( double size )
696 : : {
697 : 0 : if ( mSymbolWidth >= mSymbolHeight )
698 : : {
699 : 0 : mSymbolHeight = mSymbolHeight * size / mSymbolWidth;
700 : 0 : mSymbolWidth = size;
701 : 0 : }
702 : : else
703 : : {
704 : 0 : mSymbolWidth = mSymbolWidth * size / mSymbolHeight;
705 : 0 : mSymbolHeight = size;
706 : : }
707 : 0 : QgsMarkerSymbolLayer::setSize( size );
708 : 0 : }
709 : :
710 : 0 : void QgsEllipseSymbolLayer::setSymbolWidth( double w )
711 : : {
712 : 0 : mSymbolWidth = w;
713 : 0 : QgsMarkerSymbolLayer::setSize( mSymbolWidth >= mSymbolHeight ? mSymbolWidth : mSymbolHeight );
714 : 0 : }
715 : :
716 : 0 : void QgsEllipseSymbolLayer::setSymbolHeight( double h )
717 : : {
718 : 0 : mSymbolHeight = h;
719 : 0 : QgsMarkerSymbolLayer::setSize( mSymbolWidth >= mSymbolHeight ? mSymbolWidth : mSymbolHeight );
720 : 0 : }
721 : :
722 : 0 : void QgsEllipseSymbolLayer::setOutputUnit( QgsUnitTypes::RenderUnit unit )
723 : : {
724 : 0 : QgsMarkerSymbolLayer::setOutputUnit( unit );
725 : 0 : mSymbolWidthUnit = unit;
726 : 0 : mSymbolHeightUnit = unit;
727 : 0 : mStrokeWidthUnit = unit;
728 : 0 : }
729 : :
730 : 0 : QgsUnitTypes::RenderUnit QgsEllipseSymbolLayer::outputUnit() const
731 : : {
732 : 0 : QgsUnitTypes::RenderUnit unit = QgsMarkerSymbolLayer::outputUnit();
733 : 0 : if ( mSymbolWidthUnit != unit || mSymbolHeightUnit != unit || mStrokeWidthUnit != unit )
734 : : {
735 : 0 : return QgsUnitTypes::RenderUnknownUnit;
736 : : }
737 : 0 : return unit;
738 : 0 : }
739 : :
740 : 0 : bool QgsEllipseSymbolLayer::usesMapUnits() const
741 : : {
742 : 0 : return mSymbolWidthUnit == QgsUnitTypes::RenderMapUnits || mSymbolWidthUnit == QgsUnitTypes::RenderMetersInMapUnits
743 : 0 : || mSymbolHeightUnit == QgsUnitTypes::RenderMapUnits || mSymbolHeightUnit == QgsUnitTypes::RenderMetersInMapUnits
744 : 0 : || mStrokeWidthUnit == QgsUnitTypes::RenderMapUnits || mStrokeWidthUnit == QgsUnitTypes::RenderMetersInMapUnits
745 : 0 : || mOffsetUnit == QgsUnitTypes::RenderMapUnits || mOffsetUnit == QgsUnitTypes::RenderMetersInMapUnits;
746 : : }
747 : :
748 : 0 : void QgsEllipseSymbolLayer::setMapUnitScale( const QgsMapUnitScale &scale )
749 : : {
750 : 0 : QgsMarkerSymbolLayer::setMapUnitScale( scale );
751 : 0 : mSymbolWidthMapUnitScale = scale;
752 : 0 : mSymbolHeightMapUnitScale = scale;
753 : 0 : mStrokeWidthMapUnitScale = scale;
754 : 0 : }
755 : :
756 : 0 : QgsMapUnitScale QgsEllipseSymbolLayer::mapUnitScale() const
757 : : {
758 : 0 : if ( QgsMarkerSymbolLayer::mapUnitScale() == mSymbolWidthMapUnitScale &&
759 : 0 : mSymbolWidthMapUnitScale == mSymbolHeightMapUnitScale &&
760 : 0 : mSymbolHeightMapUnitScale == mStrokeWidthMapUnitScale )
761 : : {
762 : 0 : return mSymbolWidthMapUnitScale;
763 : : }
764 : 0 : return QgsMapUnitScale();
765 : 0 : }
766 : :
767 : 0 : QRectF QgsEllipseSymbolLayer::bounds( QPointF point, QgsSymbolRenderContext &context )
768 : : {
769 : 0 : QSizeF size = calculateSize( context );
770 : :
771 : 0 : bool hasDataDefinedRotation = false;
772 : 0 : QPointF offset;
773 : 0 : double angle = 0;
774 : 0 : calculateOffsetAndRotation( context, size.width(), size.height(), hasDataDefinedRotation, offset, angle );
775 : :
776 : 0 : QTransform transform;
777 : :
778 : : // move to the desired position
779 : 0 : transform.translate( point.x() + offset.x(), point.y() + offset.y() );
780 : :
781 : 0 : if ( !qgsDoubleNear( angle, 0.0 ) )
782 : 0 : transform.rotate( angle );
783 : :
784 : 0 : double penWidth = mStrokeWidth;
785 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
786 : : {
787 : 0 : context.setOriginalValueVariable( mStrokeWidth );
788 : 0 : QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext() );
789 : :
790 : 0 : if ( exprVal.isValid() )
791 : : {
792 : : bool ok;
793 : 0 : double strokeWidth = exprVal.toDouble( &ok );
794 : 0 : if ( ok )
795 : : {
796 : 0 : penWidth = strokeWidth;
797 : 0 : }
798 : 0 : }
799 : 0 : }
800 : 0 : penWidth = context.renderContext().convertToPainterUnits( penWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
801 : :
802 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeStyle ) )
803 : : {
804 : 0 : context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePenStyle( mStrokeStyle ) );
805 : 0 : QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyStrokeStyle, context.renderContext().expressionContext() );
806 : 0 : if ( exprVal.isValid() && exprVal.toString() == QLatin1String( "no" ) )
807 : : {
808 : 0 : penWidth = 0.0;
809 : 0 : }
810 : 0 : }
811 : 0 : else if ( mStrokeStyle == Qt::NoPen )
812 : 0 : penWidth = 0;
813 : :
814 : : //antialiasing, add 1 pixel
815 : 0 : penWidth += 1;
816 : :
817 : 0 : QRectF symbolBounds = transform.mapRect( QRectF( -size.width() / 2.0,
818 : 0 : -size.height() / 2.0,
819 : 0 : size.width(),
820 : 0 : size.height() ) );
821 : :
822 : : //extend bounds by pen width / 2.0
823 : 0 : symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
824 : 0 : penWidth / 2.0, penWidth / 2.0 );
825 : :
826 : 0 : return symbolBounds;
827 : 0 : }
828 : :
829 : 0 : bool QgsEllipseSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const
830 : : {
831 : : //width
832 : 0 : double symbolWidth = mSymbolWidth;
833 : :
834 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) ) //1. priority: data defined setting on symbol layer le
835 : : {
836 : 0 : context.setOriginalValueVariable( mSymbolWidth );
837 : 0 : symbolWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyWidth, context.renderContext().expressionContext(), mSymbolWidth );
838 : 0 : }
839 : 0 : if ( mSymbolWidthUnit == QgsUnitTypes::RenderMillimeters )
840 : : {
841 : 0 : symbolWidth *= mmMapUnitScaleFactor;
842 : 0 : }
843 : :
844 : : //height
845 : 0 : double symbolHeight = mSymbolHeight;
846 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) ) //1. priority: data defined setting on symbol layer level
847 : : {
848 : 0 : context.setOriginalValueVariable( mSymbolHeight );
849 : 0 : symbolWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyHeight, context.renderContext().expressionContext(), mSymbolHeight );
850 : 0 : }
851 : 0 : if ( mSymbolHeightUnit == QgsUnitTypes::RenderMillimeters )
852 : : {
853 : 0 : symbolHeight *= mmMapUnitScaleFactor;
854 : 0 : }
855 : :
856 : : //stroke width
857 : 0 : double strokeWidth = mStrokeWidth;
858 : :
859 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
860 : : {
861 : 0 : context.setOriginalValueVariable( mStrokeWidth );
862 : 0 : strokeWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext(), mStrokeWidth );
863 : 0 : }
864 : 0 : if ( mStrokeWidthUnit == QgsUnitTypes::RenderMillimeters )
865 : : {
866 : 0 : strokeWidth *= strokeWidth;
867 : 0 : }
868 : :
869 : : //fill color
870 : 0 : QColor fc = mColor;
871 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFillColor ) )
872 : : {
873 : 0 : context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mColor ) );
874 : 0 : fc = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyFillColor, context.renderContext().expressionContext(), mColor );
875 : 0 : }
876 : :
877 : : //stroke color
878 : 0 : QColor oc = mStrokeColor;
879 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeColor ) )
880 : : {
881 : 0 : context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mStrokeColor ) );
882 : 0 : oc = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyStrokeColor, context.renderContext().expressionContext(), mStrokeColor );
883 : 0 : }
884 : :
885 : : //symbol name
886 : 0 : QgsEllipseSymbolLayer::Shape shape = mShape;
887 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyName ) )
888 : : {
889 : 0 : context.setOriginalValueVariable( encodeShape( shape ) );
890 : 0 : shape = decodeShape( mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyName, context.renderContext().expressionContext(), encodeShape( shape ) ) );
891 : 0 : }
892 : :
893 : : //offset
894 : 0 : double offsetX = 0;
895 : 0 : double offsetY = 0;
896 : 0 : markerOffset( context, offsetX, offsetY );
897 : 0 : QPointF off( offsetX, offsetY );
898 : :
899 : : //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
900 : 0 : double rotation = 0.0;
901 : 0 : if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle ) )
902 : : {
903 : 0 : context.setOriginalValueVariable( mAngle );
904 : 0 : rotation = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyAngle, context.renderContext().expressionContext(), mAngle ) + mLineAngle;
905 : 0 : }
906 : 0 : else if ( !qgsDoubleNear( mAngle + mLineAngle, 0.0 ) )
907 : : {
908 : 0 : rotation = mAngle + mLineAngle;
909 : 0 : }
910 : 0 : rotation = -rotation; //rotation in Qt is counterclockwise
911 : 0 : if ( rotation )
912 : 0 : off = _rotatedOffset( off, rotation );
913 : :
914 : 0 : QTransform t;
915 : 0 : t.translate( shift.x() + offsetX, shift.y() + offsetY );
916 : :
917 : 0 : if ( !qgsDoubleNear( rotation, 0.0 ) )
918 : 0 : t.rotate( rotation );
919 : :
920 : 0 : double halfWidth = symbolWidth / 2.0;
921 : 0 : double halfHeight = symbolHeight / 2.0;
922 : :
923 : 0 : switch ( shape )
924 : : {
925 : : case Circle:
926 : : {
927 : 0 : if ( qgsDoubleNear( halfWidth, halfHeight ) )
928 : : {
929 : 0 : QgsPoint pt( t.map( QPointF( 0, 0 ) ) );
930 : 0 : e.writeFilledCircle( layerName, oc, pt, halfWidth );
931 : 0 : }
932 : : else
933 : : {
934 : 0 : QgsPointSequence line;
935 : :
936 : 0 : double stepsize = 2 * M_PI / 40;
937 : 0 : for ( int i = 0; i < 39; ++i )
938 : : {
939 : 0 : double angle = stepsize * i;
940 : 0 : double x = halfWidth * std::cos( angle );
941 : 0 : double y = halfHeight * std::sin( angle );
942 : 0 : line << QgsPoint( t.map( QPointF( x, y ) ) );
943 : 0 : }
944 : : //close ellipse with first point
945 : 0 : line << line.at( 0 );
946 : :
947 : 0 : if ( mBrush.style() != Qt::NoBrush )
948 : 0 : e.writePolygon( QgsRingSequence() << line, layerName, QStringLiteral( "SOLID" ), fc );
949 : 0 : if ( mPen.style() != Qt::NoPen )
950 : 0 : e.writePolyline( line, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
951 : 0 : }
952 : 0 : return true;
953 : : }
954 : :
955 : : case Rectangle:
956 : : {
957 : 0 : QgsPointSequence p;
958 : 0 : p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) )
959 : 0 : << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) )
960 : 0 : << QgsPoint( t.map( QPointF( halfWidth, halfHeight ) ) )
961 : 0 : << QgsPoint( t.map( QPointF( -halfWidth, halfHeight ) ) );
962 : 0 : p << p[0];
963 : :
964 : 0 : if ( mBrush.style() != Qt::NoBrush )
965 : 0 : e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc );
966 : 0 : if ( mPen.style() != Qt::NoPen )
967 : 0 : e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
968 : 0 : return true;
969 : 0 : }
970 : : case Cross:
971 : : {
972 : 0 : if ( mPen.style() != Qt::NoPen )
973 : : {
974 : 0 : e.writePolyline( QgsPointSequence()
975 : 0 : << QgsPoint( t.map( QPointF( -halfWidth, 0 ) ) )
976 : 0 : << QgsPoint( t.map( QPointF( halfWidth, 0 ) ) ),
977 : 0 : layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
978 : 0 : e.writePolyline( QgsPointSequence()
979 : 0 : << QgsPoint( t.map( QPointF( 0, halfHeight ) ) )
980 : 0 : << QgsPoint( t.map( QPointF( 0, -halfHeight ) ) ),
981 : 0 : layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
982 : 0 : return true;
983 : : }
984 : 0 : break;
985 : : }
986 : :
987 : : case Triangle:
988 : : {
989 : 0 : QgsPointSequence p;
990 : 0 : p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) )
991 : 0 : << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) )
992 : 0 : << QgsPoint( t.map( QPointF( 0, halfHeight ) ) );
993 : 0 : p << p[0];
994 : 0 : if ( mBrush.style() != Qt::NoBrush )
995 : 0 : e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc );
996 : 0 : if ( mPen.style() != Qt::NoPen )
997 : 0 : e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
998 : 0 : return true;
999 : 0 : }
1000 : :
1001 : : case Diamond:
1002 : : case Arrow:
1003 : : case HalfArc:
1004 : : case RightHalfTriangle:
1005 : : case LeftHalfTriangle:
1006 : : case SemiCircle:
1007 : 0 : return false;
1008 : : }
1009 : :
1010 : 0 : return false;
1011 : 0 : }
1012 : :
1013 : 0 : QgsEllipseSymbolLayer::Shape QgsEllipseSymbolLayer::decodeShape( const QString &name, bool *ok )
1014 : : {
1015 : 0 : if ( ok )
1016 : 0 : *ok = true;
1017 : 0 : QString cleaned = name.toLower().trimmed();
1018 : :
1019 : 0 : if ( cleaned == QLatin1String( "circle" ) )
1020 : 0 : return Circle;
1021 : 0 : else if ( cleaned == QLatin1String( "square" ) || cleaned == QLatin1String( "rectangle" ) )
1022 : 0 : return Rectangle;
1023 : 0 : else if ( cleaned == QLatin1String( "diamond" ) )
1024 : 0 : return Diamond;
1025 : 0 : else if ( cleaned == QLatin1String( "cross" ) )
1026 : 0 : return Cross;
1027 : 0 : else if ( cleaned == QLatin1String( "arrow" ) )
1028 : 0 : return Arrow;
1029 : 0 : else if ( cleaned == QLatin1String( "half_arc" ) )
1030 : 0 : return HalfArc;
1031 : 0 : else if ( cleaned == QLatin1String( "triangle" ) )
1032 : 0 : return Triangle;
1033 : 0 : else if ( cleaned == QLatin1String( "right_half_triangle" ) )
1034 : 0 : return RightHalfTriangle;
1035 : 0 : else if ( cleaned == QLatin1String( "left_half_triangle" ) )
1036 : 0 : return LeftHalfTriangle;
1037 : 0 : else if ( cleaned == QLatin1String( "semi_circle" ) )
1038 : 0 : return SemiCircle;
1039 : :
1040 : 0 : if ( ok )
1041 : 0 : *ok = false;
1042 : 0 : return Circle;
1043 : 0 : }
1044 : :
1045 : 0 : QString QgsEllipseSymbolLayer::encodeShape( QgsEllipseSymbolLayer::Shape shape )
1046 : : {
1047 : 0 : switch ( shape )
1048 : : {
1049 : : case Circle:
1050 : 0 : return QStringLiteral( "circle" );
1051 : : case Rectangle:
1052 : 0 : return QStringLiteral( "rectangle" );
1053 : : case Diamond:
1054 : 0 : return QStringLiteral( "diamond" );
1055 : : case Cross:
1056 : 0 : return QStringLiteral( "cross" );
1057 : : case Arrow:
1058 : 0 : return QStringLiteral( "arrow" );
1059 : : case HalfArc:
1060 : 0 : return QStringLiteral( "half_arc" );
1061 : : case Triangle:
1062 : 0 : return QStringLiteral( "triangle" );
1063 : : case RightHalfTriangle:
1064 : 0 : return QStringLiteral( "right_half_triangle" );
1065 : : case LeftHalfTriangle:
1066 : 0 : return QStringLiteral( "left_half_triangle" );
1067 : : case SemiCircle:
1068 : 0 : return QStringLiteral( "semi_circle" );
1069 : : }
1070 : 0 : return QString();
1071 : 0 : }
1072 : :
1073 : 0 : QList<QgsEllipseSymbolLayer::Shape> QgsEllipseSymbolLayer::availableShapes()
1074 : : {
1075 : 0 : QList< Shape > shapes;
1076 : 0 : shapes << Circle
1077 : 0 : << Rectangle
1078 : 0 : << Diamond
1079 : 0 : << Cross
1080 : 0 : << Arrow
1081 : 0 : << HalfArc
1082 : 0 : << Triangle
1083 : 0 : << LeftHalfTriangle
1084 : 0 : << RightHalfTriangle
1085 : 0 : << SemiCircle;
1086 : 0 : return shapes;
1087 : 0 : }
|