Skip to content

Commit

Permalink
Applying patch from smizuno to polish hard marker position accuracy. …
Browse files Browse the repository at this point in the history
…Many thanks! Fixes #1262

git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@9636 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
homann committed Nov 14, 2008
1 parent 8228596 commit 87816af
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 69 deletions.
176 changes: 108 additions & 68 deletions src/core/symbology/qgsmarkercatalogue.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ email : blazek@itc.it
* * * *
***************************************************************************/ ***************************************************************************/
#include <cmath> #include <cmath>
#include <iostream>
#include <assert.h> #include <assert.h>


#include <QPen> #include <QPen>
Expand All @@ -24,7 +23,8 @@ email : blazek@itc.it
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include <QRect> #include <QRect>
#include <QPolygon> #include <QPointF>
#include <QPolygonF>
#include <QDir> #include <QDir>
#include <QPicture> #include <QPicture>
#include <QSvgRenderer> #include <QSvgRenderer>
Expand All @@ -34,6 +34,13 @@ email : blazek@itc.it
#include "qgsmarkercatalogue.h" #include "qgsmarkercatalogue.h"
#include "qgslogger.h" #include "qgslogger.h"


// MSVC compiler doesn't have defined M_PI in math.h
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

#define DEG2RAD(x) ((x)*M_PI/180)

//#define IMAGEDEBUG //#define IMAGEDEBUG


QgsMarkerCatalogue *QgsMarkerCatalogue::mMarkerCatalogue = 0; QgsMarkerCatalogue *QgsMarkerCatalogue::mMarkerCatalogue = 0;
Expand All @@ -46,10 +53,13 @@ QgsMarkerCatalogue::QgsMarkerCatalogue()
mList.append( "hard:circle" ); mList.append( "hard:circle" );
mList.append( "hard:rectangle" ); mList.append( "hard:rectangle" );
mList.append( "hard:diamond" ); mList.append( "hard:diamond" );
mList.append( "hard:pentagon" );
mList.append( "hard:cross" ); mList.append( "hard:cross" );
mList.append( "hard:cross2" ); mList.append( "hard:cross2" );
mList.append( "hard:triangle" ); mList.append( "hard:triangle" );
mList.append( "hard:equilateral_triangle" );
mList.append( "hard:star" ); mList.append( "hard:star" );
mList.append( "hard:regular_star" );
mList.append( "hard:arrow" ); mList.append( "hard:arrow" );


// SVG // SVG
Expand Down Expand Up @@ -109,16 +119,20 @@ QImage QgsMarkerCatalogue::imageMarker( QString fullName, double size, QPen pen,
} }


QImage myImage; QImage myImage;
int imageSize;
if ( fullName.left( 5 ) == "hard:" ) if ( fullName.left( 5 ) == "hard:" )
{ {
myImage = QImage( size + 1, size + 1, QImage::Format_ARGB32_Premultiplied ); int pw = ( ( pen.width()==0 ? 1 : pen.width() ) + 1 ) / 2 * 2; // make even (round up); handle cosmetic pen
imageSize = ( (int) size + pw ) / 2 * 2 + 1; // make image width, height odd; account for pen width
myImage = QImage( imageSize, imageSize, QImage::Format_ARGB32_Premultiplied );
} }
else else
{ {
// TODO Change this logic so width is size and height is same // TODO Change this logic so width is size and height is same
// proportion of scale factor as in oritignal SVG TS XXX // proportion of scale factor as in oritignal SVG TS XXX
//QPixmap myPixmap = QPixmap(width,height); //QPixmap myPixmap = QPixmap(width,height);
myImage = QImage( size, size, QImage::Format_ARGB32_Premultiplied ); imageSize = ( (int) size ) / 2 * 2 + 1; // make image width, height odd
myImage = QImage( imageSize, imageSize, QImage::Format_ARGB32_Premultiplied );
} }


// starting with transparent QImage // starting with transparent QImage
Expand All @@ -134,7 +148,7 @@ QImage QgsMarkerCatalogue::imageMarker( QString fullName, double size, QPen pen,


if ( fullName.left( 5 ) == "hard:" ) if ( fullName.left( 5 ) == "hard:" )
{ {
hardMarker( &myPainter, fullName.mid( 5 ), size, pen, brush, qtBug ); hardMarker( &myPainter, imageSize, fullName.mid( 5 ), size, pen, brush, qtBug );
#ifdef IMAGEDEBUG #ifdef IMAGEDEBUG
QgsDebugMsg( "*** Saving hard marker to hardMarker.png ***" ); QgsDebugMsg( "*** Saving hard marker to hardMarker.png ***" );
#ifdef QGISDEBUG #ifdef QGISDEBUG
Expand Down Expand Up @@ -181,7 +195,7 @@ QPicture QgsMarkerCatalogue::pictureMarker( QString fullName, double size, QPen


if ( fullName.left( 5 ) == "hard:" ) if ( fullName.left( 5 ) == "hard:" )
{ {
hardMarker( &myPainter, fullName.mid( 5 ), size, pen, brush, qtBug ); hardMarker( &myPainter, (int) size, fullName.mid( 5 ), size, pen, brush, qtBug );
return myPicture; return myPicture;
} }
else if ( fullName.left( 4 ) == "svg:" ) else if ( fullName.left( 4 ) == "svg:" )
Expand All @@ -199,111 +213,137 @@ void QgsMarkerCatalogue::svgMarker( QPainter * thepPainter, QString fileName, do
mySVG.render( thepPainter ); mySVG.render( thepPainter );
} }


void QgsMarkerCatalogue::hardMarker( QPainter * thepPainter, QString name, double s, QPen pen, QBrush brush, bool qtBug ) void QgsMarkerCatalogue::hardMarker( QPainter * thepPainter, int imageSize, QString name, double s, QPen pen, QBrush brush, bool qtBug )
{ {
// Size of polygon symbols is calculated so that the boundingbox is circumscribed // Size of polygon symbols is calculated so that the boundingbox is circumscribed
// around a circle with diameter mPointSize // around a circle with diameter mPointSize


double half = s / 2; // number of points from center #if 0
s = s - pen.widthF(); // to make the overall size of the symbol at the specified size
#else
// the size of the base symbol is at the specified size; the outline is applied additionally
#endif

// Circle radius, is used for other figures also, when compensating for line
// width is necessary.
double r = s / 2; // get half the size of the figure to be rendered (the radius)


QgsDebugMsg( QString( "Hard marker size %1" ).arg( s ) ); QgsDebugMsg( QString( "Hard marker size %1" ).arg( s ) );


// Find out center coordinates. // Find out center coordinates of the QImage to draw on.
double x_c = s / 2; double x_c = (double) ( imageSize / 2 ) + 0.5; // add 1/2 pixel for proper rounding when the figure's coordinates are added
double y_c = x_c; double y_c = x_c; // is square image


// Also width must be odd otherwise there are discrepancies visible in canvas!
double lw = pen.widthF();//(int)(2*floor((double)pen.widthF()/2)+1); // -> lw > 0
pen.setWidthF( lw );
thepPainter->setPen( pen ); thepPainter->setPen( pen );
thepPainter->setBrush( brush ); thepPainter->setBrush( brush );
QRect box;


// Circle radius, is used for other figures also, when compensating for line
// width is necessary.

int r = ( s - 2 * lw ) / 2 - 1;
QgsDebugMsg( QString( "Hard marker radius %1" ).arg( r ) ); QgsDebugMsg( QString( "Hard marker radius %1" ).arg( r ) );


// If radius is 0, draw a circle, so it wont disappear. // If radius is 0, draw a circle, so it wont disappear.
if ( name == "circle" || r < 1 ) if ( name == "circle" || r < 1 )
{ {
// "A stroked ellipse has a size of rectangle.size() plus the pen width." // "A stroked ellipse has a size of rectangle.size() plus the pen width."
// (from Qt doc) // (from Qt doc)
// It doesn't seem like it is centered, however. Fudge...
// Is this a Qt bug or feature?
x_c -= (( lw + 5 ) / 4 );
y_c -= (( lw + 5 ) / 4 );


thepPainter->drawEllipse( QRectF( x_c - r, y_c - r, x_c + r, y_c + r ) ); thepPainter->drawEllipse( QRectF( x_c - r, y_c - r, s, s ) ); // x,y,w,h
} }
else if ( name == "rectangle" ) else if ( name == "rectangle" )
{ {
// Same fudge as for circle... thepPainter->drawRect( QRectF( x_c - r, y_c - r, s, s ) ); // x,y,w,h
x_c -= (( lw + 5 ) / 4 );
y_c -= (( lw + 5 ) / 4 );

thepPainter->drawRect( x_c - r, y_c - r, x_c + r, y_c + r );
} }
else if ( name == "diamond" ) else if ( name == "diamond" )
{ {
QPolygon pa( 4 ); QPolygonF pa;
pa.setPoint( 0, x_c - r, y_c ); pa << QPointF( x_c - r, y_c )
pa.setPoint( 1, x_c, y_c + r ); << QPointF( x_c, y_c + r )
pa.setPoint( 2, x_c + r, y_c ); << QPointF( x_c + r, y_c )
pa.setPoint( 3, x_c, y_c - r ); << QPointF( x_c, y_c - r );
thepPainter->drawPolygon( pa );
}
else if ( name == "pentagon" )
{
QPolygonF pa;
pa << QPointF( x_c + ( r * sin( DEG2RAD( 288.0 ) ) ), y_c - ( r * cos( DEG2RAD( 288.0 ) ) ) )
<< QPointF( x_c + ( r * sin( DEG2RAD( 216.0 ) ) ), y_c - ( r * cos( DEG2RAD( 216.0 ) ) ) )
<< QPointF( x_c + ( r * sin( DEG2RAD( 144.0 ) ) ), y_c - ( r * cos( DEG2RAD( 144.0 ) ) ) )
<< QPointF( x_c + ( r * sin( DEG2RAD( 72.0 ) ) ), y_c - ( r * cos( DEG2RAD( 72.0 ) ) ) )
<< QPointF( x_c, y_c - r );
thepPainter->drawPolygon( pa ); thepPainter->drawPolygon( pa );
} }
else if ( name == "cross" ) else if ( name == "cross" )
{ {
thepPainter->drawLine( x_c - half, y_c, x_c + half, y_c ); // horizontal thepPainter->drawLine( QPointF( x_c - r, y_c ), QPointF( x_c + r, y_c ) ); // horizontal
thepPainter->drawLine( x_c, y_c - half, x_c, y_c + half ); // vertical thepPainter->drawLine( QPointF( x_c, y_c - r ), QPointF( x_c, y_c + r ) ); // vertical
} }
else if ( name == "cross2" ) else if ( name == "cross2" )
{ {
thepPainter->drawLine( x_c - half, y_c - half, x_c + half, y_c + half ); thepPainter->drawLine( QPointF( x_c - r, y_c - r ), QPointF( x_c + r, y_c + r ) );
thepPainter->drawLine( x_c - half, y_c + half, x_c + half, y_c - half ); thepPainter->drawLine( QPointF( x_c - r, y_c + r ), QPointF( x_c + r, y_c - r ) );
} }
else if ( name == "triangle" ) else if ( name == "triangle" )
{ {
QPolygon pa( 3 ); QPolygonF pa;

pa << QPointF( x_c - r, y_c + r )
pa.setPoint( 0, x_c - r, y_c + r ); << QPointF( x_c + r, y_c + r )
pa.setPoint( 1, x_c + r, y_c + r ); << QPointF( x_c, y_c - r );
pa.setPoint( 2, x_c, y_c - r ); thepPainter->drawPolygon( pa );
}
else if ( name == "equilateral_triangle" )
{
QPolygonF pa;
pa << QPointF( x_c + ( r * sin( DEG2RAD( 240.0 ) ) ), y_c - ( r * cos( DEG2RAD( 240.0 ) ) ) )
<< QPointF( x_c + ( r * sin( DEG2RAD( 120.0 ) ) ), y_c - ( r * cos( DEG2RAD( 120.0 ) ) ) )
<< QPointF( x_c, y_c - r ); // 0
thepPainter->drawPolygon( pa ); thepPainter->drawPolygon( pa );
} }
else if ( name == "star" ) else if ( name == "star" )
{ {
int oneSixth = 2 * r / 6; double oneSixth = 2 * r / 6;


QPolygon pa( 10 ); QPolygonF pa;
pa.setPoint( 0, x_c, y_c - half ); pa << QPointF( x_c, y_c - r )
pa.setPoint( 1, x_c - oneSixth, y_c - oneSixth ); << QPointF( x_c - oneSixth, y_c - oneSixth )
pa.setPoint( 2, x_c - half, y_c - oneSixth ); << QPointF( x_c - r, y_c - oneSixth )
pa.setPoint( 3, x_c - oneSixth, y_c ); << QPointF( x_c - oneSixth, y_c )
pa.setPoint( 4, x_c - half, y_c + half ); << QPointF( x_c - r, y_c + r )
pa.setPoint( 5, x_c, y_c + oneSixth ); << QPointF( x_c, y_c + oneSixth )
pa.setPoint( 6, x_c + half, y_c + half ); << QPointF( x_c + r, y_c + r )
pa.setPoint( 7, x_c + oneSixth, y_c ); << QPointF( x_c + oneSixth, y_c )
pa.setPoint( 8, x_c + half, y_c - oneSixth ); << QPointF( x_c + r, y_c - oneSixth )
pa.setPoint( 9, x_c + oneSixth, y_c - oneSixth ); << QPointF( x_c + oneSixth, y_c - oneSixth );
thepPainter->drawPolygon( pa );
}
else if ( name == "regular_star" )
{
// control the 'fatness' of the star: cos(72)/cos(36) gives the classic star shape
double inner_r = r * cos( DEG2RAD( 72.0 ) ) / cos( DEG2RAD( 36.0 ) );

QPolygonF pa;
pa << QPointF( x_c + ( inner_r * sin( DEG2RAD( 324.0 ) ) ), y_c - ( inner_r * cos( DEG2RAD( 324.0 ) ) ) ) // 324
<< QPointF( x_c + ( r * sin( DEG2RAD( 288.0 ) ) ), y_c - ( r * cos( DEG2RAD( 288 ) ) ) ) // 288
<< QPointF( x_c + ( inner_r * sin( DEG2RAD( 252.0 ) ) ), y_c - ( inner_r * cos( DEG2RAD( 252.0 ) ) ) ) // 252
<< QPointF( x_c + ( r * sin( DEG2RAD( 216.0 ) ) ), y_c - ( r * cos( DEG2RAD( 216.0 ) ) ) ) // 216
<< QPointF( x_c, y_c + ( inner_r ) ) // 180
<< QPointF( x_c + ( r * sin( DEG2RAD( 144.0 ) ) ), y_c - ( r * cos( DEG2RAD( 144.0 ) ) ) ) // 144
<< QPointF( x_c + ( inner_r * sin( DEG2RAD( 108.0 ) ) ), y_c - ( inner_r * cos( DEG2RAD( 108.0 ) ) ) ) // 108
<< QPointF( x_c + ( r * sin( DEG2RAD( 72.0 ) ) ), y_c - ( r * cos( DEG2RAD( 72.0 ) ) ) ) // 72
<< QPointF( x_c + ( inner_r * sin( DEG2RAD( 36.0 ) ) ), y_c - ( inner_r * cos( DEG2RAD( 36.0 ) ) ) ) // 36
<< QPointF( x_c, y_c - r ); // 0
thepPainter->drawPolygon( pa ); thepPainter->drawPolygon( pa );
} }

else if ( name == "arrow" ) else if ( name == "arrow" )
{ {
int oneEight = r / 4; double oneEight = r / 4;
int quarter = r / 2; double quarter = r / 2;


QPolygon pa( 7 ); QPolygonF pa;
pa.setPoint( 0, x_c, y_c - r ); pa << QPointF( x_c, y_c - r )
pa.setPoint( 1, x_c + quarter, y_c - quarter ); << QPointF( x_c + quarter, y_c - quarter )
pa.setPoint( 2, x_c + oneEight, y_c - quarter ); << QPointF( x_c + oneEight, y_c - quarter )
pa.setPoint( 3, x_c + oneEight, y_c + r ); << QPointF( x_c + oneEight, y_c + r )
pa.setPoint( 4, x_c - oneEight, y_c + r ); << QPointF( x_c - oneEight, y_c + r )
pa.setPoint( 5, x_c - oneEight, y_c - quarter ); << QPointF( x_c - oneEight, y_c - quarter )
pa.setPoint( 6, x_c - quarter, y_c - quarter ); << QPointF( x_c - quarter, y_c - quarter );
thepPainter->drawPolygon( pa ); thepPainter->drawPolygon( pa );
} }
thepPainter->end(); thepPainter->end();
Expand Down
2 changes: 1 addition & 1 deletion src/core/symbology/qgsmarkercatalogue.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class CORE_EXPORT QgsMarkerCatalogue
QStringList mList; QStringList mList;


/** Hard coded */ /** Hard coded */
void hardMarker( QPainter * thepPainter, QString name, double size, QPen pen, QBrush brush, bool qtBug = true ); void hardMarker( QPainter * thepPainter, int imageSize, QString name, double size, QPen pen, QBrush brush, bool qtBug = true );


}; };


Expand Down

0 comments on commit 87816af

Please sign in to comment.