Skip to content

Commit 19bc6b9

Browse files
author
homann
committed
Applying patch from smizuno to polish hard marker position accuracy. Many thanks! Fixes #1262
git-svn-id: http://svn.osgeo.org/qgis/trunk@9636 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent f026d5a commit 19bc6b9

File tree

2 files changed

+109
-69
lines changed

2 files changed

+109
-69
lines changed

src/core/symbology/qgsmarkercatalogue.cpp

Lines changed: 108 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ email : blazek@itc.it
1414
* *
1515
***************************************************************************/
1616
#include <cmath>
17-
#include <iostream>
1817
#include <assert.h>
1918

2019
#include <QPen>
@@ -24,7 +23,8 @@ email : blazek@itc.it
2423
#include <QString>
2524
#include <QStringList>
2625
#include <QRect>
27-
#include <QPolygon>
26+
#include <QPointF>
27+
#include <QPolygonF>
2828
#include <QDir>
2929
#include <QPicture>
3030
#include <QSvgRenderer>
@@ -34,6 +34,13 @@ email : blazek@itc.it
3434
#include "qgsmarkercatalogue.h"
3535
#include "qgslogger.h"
3636

37+
// MSVC compiler doesn't have defined M_PI in math.h
38+
#ifndef M_PI
39+
#define M_PI 3.14159265358979323846
40+
#endif
41+
42+
#define DEG2RAD(x) ((x)*M_PI/180)
43+
3744
//#define IMAGEDEBUG
3845

3946
QgsMarkerCatalogue *QgsMarkerCatalogue::mMarkerCatalogue = 0;
@@ -46,10 +53,13 @@ QgsMarkerCatalogue::QgsMarkerCatalogue()
4653
mList.append( "hard:circle" );
4754
mList.append( "hard:rectangle" );
4855
mList.append( "hard:diamond" );
56+
mList.append( "hard:pentagon" );
4957
mList.append( "hard:cross" );
5058
mList.append( "hard:cross2" );
5159
mList.append( "hard:triangle" );
60+
mList.append( "hard:equilateral_triangle" );
5261
mList.append( "hard:star" );
62+
mList.append( "hard:regular_star" );
5363
mList.append( "hard:arrow" );
5464

5565
// SVG
@@ -109,16 +119,20 @@ QImage QgsMarkerCatalogue::imageMarker( QString fullName, double size, QPen pen,
109119
}
110120

111121
QImage myImage;
122+
int imageSize;
112123
if ( fullName.left( 5 ) == "hard:" )
113124
{
114-
myImage = QImage( size + 1, size + 1, QImage::Format_ARGB32_Premultiplied );
125+
int pw = ( ( pen.width()==0 ? 1 : pen.width() ) + 1 ) / 2 * 2; // make even (round up); handle cosmetic pen
126+
imageSize = ( (int) size + pw ) / 2 * 2 + 1; // make image width, height odd; account for pen width
127+
myImage = QImage( imageSize, imageSize, QImage::Format_ARGB32_Premultiplied );
115128
}
116129
else
117130
{
118131
// TODO Change this logic so width is size and height is same
119132
// proportion of scale factor as in oritignal SVG TS XXX
120133
//QPixmap myPixmap = QPixmap(width,height);
121-
myImage = QImage( size, size, QImage::Format_ARGB32_Premultiplied );
134+
imageSize = ( (int) size ) / 2 * 2 + 1; // make image width, height odd
135+
myImage = QImage( imageSize, imageSize, QImage::Format_ARGB32_Premultiplied );
122136
}
123137

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

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

182196
if ( fullName.left( 5 ) == "hard:" )
183197
{
184-
hardMarker( &myPainter, fullName.mid( 5 ), size, pen, brush, qtBug );
198+
hardMarker( &myPainter, (int) size, fullName.mid( 5 ), size, pen, brush, qtBug );
185199
return myPicture;
186200
}
187201
else if ( fullName.left( 4 ) == "svg:" )
@@ -199,111 +213,137 @@ void QgsMarkerCatalogue::svgMarker( QPainter * thepPainter, QString fileName, do
199213
mySVG.render( thepPainter );
200214
}
201215

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

207-
double half = s / 2; // number of points from center
221+
#if 0
222+
s = s - pen.widthF(); // to make the overall size of the symbol at the specified size
223+
#else
224+
// the size of the base symbol is at the specified size; the outline is applied additionally
225+
#endif
226+
227+
// Circle radius, is used for other figures also, when compensating for line
228+
// width is necessary.
229+
double r = s / 2; // get half the size of the figure to be rendered (the radius)
208230

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

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

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

222-
// Circle radius, is used for other figures also, when compensating for line
223-
// width is necessary.
224-
225-
int r = ( s - 2 * lw ) / 2 - 1;
226240
QgsDebugMsg( QString( "Hard marker radius %1" ).arg( r ) );
227241

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

238-
thepPainter->drawEllipse( QRectF( x_c - r, y_c - r, x_c + r, y_c + r ) );
248+
thepPainter->drawEllipse( QRectF( x_c - r, y_c - r, s, s ) ); // x,y,w,h
239249
}
240250
else if ( name == "rectangle" )
241251
{
242-
// Same fudge as for circle...
243-
x_c -= (( lw + 5 ) / 4 );
244-
y_c -= (( lw + 5 ) / 4 );
245-
246-
thepPainter->drawRect( x_c - r, y_c - r, x_c + r, y_c + r );
252+
thepPainter->drawRect( QRectF( x_c - r, y_c - r, s, s ) ); // x,y,w,h
247253
}
248254
else if ( name == "diamond" )
249255
{
250-
QPolygon pa( 4 );
251-
pa.setPoint( 0, x_c - r, y_c );
252-
pa.setPoint( 1, x_c, y_c + r );
253-
pa.setPoint( 2, x_c + r, y_c );
254-
pa.setPoint( 3, x_c, y_c - r );
256+
QPolygonF pa;
257+
pa << QPointF( x_c - r, y_c )
258+
<< QPointF( x_c, y_c + r )
259+
<< QPointF( x_c + r, y_c )
260+
<< QPointF( x_c, y_c - r );
261+
thepPainter->drawPolygon( pa );
262+
}
263+
else if ( name == "pentagon" )
264+
{
265+
QPolygonF pa;
266+
pa << QPointF( x_c + ( r * sin( DEG2RAD( 288.0 ) ) ), y_c - ( r * cos( DEG2RAD( 288.0 ) ) ) )
267+
<< QPointF( x_c + ( r * sin( DEG2RAD( 216.0 ) ) ), y_c - ( r * cos( DEG2RAD( 216.0 ) ) ) )
268+
<< QPointF( x_c + ( r * sin( DEG2RAD( 144.0 ) ) ), y_c - ( r * cos( DEG2RAD( 144.0 ) ) ) )
269+
<< QPointF( x_c + ( r * sin( DEG2RAD( 72.0 ) ) ), y_c - ( r * cos( DEG2RAD( 72.0 ) ) ) )
270+
<< QPointF( x_c, y_c - r );
255271
thepPainter->drawPolygon( pa );
256272
}
257273
else if ( name == "cross" )
258274
{
259-
thepPainter->drawLine( x_c - half, y_c, x_c + half, y_c ); // horizontal
260-
thepPainter->drawLine( x_c, y_c - half, x_c, y_c + half ); // vertical
275+
thepPainter->drawLine( QPointF( x_c - r, y_c ), QPointF( x_c + r, y_c ) ); // horizontal
276+
thepPainter->drawLine( QPointF( x_c, y_c - r ), QPointF( x_c, y_c + r ) ); // vertical
261277
}
262278
else if ( name == "cross2" )
263279
{
264-
thepPainter->drawLine( x_c - half, y_c - half, x_c + half, y_c + half );
265-
thepPainter->drawLine( x_c - half, y_c + half, x_c + half, y_c - half );
280+
thepPainter->drawLine( QPointF( x_c - r, y_c - r ), QPointF( x_c + r, y_c + r ) );
281+
thepPainter->drawLine( QPointF( x_c - r, y_c + r ), QPointF( x_c + r, y_c - r ) );
266282
}
267283
else if ( name == "triangle" )
268284
{
269-
QPolygon pa( 3 );
270-
271-
pa.setPoint( 0, x_c - r, y_c + r );
272-
pa.setPoint( 1, x_c + r, y_c + r );
273-
pa.setPoint( 2, x_c, y_c - r );
285+
QPolygonF pa;
286+
pa << QPointF( x_c - r, y_c + r )
287+
<< QPointF( x_c + r, y_c + r )
288+
<< QPointF( x_c, y_c - r );
289+
thepPainter->drawPolygon( pa );
290+
}
291+
else if ( name == "equilateral_triangle" )
292+
{
293+
QPolygonF pa;
294+
pa << QPointF( x_c + ( r * sin( DEG2RAD( 240.0 ) ) ), y_c - ( r * cos( DEG2RAD( 240.0 ) ) ) )
295+
<< QPointF( x_c + ( r * sin( DEG2RAD( 120.0 ) ) ), y_c - ( r * cos( DEG2RAD( 120.0 ) ) ) )
296+
<< QPointF( x_c, y_c - r ); // 0
274297
thepPainter->drawPolygon( pa );
275298
}
276299
else if ( name == "star" )
277300
{
278-
int oneSixth = 2 * r / 6;
279-
280-
QPolygon pa( 10 );
281-
pa.setPoint( 0, x_c, y_c - half );
282-
pa.setPoint( 1, x_c - oneSixth, y_c - oneSixth );
283-
pa.setPoint( 2, x_c - half, y_c - oneSixth );
284-
pa.setPoint( 3, x_c - oneSixth, y_c );
285-
pa.setPoint( 4, x_c - half, y_c + half );
286-
pa.setPoint( 5, x_c, y_c + oneSixth );
287-
pa.setPoint( 6, x_c + half, y_c + half );
288-
pa.setPoint( 7, x_c + oneSixth, y_c );
289-
pa.setPoint( 8, x_c + half, y_c - oneSixth );
290-
pa.setPoint( 9, x_c + oneSixth, y_c - oneSixth );
301+
double oneSixth = 2 * r / 6;
302+
303+
QPolygonF pa;
304+
pa << QPointF( x_c, y_c - r )
305+
<< QPointF( x_c - oneSixth, y_c - oneSixth )
306+
<< QPointF( x_c - r, y_c - oneSixth )
307+
<< QPointF( x_c - oneSixth, y_c )
308+
<< QPointF( x_c - r, y_c + r )
309+
<< QPointF( x_c, y_c + oneSixth )
310+
<< QPointF( x_c + r, y_c + r )
311+
<< QPointF( x_c + oneSixth, y_c )
312+
<< QPointF( x_c + r, y_c - oneSixth )
313+
<< QPointF( x_c + oneSixth, y_c - oneSixth );
314+
thepPainter->drawPolygon( pa );
315+
}
316+
else if ( name == "regular_star" )
317+
{
318+
// control the 'fatness' of the star: cos(72)/cos(36) gives the classic star shape
319+
double inner_r = r * cos( DEG2RAD( 72.0 ) ) / cos( DEG2RAD( 36.0 ) );
320+
321+
QPolygonF pa;
322+
pa << QPointF( x_c + ( inner_r * sin( DEG2RAD( 324.0 ) ) ), y_c - ( inner_r * cos( DEG2RAD( 324.0 ) ) ) ) // 324
323+
<< QPointF( x_c + ( r * sin( DEG2RAD( 288.0 ) ) ), y_c - ( r * cos( DEG2RAD( 288 ) ) ) ) // 288
324+
<< QPointF( x_c + ( inner_r * sin( DEG2RAD( 252.0 ) ) ), y_c - ( inner_r * cos( DEG2RAD( 252.0 ) ) ) ) // 252
325+
<< QPointF( x_c + ( r * sin( DEG2RAD( 216.0 ) ) ), y_c - ( r * cos( DEG2RAD( 216.0 ) ) ) ) // 216
326+
<< QPointF( x_c, y_c + ( inner_r ) ) // 180
327+
<< QPointF( x_c + ( r * sin( DEG2RAD( 144.0 ) ) ), y_c - ( r * cos( DEG2RAD( 144.0 ) ) ) ) // 144
328+
<< QPointF( x_c + ( inner_r * sin( DEG2RAD( 108.0 ) ) ), y_c - ( inner_r * cos( DEG2RAD( 108.0 ) ) ) ) // 108
329+
<< QPointF( x_c + ( r * sin( DEG2RAD( 72.0 ) ) ), y_c - ( r * cos( DEG2RAD( 72.0 ) ) ) ) // 72
330+
<< QPointF( x_c + ( inner_r * sin( DEG2RAD( 36.0 ) ) ), y_c - ( inner_r * cos( DEG2RAD( 36.0 ) ) ) ) // 36
331+
<< QPointF( x_c, y_c - r ); // 0
291332
thepPainter->drawPolygon( pa );
292333
}
293-
294334
else if ( name == "arrow" )
295335
{
296-
int oneEight = r / 4;
297-
int quarter = r / 2;
298-
299-
QPolygon pa( 7 );
300-
pa.setPoint( 0, x_c, y_c - r );
301-
pa.setPoint( 1, x_c + quarter, y_c - quarter );
302-
pa.setPoint( 2, x_c + oneEight, y_c - quarter );
303-
pa.setPoint( 3, x_c + oneEight, y_c + r );
304-
pa.setPoint( 4, x_c - oneEight, y_c + r );
305-
pa.setPoint( 5, x_c - oneEight, y_c - quarter );
306-
pa.setPoint( 6, x_c - quarter, y_c - quarter );
336+
double oneEight = r / 4;
337+
double quarter = r / 2;
338+
339+
QPolygonF pa;
340+
pa << QPointF( x_c, y_c - r )
341+
<< QPointF( x_c + quarter, y_c - quarter )
342+
<< QPointF( x_c + oneEight, y_c - quarter )
343+
<< QPointF( x_c + oneEight, y_c + r )
344+
<< QPointF( x_c - oneEight, y_c + r )
345+
<< QPointF( x_c - oneEight, y_c - quarter )
346+
<< QPointF( x_c - quarter, y_c - quarter );
307347
thepPainter->drawPolygon( pa );
308348
}
309349
thepPainter->end();

src/core/symbology/qgsmarkercatalogue.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class CORE_EXPORT QgsMarkerCatalogue
6464
QStringList mList;
6565

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

6969
};
7070

0 commit comments

Comments
 (0)