3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // (C) 2010 Underground Software
8 // JLH = James L. Hammons <jlhamm@acm.org>
11 // --- ---------- -----------------------------------------------------------
12 // JLH 05/21/2010 Added this text. :-)
15 // BIG NOTE: THIS CLASS ASSUMES THAT THE PAINTER * IS VALID!!! BAD THINGS WILL
16 // HAPPEN IF IT IS NOT!!!
18 #include "paintintf.h"
23 PaintInterface::PaintInterface(QPainter * p): painter(p), drawingMode(RS2::ModeFull),
24 offset(Vector(0.0, 0.0))
29 * Sets the drawing mode.
31 void PaintInterface::setDrawingMode(RS2::DrawingMode m)
37 * @return Current drawing mode.
39 RS2::DrawingMode PaintInterface::getDrawingMode()
44 void PaintInterface::createArc(QPolygon & pa, const Vector& cp, double radius,
45 double a1, double a2, bool reversed)
49 RS_DEBUG->print(RS_Debug::D_WARNING, "PaintInterface::createArc: invalid radius: %f", radius);
53 int cix; // Next point on circle
55 double aStep; // Angle Step (rad)
56 double a; // Current Angle (rad)
58 if (fabs(2.0 / radius) <= 1.0)
59 aStep = asin(2.0 / radius);
67 // less than a pixel long lines:
68 //if (radius*aStep<1.0) {
75 pa.setPoint(i++, toScreenX(cp.x + cos(a1) * radius), toScreenY(cp.y - sin(a1) * radius));
76 //moveTo(toScreenX(cp.x+cos(a1)*radius),
77 // toScreenY(cp.y-sin(a1)*radius));
81 // Arc Counterclockwise:
82 if (a1 > a2 - 1.0e-10)
85 for(a=a1+aStep; a<=a2; a+=aStep)
87 cix = toScreenX(cp.x + cos(a) * radius);
88 ciy = toScreenY(cp.y - sin(a) * radius);
90 pa.setPoint(i++, cix, ciy);
96 if (a1 < a2 + 1.0e-10)
99 for(a=a1-aStep; a>=a2; a-=aStep)
101 cix = toScreenX(cp.x + cos(a) * radius);
102 ciy = toScreenY(cp.y - sin(a) * radius);
105 pa.setPoint(i++, cix, ciy);
110 pa.setPoint(i++, toScreenX(cp.x + cos(a2) * radius), toScreenY(cp.y - sin(a2) * radius));
114 void PaintInterface::drawRect(const Vector & p1, const Vector & p2)
116 drawLine(Vector(p1.x, p1.y), Vector(p2.x, p1.y));
117 drawLine(Vector(p2.x, p1.y), Vector(p2.x, p2.y));
118 drawLine(Vector(p2.x, p2.y), Vector(p1.x, p2.y));
119 drawLine(Vector(p1.x, p2.y), Vector(p1.x, p1.y));
122 void PaintInterface::drawHandle(const Vector & p, const RS_Color & c, int size)
127 fillRect((int)(p.x - size), (int)(p.y - size), 2 * size, 2 * size, c);
130 void PaintInterface::setPreviewMode()
132 drawingMode = RS2::ModeXOR;
137 bool PaintInterface::isPreviewMode()
139 return (drawingMode == RS2::ModeXOR);
142 void PaintInterface::setOffset(const Vector & o)
147 int PaintInterface::toScreenX(double x)
149 return RS_Math::round(offset.x + x);
152 int PaintInterface::toScreenY(double y)
154 return RS_Math::round(offset.y + y);
158 * Draws a grid point at (x1, y1).
160 void PaintInterface::drawGridPoint(const Vector & p)
162 painter->drawPoint(toScreenX(p.x), toScreenY(p.y));
166 * Draws a point at (x1, y1).
168 void PaintInterface::drawPoint(const Vector & p)
170 painter->drawLine(toScreenX(p.x - 1), toScreenY(p.y), toScreenX(p.x + 1), toScreenY(p.y));
171 painter->drawLine(toScreenX(p.x), toScreenY(p.y - 1), toScreenX(p.x), toScreenY(p.y + 1));
175 * Draws a line from (x1, y1) to (x2, y2).
177 void PaintInterface::drawLine(const Vector & p1, const Vector & p2)
180 int w2 = (int)getPen().getScreenWidth() / 2;
181 QPainter::drawLine(toScreenX(p1.x - w2), toScreenY(p1.y - w2),
182 toScreenX(p2.x - w2), toScreenY(p2.y - w2));
184 painter->drawLine(toScreenX(p1.x), toScreenY(p1.y), toScreenX(p2.x), toScreenY(p2.y));
189 * Draws a rectangle with corners p1, p2.
191 /*void PaintInterface::drawRect(const Vector& p1, const Vector& p2) {
192 / *QPainter::drawRect(toScreenX(p1.x), toScreenY(p1.y),
193 abs(toScreenX(p2.x) - toScreenX(p1.x)),
194 abs(toScreenY(p2.y) - toScreenY(p1.y)));* /
195 QPainter::drawLine(toScreenX(p1.x), toScreenY(p1.y),
196 toScreenX(p2.x), toScreenY(p1.y));
197 QPainter::drawLine(toScreenX(p2.x), toScreenY(p1.y),
198 toScreenX(p2.x), toScreenY(p2.y));
199 QPainter::drawLine(toScreenX(p2.x), toScreenY(p2.y),
200 toScreenX(p1.x), toScreenY(p2.y));
201 QPainter::drawLine(toScreenX(p1.x), toScreenY(p2.y),
202 toScreenX(p1.x), toScreenY(p1.y));
206 * Draws an arc which starts / ends exactly at the given coordinates.
208 * @param cx center in x
209 * @param cy center in y
210 * @param radius Radius
211 * @param a1 Angle 1 in rad
212 * @param a2 Angle 2 in rad
213 * @param x1 startpoint x
214 * @param y1 startpoint y
215 * @param x2 endpoint x
216 * @param y2 endpoint y
217 * @param reversed true: clockwise, false: counterclockwise
219 void PaintInterface::drawArc(const Vector & cp, double radius,
220 double a1, double a2, const Vector & p1, const Vector & p2,
224 QPainter::drawArc(cx - radius, cy - radius, 2 * radius, 2 * radius, a1 * 16, (a2 - a1) * 16);
232 drawArcMac(cp, radius, a1, a2, reversed);
234 int cix; // Next point on circle
236 double aStep; // Angle Step (rad)
237 double a; // Current Angle (rad)
238 double linStep; // linear step (pixels)
240 if (drawingMode == RS2::ModePreview)
245 if (fabs(linStep / radius) <= 1.0)
246 aStep = asin(linStep / radius);
255 // Arc Counterclockwise:
256 if (a1 > a2 - 1.0e-10)
262 poly.setPoint(i++, toScreenX(p1.x), toScreenY(p1.y));
264 for(a=a1+aStep; a<=a2; a+=aStep)
266 cix = toScreenX(cp.x + cos(a) * radius);
267 ciy = toScreenY(cp.y - sin(a) * radius);
270 poly.setPoint(i++, cix, ciy);
273 //lineTo(toScreenX(p2.x), toScreenY(p2.y));
275 poly.setPoint(i++, toScreenX(p2.x), toScreenY(p2.y));
281 if (a1 < a2 + 1.0e-10)
286 poly.setPoint(i++, toScreenX(p1.x), toScreenY(p1.y));
288 for(a=a1-aStep; a>=a2; a-=aStep)
290 cix = toScreenX(cp.x + cos(a) * radius);
291 ciy = toScreenY(cp.y - sin(a) * radius);
292 poly.setPoint(i++, cix, ciy);
295 poly.setPoint(i++, toScreenX(p2.x), toScreenY(p2.y));
305 * @param cx center in x
306 * @param cy center in y
307 * @param radius Radius
308 * @param a1 Angle 1 in rad
309 * @param a2 Angle 2 in rad
310 * @param reversed true: clockwise, false: counterclockwise
312 void PaintInterface::drawArc(const Vector & cp, double radius, double a1, double a2, bool reversed)
319 drawArcMac(cp, radius, a1, a2, reversed);
322 createArc(p, cp, radius, a1, a2, reversed);
324 painter->drawPolyline(p);
330 * Draws an arc on apple.
332 * @param cx center in x
333 * @param cy center in y
334 * @param radius Radius
335 * @param a1 Angle 1 in rad
336 * @param a2 Angle 2 in rad
337 * @param reversed true: clockwise, false: counterclockwise
339 void PaintInterface::drawArcMac(const Vector& cp, double radius, double a1, double a2, bool reversed)
341 RS_DEBUG->print("PaintInterface::drawArcMac");
346 double cix; // Next point on circle
348 double aStep; // Angle Step (rad)
349 double a; // Current Angle (rad)
353 if (2.0 / radius <= 1.0)
354 aStep = asin(2.0 / radius);
361 ox = cp.x + cos(a1) * radius;
362 oy = cp.y - sin(a1) * radius;
366 // Arc Counterclockwise:
367 if (a1 > a2 - 1.0e-10)
370 for(a=a1+aStep; a<=a2; a+=aStep)
372 cix = cp.x + cos(a) * radius;
373 ciy = cp.y - sin(a) * radius;
374 drawLine(Vector(ox, oy), Vector(cix, ciy));
382 if (a1 < a2 + 1.0e-10)
385 for(a=a1-aStep; a>=a2; a-=aStep)
387 cix = cp.x + cos(a) * radius;
388 ciy = cp.y - sin(a) * radius;
389 drawLine(Vector(ox, oy), Vector(cix, ciy));
395 drawLine(Vector(ox, oy), Vector(cp.x + cos(a2) * radius, cp.y - sin(a2) * radius));
401 * @param cx center in x
402 * @param cy center in y
403 * @param radius Radius
405 void PaintInterface::drawCircle(const Vector & cp, double radius)
407 //This old code was causing the Qt painter code to segfault...
408 //If we have problems with arcs, then drawArc() is probably the culprit.
410 if (drawingMode == RS2::ModeXOR && radius < 500)
412 // This is _very_ slow for large arcs:
413 painter->drawEllipse(toScreenX(cp.x - radius), toScreenY(cp.y - radius), RS_Math::round(2.0 * radius), RS_Math::round(2.0 * radius));
418 drawArcMac(cp, radius, 0.0, 2 * M_PI, false);
420 drawArc(cp, radius, 0.0, 2 * M_PI, cp + Vector(radius, 0.0), cp + Vector(radius, 0.0), false);
424 // painter->drawEllipse(toScreenX(cp.x - radius), toScreenY(cp.y - radius), RS_Math::round(2.0 * radius), RS_Math::round(2.0 * radius));
425 painter->drawEllipse(QPointF(cp.x, cp.y), radius, radius);
430 * Draws a rotated ellipse arc.
432 void PaintInterface::drawEllipse(const Vector & cp, double radius1, double radius2,
433 double angle, double a1, double a2, bool reversed)
435 double aStep; // Angle Step (rad)
436 double a; // Current Angle (rad)
442 Vector vc(cp.x, cp.y);
443 vp.set(cp.x + cos(a1) * radius1, cp.y - sin(a1) * radius2);
444 vp.rotate(vc, -angle);
445 // moveTo(toScreenX(vp.x), toScreenY(vp.y));
449 // Arc Counterclockwise:
450 if (a1 > a2 - RS_TOLERANCE)
453 for(a=a1+aStep; a<=a2; a+=aStep)
456 vp.set(cp.x + cos(a) * radius1, cp.y - sin(a) * radius2);
457 vp.rotate(vc, -angle);
458 // lineTo(toScreenX(vp.x), toScreenY(vp.y));
459 drawLine(Vector(toScreenX(last.x), toScreenY(last.y)),
460 Vector(toScreenX(vp.x), toScreenY(vp.y)));
466 if (a1 < a2 + RS_TOLERANCE)
469 for(a=a1-aStep; a>=a2; a-=aStep)
472 vp.set(cp.x + cos(a) * radius1, cp.y - sin(a) * radius2);
473 vp.rotate(vc, -angle);
474 // lineTo(toScreenX(vp.x), toScreenY(vp.y));
475 drawLine(Vector(toScreenX(last.x), toScreenY(last.y)),
476 Vector(toScreenX(vp.x), toScreenY(vp.y)));
481 vp.set(cp.x + cos(a2) * radius1, cp.y - sin(a2) * radius2);
482 vp.rotate(vc, -angle);
483 // lineTo(toScreenX(vp.x), toScreenY(vp.y));
484 drawLine(Vector(toScreenX(last.x), toScreenY(last.y)),
485 Vector(toScreenX(vp.x), toScreenY(vp.y)));
492 void PaintInterface::drawImg(QImage & img, const Vector & pos,
493 double angle, const Vector & factor, int sx, int sy, int sw, int sh)
498 wm.translate(pos.x, pos.y);
499 wm.scale(factor.x, factor.y);
500 wm.rotate(RS_Math::rad2deg(-angle));
501 painter->setWorldMatrix(wm);
503 if (fabs(angle) < 1.0e-4)
504 painter->drawImage(0 + sx, -img.height() + sy, img, sx, sy, sw, sh);
506 painter->drawImage(0, -img.height(), img);
511 void PaintInterface::fillRect(int x1, int y1, int w, int h, const RS_Color & col)
513 painter->fillRect(x1, y1, w, h, col);
516 void PaintInterface::fillTriangle(const Vector & p1, const Vector & p2, const Vector & p3)
519 poly.putPoints(0, 3, toScreenX(p1.x),toScreenY(p1.y), toScreenX(p2.x),toScreenY(p2.y), toScreenX(p3.x),toScreenY(p3.y));
520 setBrush(painter->pen().color());
524 void PaintInterface::erase()
526 painter->eraseRect(0, 0, getWidth(), getHeight());
529 int PaintInterface::getWidth()
531 return painter->device()->width();
534 int PaintInterface::getHeight()
536 return painter->device()->height();
539 void PaintInterface::setPreviewPen()
541 setPen(RS_Color(0, 255, 255));
544 RS_Pen PaintInterface::getPen()
549 void PaintInterface::setPen(const RS_Pen & pen)
553 if (drawingMode == RS2::ModeBW)
554 lpen.setColor(RS_Color(0, 0, 0));
556 QPen p(lpen.getColor(), RS_Math::round(lpen.getScreenWidth()), RS2::rsToQtLineType(lpen.getLineType()));
557 p.setJoinStyle(Qt::RoundJoin);
558 p.setCapStyle(Qt::RoundCap);
562 void PaintInterface::setPen(const RS_Color & color)
564 if (drawingMode == RS2::ModeBW)
566 lpen.setColor(RS_Color(0, 0, 0));
567 painter->setPen(RS_Color(0, 0, 0));
571 lpen.setColor(color);
572 painter->setPen(color);
576 void PaintInterface::setPen(int r, int g, int b)
578 if (drawingMode == RS2::ModeBW)
579 setPen(QColor(0, 0, 0));
581 setPen(QColor(r, g, b));
584 void PaintInterface::disablePen()
586 lpen = RS_Pen(RS2::FlagInvalid);
587 painter->setPen(Qt::NoPen);
590 void PaintInterface::setBrush(const RS_Color & color)
592 if (drawingMode == RS2::ModeBW)
593 painter->setBrush(QColor(0, 0, 0));
595 painter->setBrush(color);
598 void PaintInterface::drawPolygon(const QPolygon & a)
600 painter->drawPolygon(a);
603 void PaintInterface::setXORMode()
605 painter->setCompositionMode(QPainter::CompositionMode_Xor);
608 void PaintInterface::setNormalMode()
610 painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
613 void PaintInterface::setClipRect(int x, int y, int w, int h)
615 painter->setClipRect(x, y, w, h);
616 painter->setClipping(true);
619 void PaintInterface::resetClipping()
621 painter->setClipping(false);