1 /****************************************************************************
2 **
3 ** This file is part of the LibreCAD project, a 2D CAD program
4 **
5 ** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
6 ** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
7 **
8 **
9 ** This file may be distributed and/or modified under the terms of the
10 ** GNU General Public License version 2 as published by the Free Software
11 ** Foundation and appearing in the file gpl-2.0.txt included in the
12 ** packaging of this file.
13 **
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ** GNU General Public License for more details.
18 **
19 ** You should have received a copy of the GNU General Public License
20 ** along with this program; if not, write to the Free Software
21 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 **
23 ** This copyright notice MUST APPEAR in all copies of the script!
24 **
25 **********************************************************************/
26 
27 #include<cmath>
28 #include "rs_painterqt.h"
29 #include "rs_math.h"
30 #include "rs_debug.h"
31 
32 namespace {
33 /**
34  * Wrapper for Qt
35  * convert RS2::LineType to Qt::PenStyle
36  */
rsToQtLineType(RS2::LineType t)37 Qt::PenStyle rsToQtLineType(RS2::LineType t) {
38 	switch (t) {
39 	case RS2::NoPen:
40 		return Qt::NoPen;
41 	case RS2::SolidLine:
42 		return Qt::SolidLine;
43 	case RS2::DotLine:
44 	case RS2::DotLineTiny:
45 	case RS2::DotLine2:
46 	case RS2::DotLineX2:
47 		return Qt::DotLine;
48 	case RS2::DashLine:
49 	case RS2::DashLineTiny:
50 	case RS2::DashLine2:
51 	case RS2::DashLineX2:
52 		return Qt::DashLine;
53 	case RS2::DashDotLine:
54 	case RS2::DashDotLineTiny:
55 	case RS2::DashDotLine2:
56 	case RS2::DashDotLineX2:
57 		return Qt::DashDotLine;
58 	case RS2::DivideLine:
59 	case RS2::DivideLineTiny:
60 	case RS2::DivideLine2:
61 	case RS2::DivideLineX2:
62 		return Qt::DashDotDotLine;
63 	case RS2::CenterLine:
64 	case RS2::CenterLineTiny:
65 	case RS2::CenterLine2:
66 	case RS2::CenterLineX2:
67 		return Qt::DashDotLine;
68 	case RS2::BorderLine:
69 	case RS2::BorderLineTiny:
70 	case RS2::BorderLine2:
71 	case RS2::BorderLineX2:
72 		return Qt::DashDotLine;
73 	case RS2::LineByLayer:
74 	case RS2::LineByBlock:
75 	default:
76 		return Qt::SolidLine;
77 	}
78 	return Qt::SolidLine;
79 }
80 }
81 
82 /**
83  * Constructor.
84  */
85 // RVT_PORT changed from RS_PainterQt::RS_PainterQt( const QPaintDevice* pd)
RS_PainterQt(QPaintDevice * pd)86 RS_PainterQt::RS_PainterQt( QPaintDevice* pd)
87         : QPainter(pd), RS_Painter() {}
88 
moveTo(int x,int y)89 void RS_PainterQt::moveTo(int x, int y) {
90         //RVT_PORT changed from QPainter::moveTo(x,y);
91         rememberX=x;
92         rememberY=y;
93 }
94 
95 
lineTo(int x,int y)96 void RS_PainterQt::lineTo(int x, int y) {
97         // RVT_PORT changed from QPainter::lineTo(x, y);
98         QPainterPath path;
99         path.moveTo(rememberX,rememberY);
100         path.lineTo(x,y);
101         QPainter::drawPath(path);
102         rememberX=x;
103         rememberY=y;
104 }
105 
106 /**
107  * Draws a grid point at (x1, y1).
108  */
drawGridPoint(const RS_Vector & p)109 void RS_PainterQt::drawGridPoint(const RS_Vector& p) {
110     QPainter::drawPoint(toScreenX(p.x), toScreenY(p.y));
111 }
112 
113 
114 
115 /**
116  * Draws a point at (x1, y1).
117  */
drawPoint(const RS_Vector & p)118 void RS_PainterQt::drawPoint(const RS_Vector& p) {
119     QPainter::drawLine(toScreenX(p.x-1), toScreenY(p.y),
120                        toScreenX(p.x+1), toScreenY(p.y));
121     QPainter::drawLine(toScreenX(p.x), toScreenY(p.y-1),
122                        toScreenX(p.x), toScreenY(p.y+1));
123 }
124 
125 
126 
127 /**
128  * Draws a line from (x1, y1) to (x2, y2).
129  */
drawLine(const RS_Vector & p1,const RS_Vector & p2)130 void RS_PainterQt::drawLine(const RS_Vector& p1, const RS_Vector& p2)
131 {
132     QPainter::drawLine(toScreenX(p1.x), toScreenY(p1.y),
133                        toScreenX(p2.x), toScreenY(p2.y));
134 }
135 
136 
137 
138 
139 
140 
141 /**
142  * Draws a rectangle with corners p1, p2.
143  */
144 /*void RS_PainterQt::drawRect(const RS_Vector& p1, const RS_Vector& p2) {
145         / *QPainter::drawRect(toScreenX(p1.x), toScreenY(p1.y),
146                                            abs(toScreenX(p2.x) - toScreenX(p1.x)),
147                                            abs(toScreenY(p2.y) - toScreenY(p1.y)));* /
148         QPainter::drawLine(toScreenX(p1.x), toScreenY(p1.y),
149                        toScreenX(p2.x), toScreenY(p1.y));
150     QPainter::drawLine(toScreenX(p2.x), toScreenY(p1.y),
151                        toScreenX(p2.x), toScreenY(p2.y));
152     QPainter::drawLine(toScreenX(p2.x), toScreenY(p2.y),
153                        toScreenX(p1.x), toScreenY(p2.y));
154     QPainter::drawLine(toScreenX(p1.x), toScreenY(p2.y),
155                        toScreenX(p1.x), toScreenY(p1.y));
156 }*/
157 
158 
159 /**
160  * Draws an arc which starts / ends exactly at the given coordinates.
161  *
162  * @param cx center in x
163  * @param cy center in y
164  * @param radius Radius
165  * @param a1 Angle 1 in rad
166  * @param a2 Angle 2 in rad
167  * @param x1 startpoint x
168  * @param y1 startpoint y
169  * @param x2 endpoint x
170  * @param y2 endpoint y
171  * @param reversed true: clockwise, false: counterclockwise
172  */
drawArc(const RS_Vector & cp,double radius,double a1,double a2,const RS_Vector & p1,const RS_Vector & p2,bool reversed)173 void RS_PainterQt::drawArc(const RS_Vector& cp, double radius,
174                            double a1, double a2,
175                            const RS_Vector& p1, const RS_Vector& p2,
176                            bool reversed) {
177     /*
178     QPainter::drawArc(cx-radius, cy-radius,
179                       2*radius, 2*radius,
180                       a1*16, (a2-a1)*16);
181     */
182 
183     if(radius<=0.5) {
184         drawGridPoint(cp);
185     } else {
186         int   cix;            // Next point on circle
187         int   ciy;            //
188         double aStep;         // Angle Step (rad)
189         double a;             // Current Angle (rad)
190         double linStep;       // linear step (pixels)
191 
192         if (drawingMode==RS2::ModePreview) {
193             linStep = 20.0;
194         } else {
195             linStep = 6.0;
196         }
197 
198         if (fabs(linStep/radius)<=1.0) {
199             aStep=asin(linStep/radius);
200         } else {
201             aStep=1.0;
202         }
203 
204         if (aStep<0.05) {
205             aStep = 0.05;
206         }
207 
208         if(!reversed) {
209             // Arc Counterclockwise:
210             if(a1>a2-1.0e-10) {
211                 a2+=2*M_PI;
212             }
213             //moveTo(toScreenX(p1.x), toScreenY(p1.y));
214             QPolygon pa;
215             int i=0;
216             pa.resize(i+1);
217             pa.setPoint(i++, toScreenX(p1.x), toScreenY(p1.y));
218             for(a=a1+aStep; a<=a2; a+=aStep) {
219                 cix = toScreenX(cp.x+cos(a)*radius);
220                 ciy = toScreenY(cp.y-sin(a)*radius);
221                 //lineTo(cix, ciy);
222                 pa.resize(i+1);
223                 pa.setPoint(i++, cix, ciy);
224             }
225             //lineTo(toScreenX(p2.x), toScreenY(p2.y));
226             pa.resize(i+1);
227             pa.setPoint(i++, toScreenX(p2.x), toScreenY(p2.y));
228             drawPolyline(pa);
229         } else {
230             // Arc Clockwise:
231             if(a1<a2+1.0e-10) {
232                 a2-=2*M_PI;
233             }
234             QPolygon pa;
235             int i=0;
236             pa.resize(i+1);
237             pa.setPoint(i++, toScreenX(p1.x), toScreenY(p1.y));
238             //moveTo(toScreenX(p1.x), toScreenY(p1.y));
239             for(a=a1-aStep; a>=a2; a-=aStep) {
240                 cix = toScreenX(cp.x+cos(a)*radius);
241                 ciy = toScreenY(cp.y-sin(a)*radius);
242                 //lineTo(cix, ciy);
243                 pa.resize(i+1);
244                 pa.setPoint(i++, cix, ciy);
245             }
246             //lineTo(toScreenX(p2.x), toScreenY(p2.y));
247             pa.resize(i+1);
248             pa.setPoint(i++, toScreenX(p2.x), toScreenY(p2.y));
249             drawPolyline(pa);
250         }
251     }
252 }
253 
254 
255 
256 /**
257  * Draws an arc.
258  *
259  * @param cx center in x
260  * @param cy center in y
261  * @param radius Radius
262  * @param a1 Angle 1 in rad
263  * @param a2 Angle 2 in rad
264  * @param reversed true: clockwise, false: counterclockwise
265  */
drawArc(const RS_Vector & cp,double radius,double a1,double a2,bool reversed)266 void RS_PainterQt::drawArc(const RS_Vector& cp, double radius,
267                            double a1, double a2,
268                            bool reversed) {
269     if(radius<=0.5) {
270         drawGridPoint(cp);
271     } else {
272 #ifdef __APPL1E__
273                 drawArcMac(cp, radius, a1, a2, reversed);
274 #else
275         QPolygon pa;
276         createArc(pa, cp, radius, a1, a2, reversed);
277         drawPolyline(pa);
278 #endif
279     }
280 }
281 
282 
283 /**
284  * Draws an arc on apple.
285  *
286  * @param cx center in x
287  * @param cy center in y
288  * @param radius Radius
289  * @param a1 Angle 1 in rad
290  * @param a2 Angle 2 in rad
291  * @param reversed true: clockwise, false: counterclockwise
292  */
drawArcMac(const RS_Vector & cp,double radius,double a1,double a2,bool reversed)293 void RS_PainterQt::drawArcMac(const RS_Vector& cp, double radius,
294                            double a1, double a2,
295                            bool reversed) {
296         RS_DEBUG->print("RS_PainterQt::drawArcMac");
297     if(radius<=0.5) {
298         drawGridPoint(cp);
299     } else {
300         //QPointArray pa;
301         //createArc(pa, cp, radius, a1, a2, reversed);
302 
303               double cix;            // Next point on circle
304               double ciy;            //
305               double aStep;         // Angle Step (rad)
306               double a;             // Current Angle (rad)
307                           double ox;
308                           double oy;
309 
310               if(2.0/radius<=1.0) {
311                   aStep=asin(2.0/radius);
312               } else {
313                   aStep=1.0;
314               }
315 
316               if (aStep<0.05) {
317                   aStep = 0.05;
318               }
319 
320               //QPointArray pa;
321               //int i=0;
322               //pa.resize(i+1);
323               //pa.setPoint(i++, toScreenX(cp.x+cos(a1)*radius),
324               //            toScreenY(cp.y-sin(a1)*radius));
325               //moveTo(toScreenX(cp.x+cos(a1)*radius),
326               //       toScreenY(cp.y-sin(a1)*radius));
327               ox = cp.x+cos(a1)*radius;
328               oy = cp.y-sin(a1)*radius;
329               if(!reversed) {
330                   // Arc Counterclockwise:
331                   if(a1>a2-1.0e-10) {
332                       a2+=2*M_PI;
333                   }
334                   for(a=a1+aStep; a<=a2; a+=aStep) {
335                       cix = cp.x+cos(a)*radius;
336                       ciy = cp.y-sin(a)*radius;
337                       //lineTo(cix, ciy);
338                                           drawLine(RS_Vector(ox, oy), RS_Vector(cix, ciy));
339                                           ox = cix;
340                                           oy = ciy;
341                       //pa.resize(i+1);
342                       //pa.setPoint(i++, cix, ciy);
343                   }
344               } else {
345                   // Arc Clockwise:
346                   if(a1<a2+1.0e-10) {
347                       a2-=2*M_PI;
348                   }
349                   for(a=a1-aStep; a>=a2; a-=aStep) {
350                       cix = cp.x+cos(a)*radius;
351                       ciy = cp.y-sin(a)*radius;
352                       drawLine(RS_Vector(ox, oy), RS_Vector(cix, ciy));
353                                           ox = cix;
354                                           oy = ciy;
355                                           //lineTo(cix, ciy);
356                       //pa.resize(i+1);
357                       //pa.setPoint(i++, cix, ciy);
358                   }
359               }
360               drawLine(RS_Vector(ox, oy),
361                                         RS_Vector(cp.x+cos(a2)*radius,
362                      cp.y-sin(a2)*radius));
363               //lineTo(toScreenX(cp.x+cos(a2)*radius),
364               //       toScreenY(cp.y-sin(a2)*radius));
365               //pa.resize(i+1);
366               //pa.setPoint(i++,
367               //            toScreenX(cp.x+cos(a2)*radius),
368               //            toScreenY(cp.y-sin(a2)*radius));
369         //drawPolyline(pa);
370     }
371 }
372 
373 
374 
375 /**
376  * Draws a circle.
377  * @param cp Center point
378  * @param radius Radius
379  */
drawCircle(const RS_Vector & cp,double radius)380 void RS_PainterQt::drawCircle(const RS_Vector& cp, double radius)
381 {
382     QPainter::drawEllipse(QPointF(cp.x, cp.y), radius, radius);
383 }
384 
385 
386 
387 /**
388  * Draws a rotated ellipse arc.
389  */
drawEllipse(const RS_Vector & cp,double radius1,double radius2,double angle,double a1,double a2,bool reversed)390 void RS_PainterQt::drawEllipse(const RS_Vector& cp,
391                                double radius1, double radius2,
392                                double angle,
393                                double a1, double a2,
394                                bool reversed) {
395     QPolygon pa;
396     createEllipse(pa, cp, radius1, radius2, angle, a1, a2, reversed);
397     drawPolyline(pa);
398 }
399 
400 
401 
402 /**
403  * Draws image.
404  */
drawImg(QImage & img,const RS_Vector & pos,double angle,const RS_Vector & factor)405 void RS_PainterQt::drawImg(QImage& img, const RS_Vector& pos,
406                            double angle, const RS_Vector& factor) {
407     save();
408 
409     // Render smooth only at close zooms
410     if (factor.x < 1 || factor.y < 1) {
411        RS_PainterQt::setRenderHint(SmoothPixmapTransform , true);
412     }
413     else {
414       RS_PainterQt::setRenderHint(SmoothPixmapTransform);
415     }
416 
417     QMatrix wm;
418     wm.translate(pos.x, pos.y);
419     wm.rotate(RS_Math::rad2deg(-angle));
420     wm.scale(factor.x, factor.y);
421     setWorldMatrix(wm);
422 
423 
424     drawImage(0,-img.height(), img);
425 
426     restore();
427 }
428 
429 
430 
drawTextH(int x1,int y1,int x2,int y2,const QString & text)431 void RS_PainterQt::drawTextH(int x1, int y1,
432                              int x2, int y2,
433                              const QString& text) {
434     drawText(x1, y1, x2, y2,
435              Qt::AlignRight|Qt::AlignVCenter,
436              text);
437 }
438 
439 
440 
drawTextV(int x1,int y1,int x2,int y2,const QString & text)441 void RS_PainterQt::drawTextV(int x1, int y1,
442                              int x2, int y2,
443                              const QString& text) {
444     save();
445     QMatrix wm = worldMatrix();
446     wm.rotate(-90.0);
447     setWorldMatrix(wm);
448     //rotate(-90.0);
449 
450     drawText(x1, y1, x2, y2,
451              Qt::AlignRight|Qt::AlignVCenter,
452              text);
453 
454     restore();
455 }
456 
fillRect(int x1,int y1,int w,int h,const RS_Color & col)457 void RS_PainterQt::fillRect(int x1, int y1, int w, int h,
458                             const RS_Color& col) {
459     QPainter::fillRect(x1, y1, w, h, col);
460 }
461 
462 
fillTriangle(const RS_Vector & p1,const RS_Vector & p2,const RS_Vector & p3)463 void RS_PainterQt::fillTriangle(const RS_Vector& p1,
464                                 const RS_Vector& p2,
465                                 const RS_Vector& p3) {
466 
467     QPolygon arr(3);
468     QBrush brushSaved=brush();
469     arr.putPoints(0, 3,
470                   toScreenX(p1.x),toScreenY(p1.y),
471                   toScreenX(p2.x),toScreenY(p2.y),
472                   toScreenX(p3.x),toScreenY(p3.y));
473     setBrush(RS_Color(pen().color()));
474     drawPolygon(arr);
475     setBrush(brushSaved);
476 }
477 
478 
erase()479 void RS_PainterQt::erase() {
480     QPainter::eraseRect(0,0,getWidth(),getHeight());
481 }
482 
483 
getWidth() const484 int RS_PainterQt::getWidth() const{
485     return device()->width();
486 }
487 
488 /** get Density per millimeter on screen/print device
489   *@return density per millimeter in pixel/mm
490   */
getDpmm() const491 double RS_PainterQt::getDpmm() const{
492     int mm(device()->widthMM());
493     if(mm==0) mm=400;
494     return double(device()->width())/mm;
495 }
496 
497 
getHeight() const498 int RS_PainterQt::getHeight() const{
499     return device()->height();
500 }
501 
brush() const502 const QBrush& RS_PainterQt::brush() const
503 {
504     return QPainter::brush();
505 }
506 
getPen() const507 RS_Pen RS_PainterQt::getPen() const{
508     return lpen;
509     //RS_Pen p(pen().color(),
510     //         RS2::qw(pen().width()),
511     //         RS2::qw(pen().style()));
512     //return QPainter::pen();
513     //return p;
514 }
515 
setPen(const RS_Pen & pen)516 void RS_PainterQt::setPen(const RS_Pen& pen) {
517     lpen = pen;
518     switch (drawingMode) {
519     case RS2::ModeBW:
520         lpen.setColor( RS_Color( Qt::black));
521         break;
522 
523     case RS2::ModeWB:
524         lpen.setColor( RS_Color( Qt::white));
525         break;
526 
527     default:
528         break;
529     }
530     QPen p(lpen.getColor(), RS_Math::round(lpen.getScreenWidth()),
531 		   rsToQtLineType(lpen.getLineType()));
532     p.setJoinStyle(Qt::RoundJoin);
533     p.setCapStyle(Qt::RoundCap);
534     QPainter::setPen(p);
535 }
536 
setPen(const RS_Color & color)537 void RS_PainterQt::setPen(const RS_Color& color) {
538     switch (drawingMode) {
539     case RS2::ModeBW:
540         lpen.setColor( RS_Color( Qt::black));
541         QPainter::setPen( RS_Color( Qt::black));
542         break;
543 
544     case RS2::ModeWB:
545         lpen.setColor( RS_Color( Qt::white));
546         QPainter::setPen( RS_Color( Qt::white));
547         break;
548 
549     default:
550         lpen.setColor( color);
551         QPainter::setPen( color);
552         break;
553     }
554 }
555 
setPen(int r,int g,int b)556 void RS_PainterQt::setPen(int r, int g, int b) {
557     switch (drawingMode) {
558     case RS2::ModeBW:
559         setPen( QColor( Qt::black));
560         break;
561 
562     case RS2::ModeWB:
563         setPen( QColor( Qt::white));
564         break;
565 
566     default:
567         setPen( QColor( r, g, b));
568         break;
569     }
570 }
571 
disablePen()572 void RS_PainterQt::disablePen() {
573     lpen = RS_Pen(RS2::FlagInvalid);
574     QPainter::setPen(Qt::NoPen);
575 }
576 
setBrush(const RS_Color & color)577 void RS_PainterQt::setBrush(const RS_Color& color) {
578     switch (drawingMode) {
579     case RS2::ModeBW:
580         QPainter::setBrush( QColor( Qt::black));
581         break;
582 
583     case RS2::ModeWB:
584         QPainter::setBrush( QColor( Qt::white));
585         break;
586 
587     default:
588         QPainter::setBrush( color);
589         break;
590     }
591 }
592 
setBrush(const QBrush & color)593 void RS_PainterQt::setBrush(const QBrush& color) {
594     QPainter::setBrush(color);
595 }
596 
drawPolygon(const QPolygon & a,Qt::FillRule rule)597 void RS_PainterQt::drawPolygon(const QPolygon& a, Qt::FillRule rule) {
598     QPainter::drawPolygon(a,rule);
599 }
600 
drawPath(const QPainterPath & path)601 void RS_PainterQt::drawPath ( const QPainterPath & path ) {
602     QPainter::drawPath(path);
603 }
604 
605 
setClipRect(int x,int y,int w,int h)606 void RS_PainterQt::setClipRect(int x, int y, int w, int h) {
607     QPainter::setClipRect(x, y, w, h);
608     setClipping(true);
609 }
610 
resetClipping()611 void RS_PainterQt::resetClipping() {
612     setClipping(false);
613 }
614 
fillRect(const QRectF & rectangle,const RS_Color & color)615 void RS_PainterQt::fillRect ( const QRectF & rectangle, const RS_Color & color ) {
616 
617         double x1=rectangle.left();
618         double x2=rectangle.right();
619         double y1=rectangle.top();
620         double y2=rectangle.bottom();
621 
622         QPainter::fillRect(toScreenX(x1),toScreenY(y1),toScreenX(x2)-toScreenX(x1),toScreenY(y2)-toScreenX(y1), color);
623 }
fillRect(const QRectF & rectangle,const QBrush & brush)624 void RS_PainterQt::fillRect ( const QRectF & rectangle, const QBrush & brush ) {
625         double x1=rectangle.left();
626         double x2=rectangle.right();
627         double y1=rectangle.top();
628         double y2=rectangle.bottom();
629         QPainter::fillRect(toScreenX(x1),toScreenY(y1),toScreenX(x2),toScreenY(y2), brush);
630 }
631