@@ -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
3946QgsMarkerCatalogue *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 ();
0 commit comments