24 #include <QDomDocument>
25 #include <QDomElement>
31 mUseCustomDashPattern( false ), mCustomDashPatternUnit(
QgsSymbolV2::MM )
62 if ( props.contains(
"color" ) )
64 if ( props.contains(
"width" ) )
65 width = props[
"width"].toDouble();
66 if ( props.contains(
"penstyle" ) )
71 if ( props.contains(
"width_unit" ) )
73 if ( props.contains(
"offset" ) )
74 l->
setOffset( props[
"offset"].toDouble() );
75 if ( props.contains(
"offset_unit" ) )
77 if ( props.contains(
"joinstyle" ) )
79 if ( props.contains(
"capstyle" ) )
82 if ( props.contains(
"use_custom_dash" ) )
86 if ( props.contains(
"customdash" ) )
90 if ( props.contains(
"customdash_unit" ) )
96 if ( props.contains(
"color_expression" ) )
98 if ( props.contains(
"width_expression" ) )
100 if ( props.contains(
"offset_expression" ) )
102 if ( props.contains(
"customdash_expression" ) )
104 if ( props.contains(
"joinstyle_expression" ) )
106 if ( props.contains(
"capstyle_expression" ) )
121 penColor.setAlphaF(
mColor.alphaF() * context.
alpha() );
122 mPen.setColor( penColor );
124 mPen.setWidthF( scaledWidth );
127 mPen.setStyle( Qt::CustomDashLine );
130 double dashWidthDiv = scaledWidth;
132 QStringList versionSplit = QString( qVersion() ).split(
"." );
133 if ( versionSplit.size() > 1
134 && versionSplit.at( 1 ).toInt() >= 8
139 QVector<qreal> scaledVector;
146 mPen.setDashPattern( scaledVector );
158 selColor.setAlphaF( context.
alpha() );
185 p->drawPolyline( points );
190 p->drawPolyline( ::
offsetLine( points, scaledOffset ) );
198 map[
"width"] = QString::number(
mWidth );
203 map[
"offset"] = QString::number(
mOffset );
232 QDomElement symbolizerElem = doc.createElement(
"se:LineSymbolizer" );
233 if ( !props.value(
"uom",
"" ).isEmpty() )
234 symbolizerElem.setAttribute(
"uom", props.value(
"uom",
"" ) );
235 element.appendChild( symbolizerElem );
241 QDomElement strokeElem = doc.createElement(
"se:Stroke" );
242 symbolizerElem.appendChild( strokeElem );
251 QDomElement perpOffsetElem = doc.createElement(
"se:PerpendicularOffset" );
252 perpOffsetElem.appendChild( doc.createTextNode( QString::number(
mOffset ) ) );
253 symbolizerElem.appendChild( perpOffsetElem );
276 QDomElement strokeElem = element.firstChildElement(
"Stroke" );
277 if ( strokeElem.isNull() )
289 &penJoinStyle, &penCapStyle,
290 &customDashVector ) )
294 QDomElement perpOffsetElem = element.firstChildElement(
"PerpendicularOffset" );
295 if ( !perpOffsetElem.isNull() )
298 double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
315 double scaledWidth = 0;
317 if ( strokeWidthExpression )
319 scaledWidth = strokeWidthExpression->
evaluate( const_cast<QgsFeature*>( context.
feature() ) ).toDouble()
321 pen.setWidthF( scaledWidth );
322 selPen.setWidthF( scaledWidth );
327 pen.setWidthF( scaledWidth );
328 selPen.setWidthF( scaledWidth );
333 if ( strokeColorExpression )
341 if ( lineOffsetExpression )
343 offset = lineOffsetExpression->
evaluate( const_cast<QgsFeature*>( context.
feature() ) ).toDouble();
348 if ( dashPatternExpression )
350 QVector<qreal> dashVector;
351 QStringList dashList = dashPatternExpression->
evaluate( const_cast<QgsFeature*>( context.
feature() ) ).toString().split(
";" );
352 QStringList::const_iterator dashIt = dashList.constBegin();
353 for ( ; dashIt != dashList.constEnd(); ++dashIt )
357 pen.setDashPattern( dashVector );
362 if ( joinStyleExpression )
364 QString joinStyleString = joinStyleExpression->
evaluate( const_cast<QgsFeature*>( context.
feature() ) ).toString();
370 if ( capStyleExpression )
372 QString capStyleString = capStyleExpression->
evaluate( const_cast<QgsFeature*>( context.
feature() ) ).toString();
391 if ( p1.x() == p2.x() )
400 mT = float( p2.y() - p1.y() ) / ( p2.x() - p1.x() );
405 double x = ( p2.x() - p1.x() );
406 double y = ( p2.y() - p1.y() );
407 mLength = sqrt( x * x + y * y );
424 return (
mIncreasing ? QPointF( 0, interval ) : QPointF( 0, -interval ) );
426 double alpha = atan(
mT );
427 double dx = cos( alpha ) * interval;
428 double dy = sin( alpha ) * interval;
429 return (
mIncreasing ? QPointF( dx, dy ) : QPointF( -dx, -dy ) );
465 if ( props.contains(
"interval" ) )
466 interval = props[
"interval"].toDouble();
467 if ( props.contains(
"rotate" ) )
468 rotate = ( props[
"rotate"] ==
"1" );
471 if ( props.contains(
"offset" ) )
473 x->
setOffset( props[
"offset"].toDouble() );
475 if ( props.contains(
"offset_unit" ) )
479 if ( props.contains(
"interval_unit" ) )
484 if ( props.contains(
"placement" ) )
486 if ( props[
"placement"] ==
"vertex" )
488 else if ( props[
"placement"] ==
"lastvertex" )
490 else if ( props[
"placement"] ==
"firstvertex" )
492 else if ( props[
"placement"] ==
"centralpoint" )
499 if ( props.contains(
"interval_expression" ) )
503 if ( props.contains(
"offset_expression" ) )
507 if ( props.contains(
"placement_expression" ) )
553 if ( offsetExpression )
555 offset = offsetExpression->
evaluate( const_cast<QgsFeature*>( context.
feature() ) ).toDouble();
560 if ( placementExpression )
562 QString placementString = placementExpression->
evaluate( const_cast<QgsFeature*>( context.
feature() ) ).toString();
563 if ( placementString.compare(
"vertex", Qt::CaseInsensitive ) == 0 )
567 else if ( placementString.compare(
"lastvertex", Qt::CaseInsensitive ) == 0 )
571 else if ( placementString.compare(
"firstvertex", Qt::CaseInsensitive ) == 0 )
575 else if ( placementString.compare(
"centerpoint", Qt::CaseInsensitive ) == 0 )
608 if ( points.isEmpty() )
611 QPointF lastPt = points[0];
612 double lengthLeft = 0;
620 if ( intervalExpression )
622 interval = intervalExpression->
evaluate( const_cast<QgsFeature*>( context.
feature() ) ).toDouble();
631 for (
int i = 1; i < points.count(); ++i )
633 const QPointF& pt = points[i];
644 double c = 1 - lengthLeft / painterUnitInterval;
662 while ( lengthLeft > painterUnitInterval )
666 lengthLeft -= painterUnitInterval;
679 static double _averageAngle(
const QPointF& prevPt,
const QPointF& pt,
const QPointF& nextPt )
684 double unitX = cos( a1 ) + cos( a2 ), unitY = sin( a1 ) + sin( a2 );
686 return atan2( unitY, unitX );
691 if ( points.isEmpty() )
707 i = points.count() - 1;
708 maxCount = points.count();
713 maxCount = points.count();
714 if ( points.first() == points.last() )
718 for ( ; i < maxCount; ++i )
720 if ( isRing && placement ==
Vertex && i == points.count() - 1 )
741 const QPointF& pt = points[vertex];
743 if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
745 int prevIndex = vertex - 1;
746 int nextIndex = vertex + 1;
748 if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
750 prevIndex = points.count() - 2;
754 QPointF prevPoint, nextPoint;
755 while ( prevIndex >= 0 )
757 prevPoint = points[ prevIndex ];
758 if ( prevPoint != pt )
765 while ( nextIndex < points.count() )
767 nextPoint = points[ nextIndex ];
768 if ( nextPoint != pt )
775 if ( prevIndex >= 0 && nextIndex < points.count() )
784 while ( vertex < points.size() - 1 )
786 const QPointF& nextPt = points[vertex+1];
798 while ( vertex >= 1 )
800 const QPointF& prevPt = points[vertex-1];
815 if ( points.size() > 0 )
819 QPolygonF::const_iterator it = points.constBegin();
821 for ( ++it; it != points.constEnd(); ++it )
823 length += sqrt(( last.x() - it->x() ) * ( last.x() - it->x() ) +
824 ( last.y() - it->y() ) * ( last.y() - it->y() ) );
829 it = points.constBegin();
831 qreal last_at = 0, next_at = 0;
834 for ( ++it; it != points.constEnd(); ++it )
837 next_at += sqrt(( last.x() - it->x() ) * ( last.x() - it->x() ) +
838 ( last.y() - it->y() ) * ( last.y() - it->y() ) );
839 if ( next_at >= length / 2 )
848 qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
849 QPointF pt = last + ( next - last ) * k;
866 map[
"interval"] = QString::number(
mInterval );
867 map[
"offset"] = QString::number(
mOffset );
871 map[
"placement"] =
"vertex";
873 map[
"placement"] =
"lastvertex";
875 map[
"placement"] =
"firstvertex";
877 map[
"placement"] =
"centralpoint";
879 map[
"placement"] =
"interval";
920 QDomElement symbolizerElem = doc.createElement(
"se:LineSymbolizer" );
921 if ( !props.value(
"uom",
"" ).isEmpty() )
922 symbolizerElem.setAttribute(
"uom", props.value(
"uom",
"" ) );
923 element.appendChild( symbolizerElem );
957 QDomElement strokeElem = doc.createElement(
"se:Stroke" );
958 symbolizerElem.appendChild( strokeElem );
961 QDomElement graphicStrokeElem = doc.createElement(
"se:GraphicStroke" );
962 strokeElem.appendChild( graphicStrokeElem );
968 graphicStrokeElem.appendChild( doc.createComment( QString(
"MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( markerLayer->
layerType() ) ) );
975 if ( !gap.isEmpty() )
977 QDomElement gapElem = doc.createElement(
"se:Gap" );
979 graphicStrokeElem.appendChild( gapElem );
984 QDomElement perpOffsetElem = doc.createElement(
"se:PerpendicularOffset" );
985 perpOffsetElem.appendChild( doc.createTextNode( QString::number(
mOffset ) ) );
986 symbolizerElem.appendChild( perpOffsetElem );
995 QDomElement strokeElem = element.firstChildElement(
"Stroke" );
996 if ( strokeElem.isNull() )
999 QDomElement graphicStrokeElem = strokeElem.firstChildElement(
"GraphicStroke" );
1000 if ( graphicStrokeElem.isNull() )
1008 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
1010 if ( it.key() ==
"placement" )
1012 if ( it.value() ==
"points" ) placement =
Vertex;
1013 else if ( it.value() ==
"firstPoint" ) placement =
FirstVertex;
1014 else if ( it.value() ==
"lastPoint" ) placement =
LastVertex;
1015 else if ( it.value() ==
"centralPoint" ) placement =
CentralPoint;
1017 else if ( it.value() ==
"rotateMarker" )
1019 rotateMarker = it.value() ==
"0";
1037 QDomElement gapElem = graphicStrokeElem.firstChildElement(
"Gap" );
1038 if ( !gapElem.isNull() )
1041 double d = gapElem.firstChild().nodeValue().toDouble( &ok );
1047 QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement(
"PerpendicularOffset" );
1048 if ( !perpOffsetElem.isNull() )
1051 double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );