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