35 props.insert( QStringLiteral(
"color" ), QStringLiteral(
"white" ) );
36 props.insert( QStringLiteral(
"style" ), QStringLiteral(
"solid" ) );
37 props.insert( QStringLiteral(
"style_border" ), QStringLiteral(
"solid" ) );
38 props.insert( QStringLiteral(
"color_border" ), QStringLiteral(
"black" ) );
39 props.insert( QStringLiteral(
"width_border" ), QStringLiteral(
"0.3" ) );
40 props.insert( QStringLiteral(
"joinstyle" ), QStringLiteral(
"miter" ) );
55 if ( mHasFixedMapPosition == fixed )
58 mHasFixedMapPosition = fixed;
65 mMapPosition = position;
71 mMapPositionCrs =
crs;
77 mRelativePosition = position;
89 return mOffsetFromReferencePoint / 3.7795275;
94 mOffsetFromReferencePoint = offset;
109 return mFrameSize / 3.7795275;
123 mContentsMargins = margins;
129 mFillSymbol.reset( symbol );
135 QPainter *painter = context.
painter();
142 drawFrame( context );
143 if ( mHasFixedMapPosition )
145 drawMarkerSymbol( context );
147 if ( mHasFixedMapPosition )
170 mMarkerSymbol.reset( symbol );
213 return QSizeF( 0, 0 );
216 void QgsAnnotation::updateBalloon()
219 if ( !mHasFixedMapPosition ||
220 ( mOffsetFromReferencePoint.x() < 0 && ( mOffsetFromReferencePoint.x() + mFrameSize.width() ) > 0
221 && mOffsetFromReferencePoint.y() < 0 && ( mOffsetFromReferencePoint.y() + mFrameSize.height() ) > 0 ) )
223 mBalloonSegment = -1;
228 QList<QLineF> segmentList;
229 segmentList << segment( 0,
nullptr );
230 segmentList << segment( 1,
nullptr );
231 segmentList << segment( 2,
nullptr );
232 segmentList << segment( 3,
nullptr );
235 double minEdgeDist = std::numeric_limits<double>::max();
236 int minEdgeIndex = -1;
241 for (
int i = 0; i < 4; ++i )
243 QLineF currentSegment = segmentList.at( i );
245 double currentMinDist = origin.
sqrDistToSegment( currentSegment.x1(), currentSegment.y1(), currentSegment.x2(), currentSegment.y2(), currentMinDistPoint );
246 bool isPreferredSegment =
false;
250 const double angle = fmod( origin.azimuth( currentMinDistPoint ) + 360.0, 360.0 );
251 if ( angle < 45 || angle > 315 )
252 isPreferredSegment = i == 0;
253 else if (
angle < 135 )
254 isPreferredSegment = i == 3;
255 else if (
angle < 225 )
256 isPreferredSegment = i == 2;
258 isPreferredSegment = i == 1;
260 else if ( currentMinDist < minEdgeDist )
261 isPreferredSegment =
true;
263 if ( isPreferredSegment )
266 minEdgePoint = currentMinDistPoint;
267 minEdgeDist = currentMinDist;
268 minEdge = currentSegment;
272 if ( minEdgeIndex < 0 )
277 mBalloonSegment = minEdgeIndex;
278 QPointF minEdgeEnd = minEdge.p2();
279 mBalloonSegmentPoint1 = QPointF( minEdgePoint.
x(), minEdgePoint.
y() );
280 if ( std::sqrt( minEdgePoint.
sqrDist( minEdgeEnd.x(), minEdgeEnd.y() ) ) < mSegmentPointWidthMm )
285 mBalloonSegmentPoint1 = QPointF( x, y );
292 mBalloonSegmentPoint2 = QPointF( x, y );
299 auto scaleSize = [context](
double size )->
double
303 if ( mHasFixedMapPosition )
308 return QLineF( scaleSize( mOffsetFromReferencePoint.x() ),
309 scaleSize( mOffsetFromReferencePoint.y() ),
310 scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
311 scaleSize( mOffsetFromReferencePoint.y() ) );
313 return QLineF( scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
314 scaleSize( mOffsetFromReferencePoint.y() ),
315 scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
316 scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ) );
318 return QLineF( scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
319 scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ),
320 scaleSize( mOffsetFromReferencePoint.x() ),
321 scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ) );
323 return QLineF( scaleSize( mOffsetFromReferencePoint.x() ),
324 scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ),
325 scaleSize( mOffsetFromReferencePoint.x() ),
326 scaleSize( mOffsetFromReferencePoint.y() ) );
336 return QLineF( 0, 0, scaleSize( mFrameSize.width() ), 0 );
338 return QLineF( scaleSize( mFrameSize.width() ), 0,
339 scaleSize( mFrameSize.width() ), scaleSize( mFrameSize.height() ) );
341 return QLineF( scaleSize( mFrameSize.width() ), scaleSize( mFrameSize.height() ),
342 0, scaleSize( mFrameSize.height() ) );
344 return QLineF( 0, scaleSize( mFrameSize.height() ),
360 poly.reserve( 9 + ( mHasFixedMapPosition ? 3 : 0 ) );
361 QVector<QPolygonF> rings;
362 for (
int i = 0; i < 4; ++i )
364 QLineF currentSegment = segment( i, &context );
365 poly << QPointF( currentSegment.p1().x(),
366 currentSegment.p1().y() );
367 if ( i == mBalloonSegment && mHasFixedMapPosition )
371 poly << QPointF( 0, 0 );
375 poly << QPointF( currentSegment.p2().x(), currentSegment.p2().y() );
377 if ( poly.at( 0 ) != poly.at( poly.count() - 1 ) )
378 poly << poly.at( 0 );
380 mFillSymbol->startRender( context );
381 mFillSymbol->renderPolygon( poly, &rings,
nullptr, context );
382 mFillSymbol->stopRender( context );
394 mMarkerSymbol->startRender( context );
395 mMarkerSymbol->renderPoint( QPointF( 0, 0 ),
nullptr, context );
396 mMarkerSymbol->stopRender( context );
402 if ( itemElem.isNull() )
406 QDomElement annotationElem = doc.createElement( QStringLiteral(
"AnnotationItem" ) );
407 annotationElem.setAttribute( QStringLiteral(
"mapPositionFixed" ), mHasFixedMapPosition );
408 annotationElem.setAttribute( QStringLiteral(
"mapPosX" ),
qgsDoubleToString( mMapPosition.
x() ) );
409 annotationElem.setAttribute( QStringLiteral(
"mapPosY" ),
qgsDoubleToString( mMapPosition.
y() ) );
410 if ( mMapPositionCrs.
isValid() )
411 mMapPositionCrs.
writeXml( annotationElem, doc );
412 annotationElem.setAttribute( QStringLiteral(
"offsetXMM" ),
qgsDoubleToString( mOffsetFromReferencePoint.x() ) );
413 annotationElem.setAttribute( QStringLiteral(
"offsetYMM" ),
qgsDoubleToString( mOffsetFromReferencePoint.y() ) );
414 annotationElem.setAttribute( QStringLiteral(
"frameWidthMM" ),
qgsDoubleToString( mFrameSize.width() ) );
415 annotationElem.setAttribute( QStringLiteral(
"frameHeightMM" ),
qgsDoubleToString( mFrameSize.height() ) );
416 annotationElem.setAttribute( QStringLiteral(
"canvasPosX" ),
qgsDoubleToString( mRelativePosition.x() ) );
417 annotationElem.setAttribute( QStringLiteral(
"canvasPosY" ),
qgsDoubleToString( mRelativePosition.y() ) );
418 annotationElem.setAttribute( QStringLiteral(
"contentsMargin" ), mContentsMargins.
toString() );
419 annotationElem.setAttribute( QStringLiteral(
"visible" ),
isVisible() );
422 annotationElem.setAttribute( QStringLiteral(
"mapLayer" ), mMapLayer->id() );
427 if ( !symbolElem.isNull() )
429 annotationElem.appendChild( symbolElem );
434 QDomElement fillElem = doc.createElement( QStringLiteral(
"fillSymbol" ) );
436 if ( !symbolElem.isNull() )
438 fillElem.appendChild( symbolElem );
439 annotationElem.appendChild( fillElem );
442 itemElem.appendChild( annotationElem );
447 if ( annotationElem.isNull() )
452 pos.setX( annotationElem.attribute( QStringLiteral(
"canvasPosX" ), QStringLiteral(
"0" ) ).toDouble() );
453 pos.setY( annotationElem.attribute( QStringLiteral(
"canvasPosY" ), QStringLiteral(
"0" ) ).toDouble() );
454 if ( pos.x() >= 1 || pos.x() < 0 || pos.y() < 0 || pos.y() >= 1 )
455 mRelativePosition = QPointF();
457 mRelativePosition = pos;
459 mapPos.
setX( annotationElem.attribute( QStringLiteral(
"mapPosX" ), QStringLiteral(
"0" ) ).toDouble() );
460 mapPos.
setY( annotationElem.attribute( QStringLiteral(
"mapPosY" ), QStringLiteral(
"0" ) ).toDouble() );
461 mMapPosition = mapPos;
463 if ( !mMapPositionCrs.
readXml( annotationElem ) )
468 mContentsMargins =
QgsMargins::fromString( annotationElem.attribute( QStringLiteral(
"contentsMargin" ) ) );
470 if ( annotationElem.hasAttribute( QStringLiteral(
"frameWidthMM" ) ) )
471 mFrameSize.setWidth( annotationElem.attribute( QStringLiteral(
"frameWidthMM" ), QStringLiteral(
"5" ) ).toDouble() );
473 mFrameSize.setWidth( dpiScale * annotationElem.attribute( QStringLiteral(
"frameWidth" ), QStringLiteral(
"50" ) ).toDouble() );
474 if ( annotationElem.hasAttribute( QStringLiteral(
"frameHeightMM" ) ) )
475 mFrameSize.setHeight( annotationElem.attribute( QStringLiteral(
"frameHeightMM" ), QStringLiteral(
"3" ) ).toDouble() );
477 mFrameSize.setHeight( dpiScale * annotationElem.attribute( QStringLiteral(
"frameHeight" ), QStringLiteral(
"50" ) ).toDouble() );
479 if ( annotationElem.hasAttribute( QStringLiteral(
"offsetXMM" ) ) )
480 mOffsetFromReferencePoint.setX( annotationElem.attribute( QStringLiteral(
"offsetXMM" ), QStringLiteral(
"0" ) ).toDouble() );
482 mOffsetFromReferencePoint.setX( dpiScale * annotationElem.attribute( QStringLiteral(
"offsetX" ), QStringLiteral(
"0" ) ).toDouble() );
483 if ( annotationElem.hasAttribute( QStringLiteral(
"offsetYMM" ) ) )
484 mOffsetFromReferencePoint.setY( annotationElem.attribute( QStringLiteral(
"offsetYMM" ), QStringLiteral(
"0" ) ).toDouble() );
486 mOffsetFromReferencePoint.setY( dpiScale * annotationElem.attribute( QStringLiteral(
"offsetY" ), QStringLiteral(
"0" ) ).toDouble() );
488 mHasFixedMapPosition = annotationElem.attribute( QStringLiteral(
"mapPositionFixed" ), QStringLiteral(
"1" ) ).toInt();
489 mVisible = annotationElem.attribute( QStringLiteral(
"visible" ), QStringLiteral(
"1" ) ).toInt();
490 if ( annotationElem.hasAttribute( QStringLiteral(
"mapLayer" ) ) )
497 QDomElement symbolElem = annotationElem.firstChildElement( QStringLiteral(
"symbol" ) );
498 if ( !symbolElem.isNull() )
500 QgsMarkerSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( symbolElem, context );
503 mMarkerSymbol.reset( symbol );
508 mFillSymbol.reset(
nullptr );
509 QDomElement fillElem = annotationElem.firstChildElement( QStringLiteral(
"fillSymbol" ) );
510 if ( !fillElem.isNull() )
512 QDomElement symbolElem = fillElem.firstChildElement( QStringLiteral(
"symbol" ) );
513 if ( !symbolElem.isNull() )
515 QgsFillSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context );
518 mFillSymbol.reset( symbol );
525 frameColor.setNamedColor( annotationElem.attribute( QStringLiteral(
"frameColor" ), QStringLiteral(
"#000000" ) ) );
526 frameColor.setAlpha( annotationElem.attribute( QStringLiteral(
"frameColorAlpha" ), QStringLiteral(
"255" ) ).toInt() );
527 QColor frameBackgroundColor;
528 frameBackgroundColor.setNamedColor( annotationElem.attribute( QStringLiteral(
"frameBackgroundColor" ) ) );
529 frameBackgroundColor.setAlpha( annotationElem.attribute( QStringLiteral(
"frameBackgroundColorAlpha" ), QStringLiteral(
"255" ) ).toInt() );
530 double frameBorderWidth = annotationElem.attribute( QStringLiteral(
"frameBorderWidth" ), QStringLiteral(
"0.5" ) ).toDouble();
532 frameBorderWidth = frameBorderWidth * 25.4 / 96.0;
534 props.insert( QStringLiteral(
"color" ), frameBackgroundColor.name() );
535 props.insert( QStringLiteral(
"style" ), QStringLiteral(
"solid" ) );
536 props.insert( QStringLiteral(
"style_border" ), QStringLiteral(
"solid" ) );
537 props.insert( QStringLiteral(
"color_border" ), frameColor.name() );
538 props.insert( QStringLiteral(
"width_border" ), QString::number( frameBorderWidth ) );
539 props.insert( QStringLiteral(
"joinstyle" ), QStringLiteral(
"miter" ) );
549 target->mVisible = mVisible;
550 target->mHasFixedMapPosition = mHasFixedMapPosition;
551 target->mMapPosition = mMapPosition;
552 target->mMapPositionCrs = mMapPositionCrs;
553 target->mRelativePosition = mRelativePosition;
554 target->mOffsetFromReferencePoint = mOffsetFromReferencePoint;
555 target->mFrameSize = mFrameSize;
556 target->mMarkerSymbol.reset( mMarkerSymbol ? mMarkerSymbol->clone() :
nullptr );
557 target->mContentsMargins = mContentsMargins;
558 target->mFillSymbol.reset( mFillSymbol ? mFillSymbol->clone() :
nullptr );
559 target->mBalloonSegment = mBalloonSegment;
560 target->mBalloonSegmentPoint1 = mBalloonSegmentPoint1;
561 target->mBalloonSegmentPoint2 = mBalloonSegmentPoint2;
562 target->mSegmentPointWidthMm = mSegmentPointWidthMm;
563 target->mMapLayer = mMapLayer;
564 target->mFeature = mFeature;