00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "qgsmarkersymbollayerv2.h"
00017 #include "qgssymbollayerv2utils.h"
00018
00019 #include "qgsrendercontext.h"
00020 #include "qgsapplication.h"
00021 #include "qgslogger.h"
00022 #include "qgsproject.h"
00023 #include "qgssvgcache.h"
00024
00025 #include <QPainter>
00026 #include <QSvgRenderer>
00027 #include <QFileInfo>
00028 #include <QDir>
00029 #include <QDomDocument>
00030 #include <QDomElement>
00031
00032 #include <cmath>
00033
00034
00035 #ifndef M_PI
00036 #define M_PI 3.14159265358979323846
00037 #endif
00038
00039 #define DEG2RAD(x) ((x)*M_PI/180)
00040
00041
00042 static QPointF _rotatedOffset( const QPointF& offset, double angle )
00043 {
00044 angle = DEG2RAD( angle );
00045 double c = cos( angle ), s = sin( angle );
00046 return QPointF( offset.x() * c - offset.y() * s, offset.x() * s + offset.y() * c );
00047 }
00048
00050
00051 QgsSimpleMarkerSymbolLayerV2::QgsSimpleMarkerSymbolLayerV2( QString name, QColor color, QColor borderColor, double size, double angle )
00052 {
00053 mName = name;
00054 mColor = color;
00055 mBorderColor = borderColor;
00056 mSize = size;
00057 mAngle = angle;
00058 mOffset = QPointF( 0, 0 );
00059 }
00060
00061 QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::create( const QgsStringMap& props )
00062 {
00063 QString name = DEFAULT_SIMPLEMARKER_NAME;
00064 QColor color = DEFAULT_SIMPLEMARKER_COLOR;
00065 QColor borderColor = DEFAULT_SIMPLEMARKER_BORDERCOLOR;
00066 double size = DEFAULT_SIMPLEMARKER_SIZE;
00067 double angle = DEFAULT_SIMPLEMARKER_ANGLE;
00068
00069 if ( props.contains( "name" ) )
00070 name = props["name"];
00071 if ( props.contains( "color" ) )
00072 color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
00073 if ( props.contains( "color_border" ) )
00074 borderColor = QgsSymbolLayerV2Utils::decodeColor( props["color_border"] );
00075 if ( props.contains( "size" ) )
00076 size = props["size"].toDouble();
00077 if ( props.contains( "angle" ) )
00078 angle = props["angle"].toDouble();
00079
00080 QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size, angle );
00081 if ( props.contains( "offset" ) )
00082 m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
00083 return m;
00084 }
00085
00086
00087 QString QgsSimpleMarkerSymbolLayerV2::layerType() const
00088 {
00089 return "SimpleMarker";
00090 }
00091
00092 void QgsSimpleMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
00093 {
00094 QColor brushColor = mColor;
00095 QColor penColor = mBorderColor;
00096 if ( context.alpha() < 1 )
00097 {
00098 penColor.setAlphaF( context.alpha() );
00099 brushColor.setAlphaF( context.alpha() );
00100 }
00101 mBrush = QBrush( brushColor );
00102 mPen = QPen( penColor );
00103 mPen.setWidthF( context.outputLineWidth( mPen.widthF() ) );
00104
00105 QColor selBrushColor = context.selectionColor();
00106 QColor selPenColor = selBrushColor == mColor ? selBrushColor : mBorderColor;
00107 if ( context.alpha() < 1 )
00108 {
00109 selBrushColor.setAlphaF( context.alpha() );
00110 selPenColor.setAlphaF( context.alpha() );
00111 }
00112 mSelBrush = QBrush( selBrushColor );
00113 mSelPen = QPen( selPenColor );
00114 mSelPen.setWidthF( context.outputLineWidth( mPen.widthF() ) );
00115
00116 bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation;
00117 bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale;
00118
00119
00120
00121
00122 mUsingCache = !hasDataDefinedRotation && !hasDataDefinedSize && !context.renderContext().forceVectorOutput();
00123
00124
00125
00126 if ( !prepareShape() )
00127 {
00128 if ( preparePath() )
00129 {
00130
00131
00132
00133 if ( mName != "circle" )
00134 mSelPen.setColor( selBrushColor );
00135 }
00136 else
00137 {
00138 QgsDebugMsg( "unknown symbol" );
00139 return;
00140 }
00141 }
00142
00143 QMatrix transform;
00144
00145
00146 if ( !hasDataDefinedSize )
00147 {
00148 double scaledSize = context.outputLineWidth( mSize );
00149 if ( mUsingCache )
00150 scaledSize *= context.renderContext().rasterScaleFactor();
00151 double half = scaledSize / 2.0;
00152 transform.scale( half, half );
00153 }
00154
00155
00156 if ( !hasDataDefinedRotation && mAngle != 0 )
00157 {
00158 transform.rotate( mAngle );
00159 }
00160
00161 if ( !mPolygon.isEmpty() )
00162 mPolygon = transform.map( mPolygon );
00163 else
00164 mPath = transform.map( mPath );
00165
00166 if ( mUsingCache )
00167 {
00168 prepareCache( context );
00169 }
00170 else
00171 {
00172 mCache = QImage();
00173 mSelCache = QImage();
00174 }
00175 }
00176
00177
00178 void QgsSimpleMarkerSymbolLayerV2::prepareCache( QgsSymbolV2RenderContext& context )
00179 {
00180 double scaledSize = context.outputPixelSize( mSize );
00181
00182
00183 double pw = (( mPen.widthF() == 0 ? 1 : mPen.widthF() ) + 1 ) / 2 * 2;
00184 int imageSize = (( int ) scaledSize + pw ) / 2 * 2 + 1;
00185
00186 double center = (( double ) imageSize / 2 ) + 0.5;
00187
00188 mCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
00189 mCache.fill( 0 );
00190
00191 QPainter p;
00192 p.begin( &mCache );
00193 p.setRenderHint( QPainter::Antialiasing );
00194 p.setBrush( mBrush );
00195 p.setPen( mPen );
00196 p.translate( QPointF( center, center ) );
00197 drawMarker( &p, context );
00198 p.end();
00199
00200
00201
00202 QColor selColor = context.selectionColor();
00203
00204 mSelCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
00205 mSelCache.fill( 0 );
00206
00207 p.begin( &mSelCache );
00208 p.setRenderHint( QPainter::Antialiasing );
00209 p.setBrush( mSelBrush );
00210 p.setPen( mSelPen );
00211 p.translate( QPointF( center, center ) );
00212 drawMarker( &p, context );
00213 p.end();
00214
00215
00216
00217
00218
00219 if ( mSelCache == mCache )
00220 {
00221 p.begin( &mSelCache );
00222 p.setRenderHint( QPainter::Antialiasing );
00223 p.fillRect( 0, 0, imageSize, imageSize, selColor );
00224 p.setBrush( mBrush );
00225 p.setPen( mPen );
00226 p.translate( QPointF( center, center ) );
00227 drawMarker( &p, context );
00228 p.end();
00229 }
00230 }
00231
00232 void QgsSimpleMarkerSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
00233 {
00234 Q_UNUSED( context );
00235 }
00236
00237 bool QgsSimpleMarkerSymbolLayerV2::prepareShape()
00238 {
00239 mPolygon.clear();
00240
00241 if ( mName == "square" || mName == "rectangle" )
00242 {
00243 mPolygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 1, 1 ) ) );
00244 return true;
00245 }
00246 else if ( mName == "diamond" )
00247 {
00248 mPolygon << QPointF( -1, 0 ) << QPointF( 0, 1 )
00249 << QPointF( 1, 0 ) << QPointF( 0, -1 );
00250 return true;
00251 }
00252 else if ( mName == "pentagon" )
00253 {
00254 mPolygon << QPointF( sin( DEG2RAD( 288.0 ) ), - cos( DEG2RAD( 288.0 ) ) )
00255 << QPointF( sin( DEG2RAD( 216.0 ) ), - cos( DEG2RAD( 216.0 ) ) )
00256 << QPointF( sin( DEG2RAD( 144.0 ) ), - cos( DEG2RAD( 144.0 ) ) )
00257 << QPointF( sin( DEG2RAD( 72.0 ) ), - cos( DEG2RAD( 72.0 ) ) )
00258 << QPointF( 0, -1 );
00259 return true;
00260 }
00261 else if ( mName == "triangle" )
00262 {
00263 mPolygon << QPointF( -1, 1 ) << QPointF( 1, 1 ) << QPointF( 0, -1 );
00264 return true;
00265 }
00266 else if ( mName == "equilateral_triangle" )
00267 {
00268 mPolygon << QPointF( sin( DEG2RAD( 240.0 ) ), - cos( DEG2RAD( 240.0 ) ) )
00269 << QPointF( sin( DEG2RAD( 120.0 ) ), - cos( DEG2RAD( 120.0 ) ) )
00270 << QPointF( 0, -1 );
00271 return true;
00272 }
00273 else if ( mName == "star" )
00274 {
00275 double sixth = 1.0 / 3;
00276
00277 mPolygon << QPointF( 0, -1 )
00278 << QPointF( -sixth, -sixth )
00279 << QPointF( -1, -sixth )
00280 << QPointF( -sixth, 0 )
00281 << QPointF( -1, 1 )
00282 << QPointF( 0, + sixth )
00283 << QPointF( 1, 1 )
00284 << QPointF( + sixth, 0 )
00285 << QPointF( 1, -sixth )
00286 << QPointF( + sixth, -sixth );
00287 return true;
00288 }
00289 else if ( mName == "regular_star" )
00290 {
00291 double inner_r = cos( DEG2RAD( 72.0 ) ) / cos( DEG2RAD( 36.0 ) );
00292
00293 mPolygon << QPointF( inner_r * sin( DEG2RAD( 324.0 ) ), - inner_r * cos( DEG2RAD( 324.0 ) ) )
00294 << QPointF( sin( DEG2RAD( 288.0 ) ) , - cos( DEG2RAD( 288 ) ) )
00295 << QPointF( inner_r * sin( DEG2RAD( 252.0 ) ), - inner_r * cos( DEG2RAD( 252.0 ) ) )
00296 << QPointF( sin( DEG2RAD( 216.0 ) ) , - cos( DEG2RAD( 216.0 ) ) )
00297 << QPointF( 0, inner_r )
00298 << QPointF( sin( DEG2RAD( 144.0 ) ) , - cos( DEG2RAD( 144.0 ) ) )
00299 << QPointF( inner_r * sin( DEG2RAD( 108.0 ) ), - inner_r * cos( DEG2RAD( 108.0 ) ) )
00300 << QPointF( sin( DEG2RAD( 72.0 ) ) , - cos( DEG2RAD( 72.0 ) ) )
00301 << QPointF( inner_r * sin( DEG2RAD( 36.0 ) ), - inner_r * cos( DEG2RAD( 36.0 ) ) )
00302 << QPointF( 0, -1 );
00303 return true;
00304 }
00305 else if ( mName == "arrow" )
00306 {
00307 mPolygon
00308 << QPointF( 0, -1 )
00309 << QPointF( 0.5, -0.5 )
00310 << QPointF( 0.25, -0.25 )
00311 << QPointF( 0.25, 1 )
00312 << QPointF( -0.25, 1 )
00313 << QPointF( -0.25, -0.5 )
00314 << QPointF( -0.5, -0.5 );
00315 return true;
00316 }
00317 else if ( mName == "filled_arrowhead" )
00318 {
00319 mPolygon << QPointF( 0, 0 ) << QPointF( -1, 1 ) << QPointF( -1, -1 );
00320 return true;
00321 }
00322
00323 return false;
00324 }
00325
00326 bool QgsSimpleMarkerSymbolLayerV2::preparePath()
00327 {
00328 mPath = QPainterPath();
00329
00330 if ( mName == "circle" )
00331 {
00332 mPath.addEllipse( QRectF( -1, -1, 2, 2 ) );
00333 return true;
00334 }
00335 else if ( mName == "cross" )
00336 {
00337 mPath.moveTo( -1, 0 );
00338 mPath.lineTo( 1, 0 );
00339 mPath.moveTo( 0, -1 );
00340 mPath.lineTo( 0, 1 );
00341 return true;
00342 }
00343 else if ( mName == "x" || mName == "cross2" )
00344 {
00345 mPath.moveTo( -1, -1 );
00346 mPath.lineTo( 1, 1 );
00347 mPath.moveTo( 1, -1 );
00348 mPath.lineTo( -1, 1 );
00349 return true;
00350 }
00351 else if ( mName == "line" )
00352 {
00353 mPath.moveTo( 0, -1 );
00354 mPath.lineTo( 0, 1 );
00355 return true;
00356 }
00357 else if ( mName == "arrowhead" )
00358 {
00359 mPath.moveTo( 0, 0 );
00360 mPath.lineTo( -1, -1 );
00361 mPath.moveTo( 0, 0 );
00362 mPath.lineTo( -1, 1 );
00363 return true;
00364 }
00365
00366 return false;
00367 }
00368
00369 void QgsSimpleMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context )
00370 {
00371 QgsRenderContext& rc = context.renderContext();
00372 QPainter* p = rc.painter();
00373 if ( !p )
00374 {
00375 return;
00376 }
00377
00378 QPointF off( context.outputLineWidth( mOffset.x() ), context.outputLineWidth( mOffset.y() ) );
00379 if ( mAngle )
00380 off = _rotatedOffset( off, mAngle );
00381
00382 if ( mUsingCache )
00383 {
00384
00385 QImage &img = context.selected() ? mSelCache : mCache;
00386 double s = img.width() / context.renderContext().rasterScaleFactor();
00387 p->drawImage( QRectF( point.x() - s / 2.0 + off.x(),
00388 point.y() - s / 2.0 + off.y(),
00389 s, s ), img );
00390 }
00391 else
00392 {
00393 QMatrix transform;
00394
00395 bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation;
00396 bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale;
00397
00398
00399 transform.translate( point.x() + off.x(), point.y() + off.y() );
00400
00401
00402 if ( hasDataDefinedSize )
00403 {
00404 double scaledSize = context.outputLineWidth( mSize );
00405 double half = scaledSize / 2.0;
00406 transform.scale( half, half );
00407 }
00408
00409
00410 if ( mAngle != 0 && hasDataDefinedRotation )
00411 {
00412 transform.rotate( mAngle );
00413 }
00414
00415 p->setBrush( context.selected() ? mSelBrush : mBrush );
00416 p->setPen( context.selected() ? mSelPen : mPen );
00417
00418 if ( !mPolygon.isEmpty() )
00419 p->drawPolygon( transform.map( mPolygon ) );
00420 else
00421 p->drawPath( transform.map( mPath ) );
00422 }
00423 }
00424
00425
00426 QgsStringMap QgsSimpleMarkerSymbolLayerV2::properties() const
00427 {
00428 QgsStringMap map;
00429 map["name"] = mName;
00430 map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
00431 map["color_border"] = QgsSymbolLayerV2Utils::encodeColor( mBorderColor );
00432 map["size"] = QString::number( mSize );
00433 map["angle"] = QString::number( mAngle );
00434 map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
00435 return map;
00436 }
00437
00438 QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::clone() const
00439 {
00440 QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( mName, mColor, mBorderColor, mSize, mAngle );
00441 m->setOffset( mOffset );
00442 return m;
00443 }
00444
00445 void QgsSimpleMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
00446 {
00447
00448 QDomElement graphicElem = doc.createElement( "se:Graphic" );
00449 element.appendChild( graphicElem );
00450
00451 QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, mName, mColor, mBorderColor, -1, mSize );
00452
00453
00454 QString angleFunc;
00455 bool ok;
00456 double angle = props.value( "angle", "0" ).toDouble( &ok );
00457 if ( !ok )
00458 {
00459 angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
00460 }
00461 else if ( angle + mAngle != 0 )
00462 {
00463 angleFunc = QString::number( angle + mAngle );
00464 }
00465 QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
00466
00467
00468 QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
00469 }
00470
00471 QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::createFromSld( QDomElement &element )
00472 {
00473 QgsDebugMsg( "Entered." );
00474
00475 QDomElement graphicElem = element.firstChildElement( "Graphic" );
00476 if ( graphicElem.isNull() )
00477 return NULL;
00478
00479 QString name = "square";
00480 QColor color, borderColor;
00481 double borderWidth, size;
00482
00483 if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, color, borderColor, borderWidth, size ) )
00484 return NULL;
00485
00486 double angle = 0.0;
00487 QString angleFunc;
00488 if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
00489 {
00490 bool ok;
00491 double d = angleFunc.toDouble( &ok );
00492 if ( ok )
00493 angle = d;
00494 }
00495
00496 QPointF offset;
00497 QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, offset );
00498
00499 QgsMarkerSymbolLayerV2 *m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size );
00500 m->setAngle( angle );
00501 m->setOffset( offset );
00502 return m;
00503 }
00504
00505 void QgsSimpleMarkerSymbolLayerV2::drawMarker( QPainter* p, QgsSymbolV2RenderContext& context )
00506 {
00507 Q_UNUSED( context );
00508
00509 if ( mPolygon.count() != 0 )
00510 {
00511 p->drawPolygon( mPolygon );
00512 }
00513 else
00514 {
00515 p->drawPath( mPath );
00516 }
00517 }
00518
00519
00521
00522
00523 QgsSvgMarkerSymbolLayerV2::QgsSvgMarkerSymbolLayerV2( QString name, double size, double angle )
00524 {
00525 mPath = symbolNameToPath( name );
00526 mSize = size;
00527 mAngle = angle;
00528 mOffset = QPointF( 0, 0 );
00529 mOutlineWidth = 1.0;
00530 mFillColor = QColor( Qt::black );
00531 mOutlineColor = QColor( Qt::black );
00532 }
00533
00534
00535 QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::create( const QgsStringMap& props )
00536 {
00537 QString name = DEFAULT_SVGMARKER_NAME;
00538 double size = DEFAULT_SVGMARKER_SIZE;
00539 double angle = DEFAULT_SVGMARKER_ANGLE;
00540
00541 if ( props.contains( "name" ) )
00542 name = props["name"];
00543 if ( props.contains( "size" ) )
00544 size = props["size"].toDouble();
00545 if ( props.contains( "angle" ) )
00546 angle = props["angle"].toDouble();
00547
00548 QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( name, size, angle );
00549
00550
00551 if ( !props.contains( "fill" ) && !props.contains( "outline" ) && !props.contains( "outline-width" ) )
00552 {
00553 QColor fillColor, outlineColor;
00554 double outlineWidth;
00555 bool hasFillParam, hasOutlineParam, hasOutlineWidthParam;
00556 QgsSvgCache::instance()->containsParams( name, hasFillParam, fillColor, hasOutlineParam, outlineColor, hasOutlineWidthParam, outlineWidth );
00557 if ( hasFillParam )
00558 {
00559 m->setFillColor( fillColor );
00560 }
00561 if ( hasOutlineParam )
00562 {
00563 m->setOutlineColor( outlineColor );
00564 }
00565 if ( hasOutlineWidthParam )
00566 {
00567 m->setOutlineWidth( outlineWidth );
00568 }
00569 }
00570
00571 if ( props.contains( "offset" ) )
00572 m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
00573 if ( props.contains( "fill" ) )
00574 m->setFillColor( QColor( props["fill"] ) );
00575 if ( props.contains( "outline" ) )
00576 m->setOutlineColor( QColor( props["outline"] ) );
00577 if ( props.contains( "outline-width" ) )
00578 m->setOutlineWidth( props["outline-width"].toDouble() );
00579 return m;
00580 }
00581
00582 void QgsSvgMarkerSymbolLayerV2::setPath( QString path )
00583 {
00584 mPath = path;
00585 QColor fillColor, outlineColor;
00586 double outlineWidth;
00587 bool hasFillParam, hasOutlineParam, hasOutlineWidthParam;
00588 QgsSvgCache::instance()->containsParams( path, hasFillParam, fillColor, hasOutlineParam, outlineColor, hasOutlineWidthParam, outlineWidth );
00589 if ( hasFillParam )
00590 {
00591 setFillColor( fillColor );
00592 }
00593 if ( hasOutlineParam )
00594 {
00595 setOutlineColor( outlineColor );
00596 }
00597 if ( hasOutlineWidthParam )
00598 {
00599 setOutlineWidth( outlineWidth );
00600 }
00601 }
00602
00603
00604 QString QgsSvgMarkerSymbolLayerV2::layerType() const
00605 {
00606 return "SvgMarker";
00607 }
00608
00609 void QgsSvgMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
00610 {
00611 mOrigSize = mSize;
00612 Q_UNUSED( context );
00613 }
00614
00615 void QgsSvgMarkerSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
00616 {
00617 Q_UNUSED( context );
00618 }
00619
00620 void QgsSvgMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context )
00621 {
00622 QPainter* p = context.renderContext().painter();
00623 if ( !p )
00624 {
00625 return;
00626 }
00627
00628 p->save();
00629 QPointF outputOffset = QPointF( context.outputLineWidth( mOffset.x() ), context.outputLineWidth( mOffset.y() ) );
00630 if ( mAngle )
00631 outputOffset = _rotatedOffset( outputOffset, mAngle );
00632 p->translate( point + outputOffset );
00633
00634 int size = ( int )( context.outputLineWidth( mSize ) );
00635 if ( size < 1 )
00636 {
00637 return;
00638 }
00639
00640 bool rotated = !doubleNear( mAngle, 0 );
00641 bool drawOnScreen = doubleNear( context.renderContext().rasterScaleFactor(), 1.0, 0.1 );
00642 if ( rotated )
00643 p->rotate( mAngle );
00644
00645 if ( drawOnScreen && !rotated )
00646 {
00647 const QImage& img = QgsSvgCache::instance()->svgAsImage( mPath, size, mFillColor, mOutlineColor, mOutlineWidth,
00648 context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() );
00649
00650 if ( !doubleNear( context.alpha(), 1.0 ) )
00651 {
00652 QImage transparentImage = img.copy();
00653 QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
00654 p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
00655 }
00656 else
00657 {
00658 p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
00659 }
00660 }
00661 else
00662 {
00663 p->setOpacity( context.alpha( ) );
00664 const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( mPath, size, mFillColor, mOutlineColor, mOutlineWidth,
00665 context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() );
00666 p->drawPicture( 0, 0, pct );
00667 }
00668
00669 if ( context.selected() )
00670 {
00671 QPen pen( context.selectionColor() );
00672 pen.setWidth( context.outputLineWidth( 1.0 ) );
00673 p->setPen( pen );
00674 p->setBrush( Qt::NoBrush );
00675 double sizePixel = context.outputLineWidth( mSize );
00676 p->drawRect( QRectF( -sizePixel / 2.0, -sizePixel / 2.0, sizePixel, sizePixel ) );
00677 }
00678
00679 p->restore();
00680 }
00681
00682
00683 QgsStringMap QgsSvgMarkerSymbolLayerV2::properties() const
00684 {
00685 QgsStringMap map;
00686 map["name"] = symbolPathToName( mPath );
00687 map["size"] = QString::number( mSize );
00688 map["angle"] = QString::number( mAngle );
00689 map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
00690 map["fill"] = mFillColor.name();
00691 map["outline"] = mOutlineColor.name();
00692 map["outline-width"] = QString::number( mOutlineWidth );
00693 return map;
00694 }
00695
00696 QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::clone() const
00697 {
00698 QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( mPath, mSize, mAngle );
00699 m->setFillColor( mFillColor );
00700 m->setOutlineColor( mOutlineColor );
00701 m->setOutlineWidth( mOutlineWidth );
00702 m->setOffset( mOffset );
00703 return m;
00704 }
00705
00706 void QgsSvgMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
00707 {
00708
00709 QDomElement graphicElem = doc.createElement( "se:Graphic" );
00710 element.appendChild( graphicElem );
00711
00712 QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mFillColor, mSize );
00713
00714
00715 QString angleFunc;
00716 bool ok;
00717 double angle = props.value( "angle", "0" ).toDouble( &ok );
00718 if ( !ok )
00719 {
00720 angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
00721 }
00722 else if ( angle + mAngle != 0 )
00723 {
00724 angleFunc = QString::number( angle + mAngle );
00725 }
00726
00727 QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
00728
00729
00730 QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
00731 }
00732
00733 QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::createFromSld( QDomElement &element )
00734 {
00735 QgsDebugMsg( "Entered." );
00736
00737 QDomElement graphicElem = element.firstChildElement( "Graphic" );
00738 if ( graphicElem.isNull() )
00739 return NULL;
00740
00741 QString path, mimeType;
00742 QColor fillColor;
00743 double size;
00744
00745 if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
00746 return NULL;
00747
00748 if ( mimeType != "image/svg+xml" )
00749 return NULL;
00750
00751 double angle = 0.0;
00752 QString angleFunc;
00753 if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
00754 {
00755 bool ok;
00756 double d = angleFunc.toDouble( &ok );
00757 if ( ok )
00758 angle = d;
00759 }
00760
00761 QPointF offset;
00762 QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, offset );
00763
00764 QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( path, size );
00765 m->setFillColor( fillColor );
00766
00767
00768 m->setAngle( angle );
00769 m->setOffset( offset );
00770 return m;
00771 }
00772
00773
00774 QStringList QgsSvgMarkerSymbolLayerV2::listSvgFiles()
00775 {
00776
00777 QStringList list;
00778 QStringList svgPaths = QgsApplication::svgPaths();
00779
00780 for ( int i = 0; i < svgPaths.size(); i++ )
00781 {
00782 QDir dir( svgPaths[i] );
00783 foreach( QString item, dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
00784 {
00785 svgPaths.insert( i + 1, dir.path() + "/" + item );
00786 }
00787
00788 foreach( QString item, dir.entryList( QStringList( "*.svg" ), QDir::Files ) )
00789 {
00790
00791 list.append( dir.path() + "/" + item );
00792 }
00793 }
00794 return list;
00795 }
00796
00797 QString QgsSvgMarkerSymbolLayerV2::symbolNameToPath( QString name )
00798 {
00799
00800
00801
00802 if ( QFile( name ).exists() )
00803 return QFileInfo( name ).canonicalFilePath();
00804
00805
00806
00807 QStringList svgPaths = QgsApplication::svgPaths();
00808 for ( int i = 0; i < svgPaths.size(); i++ )
00809 {
00810 QgsDebugMsg( "SvgPath: " + svgPaths[i] );
00811 QFileInfo myInfo( name );
00812 QString myFileName = myInfo.fileName();
00813 QString myLowestDir = myInfo.dir().dirName();
00814 QString myLocalPath = svgPaths[i] + "/" + myLowestDir + "/" + myFileName;
00815
00816 QgsDebugMsg( "Alternative svg path: " + myLocalPath );
00817 if ( QFile( myLocalPath ).exists() )
00818 {
00819 QgsDebugMsg( "Svg found in alternative path" );
00820 return QFileInfo( myLocalPath ).canonicalFilePath();
00821 }
00822 else if ( myInfo.isRelative() )
00823 {
00824 QFileInfo pfi( QgsProject::instance()->fileName() );
00825 QString alternatePath = pfi.canonicalPath() + QDir::separator() + name;
00826 if ( pfi.exists() && QFile( alternatePath ).exists() )
00827 {
00828 QgsDebugMsg( "Svg found in alternative path" );
00829 return QFileInfo( alternatePath ).canonicalFilePath();
00830 }
00831 else
00832 {
00833 QgsDebugMsg( "Svg not found in project path" );
00834 }
00835 }
00836 else
00837 {
00838
00839 QgsDebugMsg( "Computed alternate path but no svg there either" );
00840 }
00841 }
00842 return QString();
00843 }
00844
00845 QString QgsSvgMarkerSymbolLayerV2::symbolPathToName( QString path )
00846 {
00847
00848
00849 QFileInfo fi( path );
00850 if ( !fi.exists() )
00851 return path;
00852
00853 path = fi.canonicalFilePath();
00854
00855 QStringList svgPaths = QgsApplication::svgPaths();
00856
00857 for ( int i = 0; i < svgPaths.size(); i++ )
00858 {
00859 QString dir = QFileInfo( svgPaths[i] ).canonicalFilePath();
00860
00861 if ( !dir.isEmpty() && path.startsWith( dir ) )
00862 {
00863 path = path.mid( dir.size() );
00864 break;
00865 }
00866 }
00867
00868 return path;
00869 }
00870
00871
00873
00874 QgsFontMarkerSymbolLayerV2::QgsFontMarkerSymbolLayerV2( QString fontFamily, QChar chr, double pointSize, QColor color, double angle )
00875 {
00876 mFontFamily = fontFamily;
00877 mChr = chr;
00878 mColor = color;
00879 mAngle = angle;
00880 mSize = pointSize;
00881 mOffset = QPointF( 0, 0 );
00882 }
00883
00884 QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::create( const QgsStringMap& props )
00885 {
00886 QString fontFamily = DEFAULT_FONTMARKER_FONT;
00887 QChar chr = DEFAULT_FONTMARKER_CHR;
00888 double pointSize = DEFAULT_FONTMARKER_SIZE;
00889 QColor color = DEFAULT_FONTMARKER_COLOR;
00890 double angle = DEFAULT_FONTMARKER_ANGLE;
00891
00892 if ( props.contains( "font" ) )
00893 fontFamily = props["font"];
00894 if ( props.contains( "chr" ) && props["chr"].length() > 0 )
00895 chr = props["chr"].at( 0 );
00896 if ( props.contains( "size" ) )
00897 pointSize = props["size"].toDouble();
00898 if ( props.contains( "color" ) )
00899 color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
00900 if ( props.contains( "angle" ) )
00901 angle = props["angle"].toDouble();
00902
00903 QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, pointSize, color, angle );
00904 if ( props.contains( "offset" ) )
00905 m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
00906 return m;
00907 }
00908
00909 QString QgsFontMarkerSymbolLayerV2::layerType() const
00910 {
00911 return "FontMarker";
00912 }
00913
00914 void QgsFontMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
00915 {
00916 mFont = QFont( mFontFamily );
00917 mFont.setPixelSize( context.outputLineWidth( mSize ) );
00918 QFontMetrics fm( mFont );
00919 mChrOffset = QPointF( fm.width( mChr ) / 2, -fm.ascent() / 2 );
00920
00921 mOrigSize = mSize;
00922 }
00923
00924 void QgsFontMarkerSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
00925 {
00926 Q_UNUSED( context );
00927 }
00928
00929 void QgsFontMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context )
00930 {
00931 QPainter* p = context.renderContext().painter();
00932 QColor penColor = context.selected() ? context.selectionColor() : mColor;
00933 penColor.setAlphaF( context.alpha() );
00934 p->setPen( penColor );
00935 p->setFont( mFont );
00936
00937
00938 p->save();
00939 QPointF outputOffset = QPointF( context.outputLineWidth( mOffset.x() ), context.outputLineWidth( mOffset.y() ) );
00940 if ( mAngle )
00941 outputOffset = _rotatedOffset( outputOffset, mAngle );
00942 p->translate( point + outputOffset );
00943
00944 if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
00945 {
00946 double s = mSize / mOrigSize;
00947 p->scale( s, s );
00948 }
00949
00950 if ( mAngle != 0 )
00951 p->rotate( mAngle );
00952
00953 p->drawText( -mChrOffset, mChr );
00954 p->restore();
00955 }
00956
00957 QgsStringMap QgsFontMarkerSymbolLayerV2::properties() const
00958 {
00959 QgsStringMap props;
00960 props["font"] = mFontFamily;
00961 props["chr"] = mChr;
00962 props["size"] = QString::number( mSize );
00963 props["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
00964 props["angle"] = QString::number( mAngle );
00965 props["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
00966 return props;
00967 }
00968
00969 QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::clone() const
00970 {
00971 QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( mFontFamily, mChr, mSize, mColor, mAngle );
00972 m->setOffset( mOffset );
00973 return m;
00974 }
00975
00976 void QgsFontMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
00977 {
00978
00979 QDomElement graphicElem = doc.createElement( "se:Graphic" );
00980 element.appendChild( graphicElem );
00981
00982 QString fontPath = QString( "ttf://%1" ).arg( mFontFamily );
00983 int markIndex = mChr.unicode();
00984 QgsSymbolLayerV2Utils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, mSize );
00985
00986
00987 QString angleFunc;
00988 bool ok;
00989 double angle = props.value( "angle", "0" ).toDouble( &ok );
00990 if ( !ok )
00991 {
00992 angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
00993 }
00994 else if ( angle + mAngle != 0 )
00995 {
00996 angleFunc = QString::number( angle + mAngle );
00997 }
00998 QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
00999
01000
01001 QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
01002 }
01003
01004 QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::createFromSld( QDomElement &element )
01005 {
01006 QgsDebugMsg( "Entered." );
01007
01008 QDomElement graphicElem = element.firstChildElement( "Graphic" );
01009 if ( graphicElem.isNull() )
01010 return NULL;
01011
01012 QString name, format;
01013 QColor color;
01014 double size;
01015 int chr;
01016
01017 if ( !QgsSymbolLayerV2Utils::externalMarkerFromSld( graphicElem, name, format, chr, color, size ) )
01018 return NULL;
01019
01020 if ( !name.startsWith( "ttf://" ) || format != "ttf" )
01021 return NULL;
01022
01023 QString fontFamily = name.mid( 6 );
01024
01025 double angle = 0.0;
01026 QString angleFunc;
01027 if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
01028 {
01029 bool ok;
01030 double d = angleFunc.toDouble( &ok );
01031 if ( ok )
01032 angle = d;
01033 }
01034
01035 QPointF offset;
01036 QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, offset );
01037
01038 QgsMarkerSymbolLayerV2 *m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, size, color );
01039 m->setAngle( angle );
01040 m->setOffset( offset );
01041 return m;
01042 }