3 // Part of the Architektonas Project
4 // Extensively rewritten and refactored by James L. Hammons
5 // Portions copyright (C) 2001-2003 RibbonSoft
6 // Copyright (C) 2010 Underground Software
7 // See the README and GPLv2 files for licensing and warranty information
9 // JLH = James L. Hammons <jlhamm@acm.org>
12 // --- ---------- -----------------------------------------------------------
13 // JLH 05/21/2010 Created this file. :-)
16 // BIG NOTE: THIS CLASS ASSUMES THAT THE PAINTER * IS VALID!!! BAD THINGS WILL
17 // HAPPEN IF IT IS NOT!!!
19 #include "paintinterface.h"
22 #include "mathextra.h"
24 PaintInterface::PaintInterface(QPainter * p): painter(p), drawingMode(RS2::ModeFull),
25 offset(Vector(0.0, 0.0))
30 * Sets the drawing mode.
32 void PaintInterface::setDrawingMode(RS2::DrawingMode m)
38 * @return Current drawing mode.
40 RS2::DrawingMode PaintInterface::getDrawingMode()
45 void PaintInterface::createArc(QPolygon & pa, const Vector& cp, double radius,
46 double a1, double a2, bool reversed)
50 DEBUG->print(Debug::D_WARNING, "PaintInterface::createArc: invalid radius: %f", radius);
54 int cix; // Next point on circle
56 double aStep; // Angle Step (rad)
57 double a; // Current Angle (rad)
59 if (fabs(2.0 / radius) <= 1.0)
60 aStep = asin(2.0 / radius);
68 // less than a pixel long lines:
69 //if (radius*aStep<1.0) {
76 pa.setPoint(i++, toScreenX(cp.x + cos(a1) * radius), toScreenY(cp.y - sin(a1) * radius));
77 //moveTo(toScreenX(cp.x+cos(a1)*radius),
78 // toScreenY(cp.y-sin(a1)*radius));
82 // Arc Counterclockwise:
83 if (a1 > a2 - 1.0e-10)
86 for(a=a1+aStep; a<=a2; a+=aStep)
88 cix = toScreenX(cp.x + cos(a) * radius);
89 ciy = toScreenY(cp.y - sin(a) * radius);
91 pa.setPoint(i++, cix, ciy);
97 if (a1 < a2 + 1.0e-10)
100 for(a=a1-aStep; a>=a2; a-=aStep)
102 cix = toScreenX(cp.x + cos(a) * radius);
103 ciy = toScreenY(cp.y - sin(a) * radius);
106 pa.setPoint(i++, cix, ciy);
111 pa.setPoint(i++, toScreenX(cp.x + cos(a2) * radius), toScreenY(cp.y - sin(a2) * radius));
115 void PaintInterface::drawRect(const Vector & p1, const Vector & p2)
117 drawLine(Vector(p1.x, p1.y), Vector(p2.x, p1.y));
118 drawLine(Vector(p2.x, p1.y), Vector(p2.x, p2.y));
119 drawLine(Vector(p2.x, p2.y), Vector(p1.x, p2.y));
120 drawLine(Vector(p1.x, p2.y), Vector(p1.x, p1.y));
123 void PaintInterface::drawHandle(const Vector & p, const Color & c, int size)
128 fillRect((int)(p.x - size), (int)(p.y - size), 2 * size, 2 * size, c);
131 void PaintInterface::setPreviewMode()
133 drawingMode = RS2::ModeXOR;
138 bool PaintInterface::isPreviewMode()
140 return (drawingMode == RS2::ModeXOR);
143 void PaintInterface::setOffset(const Vector & o)
148 int PaintInterface::toScreenX(double x)
150 return Math::round(offset.x + x);
153 int PaintInterface::toScreenY(double y)
155 return Math::round(offset.y + y);
159 * Draws a grid point at (x1, y1).
161 void PaintInterface::drawGridPoint(const Vector & p)
163 painter->drawPoint(toScreenX(p.x), toScreenY(p.y));
167 * Draws a point at (x1, y1).
169 void PaintInterface::drawPoint(const Vector & p)
171 painter->drawLine(toScreenX(p.x - 1), toScreenY(p.y), toScreenX(p.x + 1), toScreenY(p.y));
172 painter->drawLine(toScreenX(p.x), toScreenY(p.y - 1), toScreenX(p.x), toScreenY(p.y + 1));
176 * Draws a line from (x1, y1) to (x2, y2).
178 void PaintInterface::drawLine(const Vector & p1, const Vector & p2)
181 int w2 = (int)getPen().getScreenWidth() / 2;
182 QPainter::drawLine(toScreenX(p1.x - w2), toScreenY(p1.y - w2),
183 toScreenX(p2.x - w2), toScreenY(p2.y - w2));
185 painter->drawLine(toScreenX(p1.x), toScreenY(p1.y), toScreenX(p2.x), toScreenY(p2.y));
190 * Draws a rectangle with corners p1, p2.
192 /*void PaintInterface::drawRect(const Vector& p1, const Vector& p2) {
193 / *QPainter::drawRect(toScreenX(p1.x), toScreenY(p1.y),
194 abs(toScreenX(p2.x) - toScreenX(p1.x)),
195 abs(toScreenY(p2.y) - toScreenY(p1.y)));* /
196 QPainter::drawLine(toScreenX(p1.x), toScreenY(p1.y),
197 toScreenX(p2.x), toScreenY(p1.y));
198 QPainter::drawLine(toScreenX(p2.x), toScreenY(p1.y),
199 toScreenX(p2.x), toScreenY(p2.y));
200 QPainter::drawLine(toScreenX(p2.x), toScreenY(p2.y),
201 toScreenX(p1.x), toScreenY(p2.y));
202 QPainter::drawLine(toScreenX(p1.x), toScreenY(p2.y),
203 toScreenX(p1.x), toScreenY(p1.y));
207 * Draws an arc which starts / ends exactly at the given coordinates.
209 * @param cx center in x
210 * @param cy center in y
211 * @param radius Radius
212 * @param a1 Angle 1 in rad
213 * @param a2 Angle 2 in rad
214 * @param x1 startpoint x
215 * @param y1 startpoint y
216 * @param x2 endpoint x
217 * @param y2 endpoint y
218 * @param reversed true: clockwise, false: counterclockwise
220 void PaintInterface::drawArc(const Vector & cp, double radius,
221 double a1, double a2, const Vector & p1, const Vector & p2,
225 QPainter::drawArc(cx - radius, cy - radius, 2 * radius, 2 * radius, a1 * 16, (a2 - a1) * 16);
233 drawArcMac(cp, radius, a1, a2, reversed);
235 int cix; // Next point on circle
237 double aStep; // Angle Step (rad)
238 double a; // Current Angle (rad)
239 double linStep; // linear step (pixels)
241 if (drawingMode == RS2::ModePreview)
246 if (fabs(linStep / radius) <= 1.0)
247 aStep = asin(linStep / radius);
256 // Arc Counterclockwise:
257 if (a1 > a2 - 1.0e-10)
263 poly.setPoint(i++, toScreenX(p1.x), toScreenY(p1.y));
265 for(a=a1+aStep; a<=a2; a+=aStep)
267 cix = toScreenX(cp.x + cos(a) * radius);
268 ciy = toScreenY(cp.y - sin(a) * radius);
271 poly.setPoint(i++, cix, ciy);
274 //lineTo(toScreenX(p2.x), toScreenY(p2.y));
276 poly.setPoint(i++, toScreenX(p2.x), toScreenY(p2.y));
282 if (a1 < a2 + 1.0e-10)
287 poly.setPoint(i++, toScreenX(p1.x), toScreenY(p1.y));
289 for(a=a1-aStep; a>=a2; a-=aStep)
291 cix = toScreenX(cp.x + cos(a) * radius);
292 ciy = toScreenY(cp.y - sin(a) * radius);
293 poly.setPoint(i++, cix, ciy);
296 poly.setPoint(i++, toScreenX(p2.x), toScreenY(p2.y));
306 * @param cx center in x
307 * @param cy center in y
308 * @param radius Radius
309 * @param a1 Angle 1 in rad
310 * @param a2 Angle 2 in rad
311 * @param reversed true: clockwise, false: counterclockwise
313 void PaintInterface::drawArc(const Vector & cp, double radius, double a1, double a2, bool reversed)
320 drawArcMac(cp, radius, a1, a2, reversed);
323 createArc(p, cp, radius, a1, a2, reversed);
325 painter->drawPolyline(p);
331 * Draws an arc on apple.
333 * @param cx center in x
334 * @param cy center in y
335 * @param radius Radius
336 * @param a1 Angle 1 in rad
337 * @param a2 Angle 2 in rad
338 * @param reversed true: clockwise, false: counterclockwise
340 void PaintInterface::drawArcMac(const Vector& cp, double radius, double a1, double a2, bool reversed)
342 DEBUG->print("PaintInterface::drawArcMac");
347 double cix; // Next point on circle
349 double aStep; // Angle Step (rad)
350 double a; // Current Angle (rad)
354 if (2.0 / radius <= 1.0)
355 aStep = asin(2.0 / radius);
362 ox = cp.x + cos(a1) * radius;
363 oy = cp.y - sin(a1) * radius;
367 // Arc Counterclockwise:
368 if (a1 > a2 - 1.0e-10)
371 for(a=a1+aStep; a<=a2; a+=aStep)
373 cix = cp.x + cos(a) * radius;
374 ciy = cp.y - sin(a) * radius;
375 drawLine(Vector(ox, oy), Vector(cix, ciy));
383 if (a1 < a2 + 1.0e-10)
386 for(a=a1-aStep; a>=a2; a-=aStep)
388 cix = cp.x + cos(a) * radius;
389 ciy = cp.y - sin(a) * radius;
390 drawLine(Vector(ox, oy), Vector(cix, ciy));
396 drawLine(Vector(ox, oy), Vector(cp.x + cos(a2) * radius, cp.y - sin(a2) * radius));
402 * @param cx center in x
403 * @param cy center in y
404 * @param radius Radius
406 void PaintInterface::drawCircle(const Vector & cp, double radius)
408 //This old code was causing the Qt painter code to segfault...
409 //If we have problems with arcs, then drawArc() is probably the culprit.
411 if (drawingMode == RS2::ModeXOR && radius < 500)
413 // This is _very_ slow for large arcs:
414 painter->drawEllipse(toScreenX(cp.x - radius), toScreenY(cp.y - radius), Math::round(2.0 * radius), Math::round(2.0 * radius));
419 drawArcMac(cp, radius, 0.0, 2 * M_PI, false);
421 drawArc(cp, radius, 0.0, 2 * M_PI, cp + Vector(radius, 0.0), cp + Vector(radius, 0.0), false);
425 // painter->drawEllipse(toScreenX(cp.x - radius), toScreenY(cp.y - radius), Math::round(2.0 * radius), Math::round(2.0 * radius));
426 painter->drawEllipse(QPointF(cp.x, cp.y), radius, radius);
431 * Draws a rotated ellipse arc.
433 void PaintInterface::drawEllipse(const Vector & cp, double radius1, double radius2,
434 double angle, double a1, double a2, bool reversed)
436 double aStep; // Angle Step (rad)
437 double a; // Current Angle (rad)
443 Vector vc(cp.x, cp.y);
444 vp.set(cp.x + cos(a1) * radius1, cp.y - sin(a1) * radius2);
445 vp.rotate(vc, -angle);
446 // moveTo(toScreenX(vp.x), toScreenY(vp.y));
450 // Arc Counterclockwise:
451 if (a1 > a2 - RS_TOLERANCE)
454 for(a=a1+aStep; a<=a2; a+=aStep)
457 vp.set(cp.x + cos(a) * radius1, cp.y - sin(a) * radius2);
458 vp.rotate(vc, -angle);
459 // lineTo(toScreenX(vp.x), toScreenY(vp.y));
460 drawLine(Vector(toScreenX(last.x), toScreenY(last.y)),
461 Vector(toScreenX(vp.x), toScreenY(vp.y)));
467 if (a1 < a2 + RS_TOLERANCE)
470 for(a=a1-aStep; a>=a2; a-=aStep)
473 vp.set(cp.x + cos(a) * radius1, cp.y - sin(a) * radius2);
474 vp.rotate(vc, -angle);
475 // lineTo(toScreenX(vp.x), toScreenY(vp.y));
476 drawLine(Vector(toScreenX(last.x), toScreenY(last.y)),
477 Vector(toScreenX(vp.x), toScreenY(vp.y)));
482 vp.set(cp.x + cos(a2) * radius1, cp.y - sin(a2) * radius2);
483 vp.rotate(vc, -angle);
484 // lineTo(toScreenX(vp.x), toScreenY(vp.y));
485 drawLine(Vector(toScreenX(last.x), toScreenY(last.y)),
486 Vector(toScreenX(vp.x), toScreenY(vp.y)));
493 void PaintInterface::drawImg(QImage & img, const Vector & pos,
494 double angle, const Vector & factor, int sx, int sy, int sw, int sh)
499 wm.translate(pos.x, pos.y);
500 wm.scale(factor.x, factor.y);
501 wm.rotate(Math::rad2deg(-angle));
502 painter->setWorldMatrix(wm);
504 if (fabs(angle) < 1.0e-4)
505 painter->drawImage(0 + sx, -img.height() + sy, img, sx, sy, sw, sh);
507 painter->drawImage(0, -img.height(), img);
512 void PaintInterface::fillRect(int x1, int y1, int w, int h, const Color & col)
514 painter->fillRect(x1, y1, w, h, col);
517 void PaintInterface::fillTriangle(const Vector & p1, const Vector & p2, const Vector & p3)
520 poly.putPoints(0, 3, toScreenX(p1.x),toScreenY(p1.y), toScreenX(p2.x),toScreenY(p2.y), toScreenX(p3.x),toScreenY(p3.y));
521 setBrush(painter->pen().color());
525 void PaintInterface::erase()
527 painter->eraseRect(0, 0, getWidth(), getHeight());
530 int PaintInterface::getWidth()
532 return painter->device()->width();
535 int PaintInterface::getHeight()
537 return painter->device()->height();
540 void PaintInterface::setPreviewPen()
542 setPen(Color(0, 255, 255));
545 Pen PaintInterface::getPen()
550 void PaintInterface::setPen(const Pen & pen)
554 if (drawingMode == RS2::ModeBW)
555 lpen.setColor(Color(0, 0, 0));
557 QPen p(lpen.getColor(), Math::round(lpen.getScreenWidth()), RS2::rsToQtLineType(lpen.getLineType()));
558 p.setJoinStyle(Qt::RoundJoin);
559 p.setCapStyle(Qt::RoundCap);
563 void PaintInterface::setPen(const Color & color)
565 if (drawingMode == RS2::ModeBW)
567 lpen.setColor(Color(0, 0, 0));
568 painter->setPen(Color(0, 0, 0));
572 lpen.setColor(color);
573 painter->setPen(color);
577 void PaintInterface::setPen(int r, int g, int b)
579 if (drawingMode == RS2::ModeBW)
580 setPen(QColor(0, 0, 0));
582 setPen(QColor(r, g, b));
585 void PaintInterface::disablePen(void)
587 lpen = Pen(RS2::FlagInvalid);
588 painter->setPen(Qt::NoPen);
591 void PaintInterface::setBrush(const Color & color)
593 if (drawingMode == RS2::ModeBW)
594 painter->setBrush(QColor(0, 0, 0));
596 painter->setBrush(color);
599 void PaintInterface::disableBrush(void)
601 // lpen = Pen(RS2::FlagInvalid);
602 painter->setBrush(Qt::NoBrush);
605 void PaintInterface::drawPolygon(const QPolygon & a)
607 painter->drawPolygon(a);
610 void PaintInterface::setXORMode(void)
612 painter->setCompositionMode(QPainter::CompositionMode_Xor);
615 void PaintInterface::setNormalMode(void)
617 painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
620 void PaintInterface::setClipRect(int x, int y, int w, int h)
622 painter->setClipRect(x, y, w, h);
623 painter->setClipping(true);
626 void PaintInterface::resetClipping()
628 painter->setClipping(false);