00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <cmath>
00017 #include <assert.h>
00018
00019 #include <QPen>
00020 #include <QBrush>
00021 #include <QPainter>
00022 #include <QImage>
00023 #include <QString>
00024 #include <QStringList>
00025 #include <QRect>
00026 #include <QPointF>
00027 #include <QPolygonF>
00028 #include <QDir>
00029 #include <QPicture>
00030 #include <QSvgRenderer>
00031
00032 #include "qgis.h"
00033 #include "qgsapplication.h"
00034 #include "qgsmarkercatalogue.h"
00035 #include "qgslogger.h"
00036
00037
00038 #ifndef M_PI
00039 #define M_PI 3.14159265358979323846
00040 #endif
00041
00042 #define DEG2RAD(x) ((x)*M_PI/180)
00043
00044
00045
00046 QgsMarkerCatalogue *QgsMarkerCatalogue::mMarkerCatalogue = 0;
00047
00048 QgsMarkerCatalogue::QgsMarkerCatalogue()
00049 {
00050 refreshList();
00051 }
00052
00053 void QgsMarkerCatalogue::refreshList()
00054 {
00055
00056 mList.clear();
00057
00058
00059 mList.append( "hard:circle" );
00060 mList.append( "hard:rectangle" );
00061 mList.append( "hard:diamond" );
00062 mList.append( "hard:pentagon" );
00063 mList.append( "hard:cross" );
00064 mList.append( "hard:cross2" );
00065 mList.append( "hard:triangle" );
00066 mList.append( "hard:equilateral_triangle" );
00067 mList.append( "hard:star" );
00068 mList.append( "hard:regular_star" );
00069 mList.append( "hard:arrow" );
00070
00071
00072 QStringList svgPaths = QgsApplication::svgPaths();
00073 QgsDebugMsg( QString( "Application SVG Search paths: \n%1" ).arg( svgPaths.join( "\n" ) ) );
00074
00075 for ( int i = 0; i < svgPaths.size(); i++ )
00076 {
00077 QDir dir( svgPaths[i] );
00078 foreach( QString item, dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
00079 {
00080 svgPaths.insert( i + 1, dir.path() + "/" + item );
00081 }
00082
00083 QgsDebugMsg( QString( "Looking for svgs in %1" ).arg( dir.path() ) );
00084
00085 foreach( QString item, dir.entryList( QStringList( "*.svg" ), QDir::Files ) )
00086 {
00087
00088 mList.append( "svg:" + dir.path() + "/" + item );
00089 }
00090 }
00091
00092 emit markersRefreshed();
00093 }
00094
00095 QStringList QgsMarkerCatalogue::list()
00096 {
00097 return mList;
00098 }
00099
00100 QgsMarkerCatalogue::~QgsMarkerCatalogue()
00101 {
00102 }
00103
00104 QgsMarkerCatalogue *QgsMarkerCatalogue::instance()
00105 {
00106 if ( !QgsMarkerCatalogue::mMarkerCatalogue )
00107 {
00108 QgsMarkerCatalogue::mMarkerCatalogue = new QgsMarkerCatalogue();
00109 }
00110
00111 return QgsMarkerCatalogue::mMarkerCatalogue;
00112 }
00113
00114 QImage QgsMarkerCatalogue::imageMarker( QString fullName, double size, QPen pen, QBrush brush, double opacity )
00115 {
00116
00117
00118
00119
00120
00121 QImage myImage;
00122 int imageSize;
00123 if ( fullName.startsWith( "hard:" ) )
00124 {
00125 int pw = (( pen.width() == 0 ? 1 : pen.width() ) + 1 ) / 2 * 2;
00126 imageSize = (( int ) size + pw ) / 2 * 2 + 1;
00127 myImage = QImage( imageSize, imageSize, QImage::Format_ARGB32_Premultiplied );
00128 }
00129 else
00130 {
00131
00132
00133
00134 imageSize = (( int ) size ) / 2 * 2 + 1;
00135 myImage = QImage( imageSize, imageSize, QImage::Format_ARGB32_Premultiplied );
00136 }
00137
00138
00139 myImage.fill( 0 );
00140
00141 QPainter myPainter;
00142 myPainter.begin( &myImage );
00143 myPainter.setRenderHint( QPainter::Antialiasing );
00144 myPainter.setOpacity( opacity );
00145
00146
00147
00148
00149 if ( fullName.startsWith( "svg:" ) )
00150 {
00151 if ( svgMarker( &myPainter, fullName.mid( 4 ), size ) )
00152 return myImage;
00153
00154 QgsDebugMsg( QString( "%1 not found - replacing with hard:circle" ).arg( fullName ) );
00155 fullName = "hard:circle";
00156 }
00157
00158 if ( fullName.startsWith( "font:" ) )
00159 {
00160 if ( fontMarker( &myPainter, fullName.mid( 5 ), size ) )
00161 return myImage;
00162
00163 QgsDebugMsg( QString( "%1 not found - replacing with hard:circle" ).arg( fullName ) );
00164 fullName = "hard:circle";
00165 }
00166
00167 if ( fullName.endsWith( ".svg", Qt::CaseInsensitive ) )
00168 {
00169 if ( svgMarker( &myPainter, fullName, size ) )
00170 return myImage;
00171
00172 QgsDebugMsg( QString( "%1 not found - replacing with hard:circle" ).arg( fullName ) );
00173 fullName = "hard:circle";
00174 }
00175
00176 if ( fullName.startsWith( "hard:" ) )
00177 {
00178 hardMarker( &myPainter, imageSize, fullName.mid( 5 ), size, pen, brush );
00179 #ifdef IMAGEDEBUG
00180 QgsDebugMsg( "*** Saving hard marker to hardMarker.png ***" );
00181 #ifdef QGISDEBUG
00182 myImage.save( "hardMarker.png" );
00183 #endif
00184 #endif
00185 return myImage;
00186 }
00187
00188 return QImage();
00189 }
00190
00191 QPicture QgsMarkerCatalogue::pictureMarker( QString fullName, double size, QPen pen, QBrush brush, double opacity )
00192 {
00193
00194
00195
00196
00197 QPicture myPicture;
00198 if ( fullName.left( 5 ) == "hard:" )
00199 {
00200
00201
00202 myPicture = QPicture( size + 1 );
00203 }
00204 else
00205 {
00206
00207
00208 if ( size < 1 ) size = 1;
00209 myPicture = QPicture( size );
00210 }
00211
00212 QPainter myPainter( &myPicture );
00213 myPainter.setRenderHint( QPainter::Antialiasing );
00214 myPainter.setOpacity( opacity );
00215
00216
00217
00218
00219 if ( fullName.left( 4 ) == "svg:" )
00220 {
00221 if ( svgMarker( &myPainter, fullName.mid( 4 ), size ) )
00222 return myPicture;
00223
00224 QgsDebugMsg( QString( "%1 not found - replacing with hard:circle" ).arg( fullName ) );
00225 fullName = "hard:circle";
00226 }
00227
00228 if ( fullName.left( 5 ) == "hard:" )
00229 {
00230 hardMarker( &myPainter, ( int ) size, fullName.mid( 5 ), size, pen, brush );
00231 return myPicture;
00232 }
00233
00234 return QPicture();
00235 }
00236
00237 bool QgsMarkerCatalogue::fontMarker( QPainter *thepPainter, QString fullName, double scaleFactor )
00238 {
00239 QStringList args = fullName.split( "," );
00240 if ( args.size() == 0 )
00241 return false;
00242
00243 QChar c;
00244
00245 if ( args.size() > 0 )
00246 {
00247 if ( args[0] == "#" )
00248 {
00249 c = QChar( '#' );
00250 }
00251 else if ( args[0].startsWith( "#" ) )
00252 {
00253 c = QChar( args[0].mid( 1 ).toInt() );
00254 }
00255 else
00256 {
00257 c = args[0][0];
00258 }
00259 }
00260
00261 QString family = args.size() >= 2 ? args[1] : "Helvetica";
00262 int weight = args.size() >= 3 ? args[2].toInt() : -1;
00263 int italic = args.size() >= 4 ? args[3].toInt() != 0 : false;
00264
00265 thepPainter->setFont( QFont( family, scaleFactor, weight, italic ) );
00266 thepPainter->drawText( 0, 0, c );
00267
00268 return true;
00269 }
00270
00271 bool QgsMarkerCatalogue::svgMarker( QPainter * thepPainter, QString fileName, double scaleFactor )
00272 {
00273 QSvgRenderer mySVG;
00274 if ( !mySVG.load( fileName ) )
00275 return false;
00276
00277 mySVG.render( thepPainter );
00278
00279 return true;
00280 }
00281
00282 void QgsMarkerCatalogue::hardMarker( QPainter * thepPainter, int imageSize, QString name, double s, QPen pen, QBrush brush )
00283 {
00284
00285
00286
00287 #if 0
00288 s = s - pen.widthF();
00289 #else
00290
00291 #endif
00292
00293
00294
00295 double r = s / 2;
00296
00297 QgsDebugMsgLevel( QString( "Hard marker size %1" ).arg( s ), 3 );
00298
00299
00300 double x_c = ( double )( imageSize / 2 ) + 0.5;
00301 double y_c = x_c;
00302
00303 thepPainter->setPen( pen );
00304 thepPainter->setBrush( brush );
00305
00306 QgsDebugMsgLevel( QString( "Hard marker radius %1" ).arg( r ), 3 );
00307
00308 if ( name == "circle" )
00309 {
00310
00311
00312
00313 thepPainter->drawEllipse( QRectF( x_c - r, y_c - r, s, s ) );
00314 }
00315 else if ( name == "rectangle" )
00316 {
00317 thepPainter->drawRect( QRectF( x_c - r, y_c - r, s, s ) );
00318 }
00319 else if ( name == "diamond" )
00320 {
00321 QPolygonF pa;
00322 pa << QPointF( x_c - r, y_c )
00323 << QPointF( x_c, y_c + r )
00324 << QPointF( x_c + r, y_c )
00325 << QPointF( x_c, y_c - r );
00326 thepPainter->drawPolygon( pa );
00327 }
00328 else if ( name == "pentagon" )
00329 {
00330 QPolygonF pa;
00331 pa << QPointF( x_c + ( r * sin( DEG2RAD( 288.0 ) ) ), y_c - ( r * cos( DEG2RAD( 288.0 ) ) ) )
00332 << QPointF( x_c + ( r * sin( DEG2RAD( 216.0 ) ) ), y_c - ( r * cos( DEG2RAD( 216.0 ) ) ) )
00333 << QPointF( x_c + ( r * sin( DEG2RAD( 144.0 ) ) ), y_c - ( r * cos( DEG2RAD( 144.0 ) ) ) )
00334 << QPointF( x_c + ( r * sin( DEG2RAD( 72.0 ) ) ), y_c - ( r * cos( DEG2RAD( 72.0 ) ) ) )
00335 << QPointF( x_c, y_c - r );
00336 thepPainter->drawPolygon( pa );
00337 }
00338 else if ( name == "cross" )
00339 {
00340 thepPainter->drawLine( QPointF( x_c - r, y_c ), QPointF( x_c + r, y_c ) );
00341 thepPainter->drawLine( QPointF( x_c, y_c - r ), QPointF( x_c, y_c + r ) );
00342 }
00343 else if ( name == "cross2" )
00344 {
00345 thepPainter->drawLine( QPointF( x_c - r, y_c - r ), QPointF( x_c + r, y_c + r ) );
00346 thepPainter->drawLine( QPointF( x_c - r, y_c + r ), QPointF( x_c + r, y_c - r ) );
00347 }
00348 else if ( name == "triangle" )
00349 {
00350 QPolygonF pa;
00351 pa << QPointF( x_c - r, y_c + r )
00352 << QPointF( x_c + r, y_c + r )
00353 << QPointF( x_c, y_c - r );
00354 thepPainter->drawPolygon( pa );
00355 }
00356 else if ( name == "equilateral_triangle" )
00357 {
00358 QPolygonF pa;
00359 pa << QPointF( x_c + ( r * sin( DEG2RAD( 240.0 ) ) ), y_c - ( r * cos( DEG2RAD( 240.0 ) ) ) )
00360 << QPointF( x_c + ( r * sin( DEG2RAD( 120.0 ) ) ), y_c - ( r * cos( DEG2RAD( 120.0 ) ) ) )
00361 << QPointF( x_c, y_c - r );
00362 thepPainter->drawPolygon( pa );
00363 }
00364 else if ( name == "star" )
00365 {
00366 double oneSixth = 2 * r / 6;
00367
00368 QPolygonF pa;
00369 pa << QPointF( x_c, y_c - r )
00370 << QPointF( x_c - oneSixth, y_c - oneSixth )
00371 << QPointF( x_c - r, y_c - oneSixth )
00372 << QPointF( x_c - oneSixth, y_c )
00373 << QPointF( x_c - r, y_c + r )
00374 << QPointF( x_c, y_c + oneSixth )
00375 << QPointF( x_c + r, y_c + r )
00376 << QPointF( x_c + oneSixth, y_c )
00377 << QPointF( x_c + r, y_c - oneSixth )
00378 << QPointF( x_c + oneSixth, y_c - oneSixth );
00379 thepPainter->drawPolygon( pa );
00380 }
00381 else if ( name == "regular_star" )
00382 {
00383
00384 double inner_r = r * cos( DEG2RAD( 72.0 ) ) / cos( DEG2RAD( 36.0 ) );
00385
00386 QPolygonF pa;
00387 pa << QPointF( x_c + ( inner_r * sin( DEG2RAD( 324.0 ) ) ), y_c - ( inner_r * cos( DEG2RAD( 324.0 ) ) ) )
00388 << QPointF( x_c + ( r * sin( DEG2RAD( 288.0 ) ) ), y_c - ( r * cos( DEG2RAD( 288 ) ) ) )
00389 << QPointF( x_c + ( inner_r * sin( DEG2RAD( 252.0 ) ) ), y_c - ( inner_r * cos( DEG2RAD( 252.0 ) ) ) )
00390 << QPointF( x_c + ( r * sin( DEG2RAD( 216.0 ) ) ), y_c - ( r * cos( DEG2RAD( 216.0 ) ) ) )
00391 << QPointF( x_c, y_c + ( inner_r ) )
00392 << QPointF( x_c + ( r * sin( DEG2RAD( 144.0 ) ) ), y_c - ( r * cos( DEG2RAD( 144.0 ) ) ) )
00393 << QPointF( x_c + ( inner_r * sin( DEG2RAD( 108.0 ) ) ), y_c - ( inner_r * cos( DEG2RAD( 108.0 ) ) ) )
00394 << QPointF( x_c + ( r * sin( DEG2RAD( 72.0 ) ) ), y_c - ( r * cos( DEG2RAD( 72.0 ) ) ) )
00395 << QPointF( x_c + ( inner_r * sin( DEG2RAD( 36.0 ) ) ), y_c - ( inner_r * cos( DEG2RAD( 36.0 ) ) ) )
00396 << QPointF( x_c, y_c - r );
00397 thepPainter->drawPolygon( pa );
00398 }
00399 else if ( name == "arrow" )
00400 {
00401 double oneEight = r / 4;
00402 double quarter = r / 2;
00403
00404 QPolygonF pa;
00405 pa << QPointF( x_c, y_c - r )
00406 << QPointF( x_c + quarter, y_c - quarter )
00407 << QPointF( x_c + oneEight, y_c - quarter )
00408 << QPointF( x_c + oneEight, y_c + r )
00409 << QPointF( x_c - oneEight, y_c + r )
00410 << QPointF( x_c - oneEight, y_c - quarter )
00411 << QPointF( x_c - quarter, y_c - quarter );
00412 thepPainter->drawPolygon( pa );
00413 }
00414 thepPainter->end();
00415 }