00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 #include "qtcolortriangle.h"
00057
00058 #include <QEvent>
00059 #include <QMap>
00060 #include <QVarLengthArray>
00061 #include <QConicalGradient>
00062 #include <QFrame>
00063 #include <QImage>
00064 #include <QKeyEvent>
00065 #include <QLayout>
00066 #include <QMouseEvent>
00067 #include <QPainter>
00068 #include <QPainterPath>
00069 #include <QPixmap>
00070 #include <QResizeEvent>
00071 #include <QToolTip>
00072 #include <QVBoxLayout>
00073
00074 #include <math.h>
00075
00098 const double PI = 3.14159265358979323846264338327950288419717;
00099 const double TWOPI = 2.0*PI;
00100
00101
00102
00103
00104 struct DoubleColor
00105 {
00106 double r, g, b;
00107
00108 DoubleColor() : r(0.0), g(0.0), b(0.0) {}
00109 DoubleColor(double red, double green, double blue) : r(red), g(green), b(blue) {}
00110 DoubleColor(const DoubleColor &c) : r(c.r), g(c.g), b(c.b) {}
00111 };
00112
00113
00114
00115
00116 struct Vertex {
00117 DoubleColor color;
00118 QPointF point;
00119
00120 Vertex(const DoubleColor &c, const QPointF &p) : color(c), point(p) {}
00121 Vertex(const QColor &c, const QPointF &p)
00122 : color(DoubleColor((double) c.red(), (double) c.green(),
00123 (double) c.blue())), point(p) {}
00124 };
00125
00130 static void swap(Vertex **a, Vertex **b)
00131 {
00132 Vertex *tmp = *a;
00133 *a = *b;
00134 *b = tmp;
00135 }
00136
00140 QtColorTriangle::QtColorTriangle(QWidget *parent)
00141 : QWidget(parent), bg(sizeHint(), QImage::Format_RGB32), selMode(Idle)
00142 {
00143 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
00144 setFocusPolicy(Qt::StrongFocus);
00145
00146 mustGenerateBackground = true;
00147
00148 QColor tmp;
00149 tmp.setHsv(76, 184, 206);
00150 setColor(tmp);
00151 }
00152
00156 QtColorTriangle::~QtColorTriangle()
00157 {
00158 }
00159
00165 void QtColorTriangle::polish()
00166 {
00167 outerRadius = (contentsRect().width() - 1) / 2;
00168 if ((contentsRect().height() - 1) / 2 < outerRadius)
00169 outerRadius = (contentsRect().height() - 1) / 2;
00170
00171 penWidth = (int) floor(outerRadius / 50.0);
00172 ellipseSize = (int) floor(outerRadius / 12.5);
00173
00174 double cx = (double) contentsRect().center().x();
00175 double cy = (double) contentsRect().center().y();
00176
00177 pa = QPointF(cx + (cos(a) * (outerRadius - (outerRadius / 5.0))),
00178 cy - (sin(a) * (outerRadius - (outerRadius / 5.0))));
00179 pb = QPointF(cx + (cos(b) * (outerRadius - (outerRadius / 5.0))),
00180 cy - (sin(b) * (outerRadius - (outerRadius / 5.0))));
00181 pc = QPointF(cx + (cos(c) * (outerRadius - (outerRadius / 5.0))),
00182 cy - (sin(c) * (outerRadius - (outerRadius / 5.0))));
00183 pd = QPointF(cx + (cos(a) * (outerRadius - (outerRadius / 10.0))),
00184 cy - (sin(a) * (outerRadius - (outerRadius / 10.0))));
00185
00186
00187 selectorPos = pointFromColor(curColor);
00188
00189 update();
00190 }
00191
00194 QSize QtColorTriangle::sizeHint() const
00195 {
00196 return QSize(100, 100);
00197 }
00198
00203 int QtColorTriangle::heightForWidth(int w) const
00204 {
00205 return w;
00206 }
00207
00214 void QtColorTriangle::genBackground()
00215 {
00216
00217 double innerRadius = outerRadius - outerRadius / 5;
00218
00219
00220 bg = QImage(contentsRect().size(), QImage::Format_ARGB32_Premultiplied);
00221 bg.fill(qRgba(0,0,0,0));
00222 QPainter p(&bg);
00223 p.setRenderHint(QPainter::Antialiasing);
00224
00225 QConicalGradient gradient(bg.rect().center(), 90);
00226 QColor color;
00227 for (double i = 0; i <= 1.0; i += 0.1) {
00228 #if QT_VERSION < 0x040100
00229 color.setHsv(int(i * 360.0), 255, 255);
00230 #else
00231 color.setHsv(int(360.0 - (i * 360.0)), 255, 255);
00232 #endif
00233 gradient.setColorAt(i, color);
00234 }
00235
00236 QRectF innerRadiusRect(bg.rect().center().x() - innerRadius, bg.rect().center().y() - innerRadius,
00237 innerRadius * 2 + 1, innerRadius * 2 + 1);
00238 QRectF outerRadiusRect(bg.rect().center().x() - outerRadius, bg.rect().center().y() - outerRadius,
00239 outerRadius * 2 + 1, outerRadius * 2 + 1);
00240 QPainterPath path;
00241 path.addEllipse(innerRadiusRect);
00242 path.addEllipse(outerRadiusRect);
00243
00244 p.save();
00245 p.setClipPath(path);
00246 p.fillRect(bg.rect(), gradient);
00247 p.restore();
00248
00249 double penThickness = bg.width() / 400.0;
00250 for (int f = 0; f <= 5760; f += 20) {
00251 int value = int((0.5 + cos(((f - 1800) / 5760.0) * TWOPI) / 2) * 255.0);
00252
00253 color.setHsv(int((f / 5760.0) * 360.0), 128 + (255 - value)/2, 255 - (255 - value)/4);
00254 p.setPen(QPen(color, penThickness));
00255 p.drawArc(innerRadiusRect, 1440 - f, 20);
00256
00257 color.setHsv(int((f / 5760.0) * 360.0), 128 + value/2, 255 - value/4);
00258 p.setPen(QPen(color, penThickness));
00259 p.drawArc(outerRadiusRect, 2880 - 1440 - f, 20);
00260 }
00261
00262 return;
00263 }
00264
00271 void QtColorTriangle::mouseMoveEvent(QMouseEvent *e)
00272 {
00273 if ((e->buttons() & Qt::LeftButton) == 0)
00274 return;
00275
00276 QPointF depos((double) e->pos().x(), (double) e->pos().y());
00277 bool newColor = false;
00278
00279 if (selMode == SelectingHue) {
00280
00281
00282
00283 a = angleAt(depos, contentsRect());
00284 b = a + TWOPI / 3.0;
00285 c = b + TWOPI / 3.0;
00286 if (b > TWOPI) b -= TWOPI;
00287 if (c > TWOPI) c -= TWOPI;
00288
00289 double am = a - PI/2;
00290 if (am < 0) am += TWOPI;
00291
00292 curHue = 360 - (int) (((am) * 360.0) / TWOPI);
00293 int h,s,v;
00294 curColor.getHsv(&h, &s, &v);
00295
00296 if (curHue != h) {
00297 newColor = true;
00298 curColor.setHsv(curHue, s, v, curColor.alpha());
00299 }
00300
00301 double cx = (double) contentsRect().center().x();
00302 double cy = (double) contentsRect().center().y();
00303
00304 pa = QPointF(cx + (cos(a) * (outerRadius - (outerRadius / 5.0))),
00305 cy - (sin(a) * (outerRadius - (outerRadius / 5.0))));
00306 pb = QPointF(cx + (cos(b) * (outerRadius - (outerRadius / 5.0))),
00307 cy - (sin(b) * (outerRadius - (outerRadius / 5.0))));
00308 pc = QPointF(cx + (cos(c) * (outerRadius - (outerRadius / 5.0))),
00309 cy - (sin(c) * (outerRadius - (outerRadius / 5.0))));
00310 pd = QPointF(cx + (cos(a) * (outerRadius - (outerRadius / 10.0))),
00311 cy - (sin(a) * (outerRadius - (outerRadius / 10.0))));
00312
00313 selectorPos = pointFromColor(curColor);
00314 } else {
00315 Vertex aa(Qt::black, pa);
00316 Vertex bb(Qt::black, pb);
00317 Vertex cc(Qt::black, pc);
00318
00319 Vertex *p1 = &aa;
00320 Vertex *p2 = &bb;
00321 Vertex *p3 = &cc;
00322 if (p1->point.y() > p2->point.y()) swap(&p1, &p2);
00323 if (p1->point.y() > p3->point.y()) swap(&p1, &p3);
00324 if (p2->point.y() > p3->point.y()) swap(&p2, &p3);
00325
00326 selectorPos = movePointToTriangle(depos.x(), depos.y(), aa, bb, cc);
00327 QColor col = colorFromPoint(selectorPos);
00328 if (col != curColor) {
00329
00330
00331 int h,s,v;
00332 col.getHsv(&h, &s, &v);
00333 curColor.setHsv(curHue, s, v, curColor.alpha());
00334 newColor = true;
00335 }
00336 }
00337
00338 if (newColor)
00339 internalSetNewColor(curColor);
00340
00341 update();
00342 }
00343
00352 void QtColorTriangle::mousePressEvent(QMouseEvent *e)
00353 {
00354
00355 if (e->button() != Qt::LeftButton)
00356 return;
00357
00358 QPointF depos((double) e->pos().x(), (double) e->pos().y());
00359 double rad = radiusAt(depos, contentsRect());
00360 bool newColor = false;
00361
00362
00363
00364 if (rad > (outerRadius - (outerRadius / 5))) {
00365 selMode = SelectingHue;
00366
00367 a = angleAt(depos, contentsRect());
00368 b = a + TWOPI / 3.0;
00369 c = b + TWOPI / 3.0;
00370 if (b > TWOPI) b -= TWOPI;
00371 if (c > TWOPI) c -= TWOPI;
00372
00373 double am = a - PI/2;
00374 if (am < 0) am += TWOPI;
00375
00376 curHue = 360 - (int) ((am * 360.0) / TWOPI);
00377 int h,s,v;
00378 curColor.getHsv(&h, &s, &v);
00379
00380 if (h != curHue) {
00381 newColor = true;
00382 curColor.setHsv(curHue, s, v, curColor.alpha());
00383 }
00384
00385 double cx = (double) contentsRect().center().x();
00386 double cy = (double) contentsRect().center().y();
00387
00388 pa = QPointF(cx + (cos(a) * (outerRadius - (outerRadius / 5.0))),
00389 cy - (sin(a) * (outerRadius - (outerRadius / 5.0))));
00390 pb = QPointF(cx + (cos(b) * (outerRadius - (outerRadius / 5.0))),
00391 cy - (sin(b) * (outerRadius - (outerRadius / 5.0))));
00392 pc = QPointF(cx + (cos(c) * (outerRadius - (outerRadius / 5.0))),
00393 cy - (sin(c) * (outerRadius - (outerRadius / 5.0))));
00394 pd = QPointF(cx + (cos(a) * (outerRadius - (outerRadius / 10.0))),
00395 cy - (sin(a) * (outerRadius - (outerRadius / 10.0))));
00396
00397 selectorPos = pointFromColor(curColor);
00398 internalSetNewColor(curColor);
00399 } else {
00400 selMode = SelectingSatValue;
00401
00402 Vertex aa(Qt::black, pa);
00403 Vertex bb(Qt::black, pb);
00404 Vertex cc(Qt::black, pc);
00405
00406 Vertex *p1 = &aa;
00407 Vertex *p2 = &bb;
00408 Vertex *p3 = &cc;
00409 if (p1->point.y() > p2->point.y()) swap(&p1, &p2);
00410 if (p1->point.y() > p3->point.y()) swap(&p1, &p3);
00411 if (p2->point.y() > p3->point.y()) swap(&p2, &p3);
00412
00413 selectorPos = movePointToTriangle(depos.x(), depos.y(), aa, bb, cc);
00414 QColor col = colorFromPoint(selectorPos);
00415 if (col != curColor) {
00416 int tempalpha = curColor.alpha();
00417 curColor = col;
00418 curColor.setAlpha(tempalpha);
00419 newColor = true;
00420 }
00421 }
00422
00423 if (newColor)
00424 internalSetNewColor(curColor);
00425
00426 update();
00427 }
00428
00434 void QtColorTriangle::mouseReleaseEvent(QMouseEvent *e)
00435 {
00436 if (e->button() == Qt::LeftButton)
00437 selMode = Idle;
00438 }
00439
00443 void QtColorTriangle::keyPressEvent(QKeyEvent *e)
00444 {
00445 switch (e->key()) {
00446 case Qt::Key_Left: {
00447 --curHue;
00448 if (curHue < 0) curHue += 360;
00449 int h,s,v;
00450 curColor.getHsv(&h, &s, &v);
00451 QColor tmp;
00452 tmp.setHsv(curHue, s, v);
00453 setColor(tmp);
00454 }
00455 break;
00456 case Qt::Key_Right: {
00457 ++curHue;
00458 if (curHue > 359) curHue -= 360;
00459 int h,s,v;
00460 curColor.getHsv(&h, &s, &v);
00461 QColor tmp;
00462 tmp.setHsv(curHue, s, v);
00463 setColor(tmp);
00464 }
00465 break;
00466 case Qt::Key_Up: {
00467 int h,s,v;
00468 curColor.getHsv(&h, &s, &v);
00469 QColor tmp;
00470 if (e->modifiers() & Qt::ShiftModifier) {
00471 if (s > 5) s -= 5;
00472 else s = 0;
00473 } else {
00474 if (v > 5) v -= 5;
00475 else v = 0;
00476 }
00477 tmp.setHsv(curHue, s, v);
00478 setColor(tmp);
00479 }
00480 break;
00481 case Qt::Key_Down: {
00482 int h,s,v;
00483 curColor.getHsv(&h, &s, &v);
00484 QColor tmp;
00485 if (e->modifiers() & Qt::ShiftModifier) {
00486 if (s < 250) s += 5;
00487 else s = 255;
00488 } else {
00489 if (v < 250) v += 5;
00490 else v = 255;
00491 }
00492 tmp.setHsv(curHue, s, v);
00493 setColor(tmp);
00494 }
00495 break;
00496 };
00497 }
00498
00504 void QtColorTriangle::resizeEvent(QResizeEvent *)
00505 {
00506 outerRadius = (contentsRect().width() - 1) / 2;
00507 if ((contentsRect().height() - 1) / 2 < outerRadius)
00508 outerRadius = (contentsRect().height() - 1) / 2;
00509
00510 penWidth = (int) floor(outerRadius / 50.0);
00511 ellipseSize = (int) floor(outerRadius / 12.5);
00512
00513 double cx = (double) contentsRect().center().x();
00514 double cy = (double) contentsRect().center().y();
00515
00516 pa = QPointF(cx + (cos(a) * (outerRadius - (outerRadius / 5.0))),
00517 cy - (sin(a) * (outerRadius - (outerRadius / 5.0))));
00518 pb = QPointF(cx + (cos(b) * (outerRadius - (outerRadius / 5.0))),
00519 cy - (sin(b) * (outerRadius - (outerRadius / 5.0))));
00520 pc = QPointF(cx + (cos(c) * (outerRadius - (outerRadius / 5.0))),
00521 cy - (sin(c) * (outerRadius - (outerRadius / 5.0))));
00522 pd = QPointF(cx + (cos(a) * (outerRadius - (outerRadius / 10.0))),
00523 cy - (sin(a) * (outerRadius - (outerRadius / 10.0))));
00524
00525
00526 selectorPos = pointFromColor(curColor);
00527
00528 mustGenerateBackground = true;
00529 update();
00530 }
00531
00538 void QtColorTriangle::paintEvent(QPaintEvent *e)
00539 {
00540 QPainter p(this);
00541 if (e->rect().intersects(contentsRect()))
00542 p.setClipRegion(e->region().intersected(contentsRect()));
00543 if (mustGenerateBackground) {
00544 genBackground();
00545 mustGenerateBackground = false;
00546 }
00547
00548
00549
00550 QImage buf = bg.copy();
00551
00552
00553 int h,s,v;
00554 curColor.getHsv(&h, &s, &v);
00555
00556
00557 QColor hueColor;
00558 hueColor.setHsv(curHue, 255, 255);
00559
00560
00561 drawTrigon(&buf, pa, pb, pc, hueColor);
00562
00563
00564 QPixmap pix = QPixmap::fromImage(buf);
00565 QPainter painter(&pix);
00566 painter.setRenderHint(QPainter::Antialiasing);
00567
00568
00569 QColor halfAlpha(0, 0, 0, 128);
00570 painter.setPen(QPen(halfAlpha, 0));
00571 painter.drawLine(pa, pb);
00572 painter.drawLine(pb, pc);
00573 painter.drawLine(pc, pa);
00574
00575 int ri, gi, bi;
00576 hueColor.getRgb(&ri, &gi, &bi);
00577 if ((ri * 30) + (gi * 59) + (bi * 11) > 12800)
00578 painter.setPen(QPen(Qt::black, penWidth));
00579 else
00580 painter.setPen(QPen(Qt::white, penWidth));
00581 painter.drawEllipse((int) (pd.x() - ellipseSize / 2.0),
00582 (int) (pd.y() - ellipseSize / 2.0),
00583 ellipseSize, ellipseSize);
00584
00585 curColor.getRgb(&ri, &gi, &bi);
00586
00587
00588
00589 if ((ri * 30) + (gi * 59) + (bi * 11) > 12800)
00590 painter.setPen(QPen(Qt::black, penWidth));
00591 else
00592 painter.setPen(QPen(Qt::white, penWidth));
00593
00594
00595 painter.drawEllipse(QRectF(selectorPos.x() - ellipseSize / 2.0,
00596 selectorPos.y() - ellipseSize / 2.0,
00597 ellipseSize + 0.5, ellipseSize + 0.5));
00598
00599
00600 p.drawPixmap(contentsRect().topLeft(), pix);
00601 }
00602
00603
00604 void QtColorTriangle::internalSetNewColor(const QColor& color)
00605 {
00606 emit colorChanged(color);
00607 }
00608
00609
00610
00620 void QtColorTriangle::drawTrigon(QImage *buf, const QPointF &pa,
00621 const QPointF &pb, const QPointF &pc,
00622 const QColor &color)
00623 {
00624
00625
00626
00627
00628
00629 Vertex aa(color, pa);
00630 Vertex bb(Qt::black, pb);
00631 Vertex cc(Qt::white, pc);
00632
00633
00634
00635 Vertex *p1 = &aa;
00636 Vertex *p2 = &bb;
00637 Vertex *p3 = &cc;
00638 if (p1->point.y() > p2->point.y()) swap(&p1, &p2);
00639 if (p1->point.y() > p3->point.y()) swap(&p1, &p3);
00640 if (p2->point.y() > p3->point.y()) swap(&p2, &p3);
00641
00642
00643 double p1p2ydist = p2->point.y() - p1->point.y();
00644 double p1p3ydist = p3->point.y() - p1->point.y();
00645 double p2p3ydist = p3->point.y() - p2->point.y();
00646 double p1p2xdist = p2->point.x() - p1->point.x();
00647 double p1p3xdist = p3->point.x() - p1->point.x();
00648 double p2p3xdist = p3->point.x() - p2->point.x();
00649
00650
00651
00652 bool lefty = p1p2xdist < 0;
00653
00654
00655
00656
00657
00658 QVarLengthArray<DoubleColor, 2000> leftColors;
00659 QVarLengthArray<DoubleColor, 2000> rightColors;
00660 QVarLengthArray<double, 2000> leftX;
00661 QVarLengthArray<double, 2000> rightX;
00662
00663 leftColors.resize(int(floor(p3->point.y() + 1)));
00664 rightColors.resize(int(floor(p3->point.y() + 1)));
00665 leftX.resize(int(floor(p3->point.y() + 1)));
00666 rightX.resize(int(floor(p3->point.y() + 1)));
00667
00668
00669
00670 DoubleColor source;
00671 DoubleColor dest;
00672 double r, g, b;
00673 double rdelta, gdelta, bdelta;
00674 double x;
00675 double xdelta;
00676 int y1, y2;
00677
00678
00679 x = p1->point.x();
00680 source = p1->color;
00681 dest = p3->color;
00682 r = source.r;
00683 g = source.g;
00684 b = source.b;
00685 y1 = (int) floor(p1->point.y());
00686 y2 = (int) floor(p3->point.y());
00687
00688
00689
00690 xdelta = p1p3ydist == 0.0 ? 0.0 : p1p3xdist / p1p3ydist;
00691 rdelta = p1p3ydist == 0.0 ? 0.0 : (dest.r - r) / p1p3ydist;
00692 gdelta = p1p3ydist == 0.0 ? 0.0 : (dest.g - g) / p1p3ydist;
00693 bdelta = p1p3ydist == 0.0 ? 0.0 : (dest.b - b) / p1p3ydist;
00694
00695
00696 int y;
00697 for (y = y1; y < y2; ++y) {
00698 if (lefty) {
00699 rightColors[y] = DoubleColor(r, g, b);
00700 rightX[y] = x;
00701 } else {
00702 leftColors[y] = DoubleColor(r, g, b);
00703 leftX[y] = x;
00704 }
00705
00706 r += rdelta;
00707 g += gdelta;
00708 b += bdelta;
00709 x += xdelta;
00710 }
00711
00712
00713
00714 x = p1->point.x();
00715 source = p1->color;
00716 dest = p2->color;
00717 r = source.r;
00718 g = source.g;
00719 b = source.b;
00720 y1 = (int) floor(p1->point.y());
00721 y2 = (int) floor(p2->point.y());
00722
00723
00724
00725 xdelta = p1p2ydist == 0.0 ? 0.0 : p1p2xdist / p1p2ydist;
00726 rdelta = p1p2ydist == 0.0 ? 0.0 : (dest.r - r) / p1p2ydist;
00727 gdelta = p1p2ydist == 0.0 ? 0.0 : (dest.g - g) / p1p2ydist;
00728 bdelta = p1p2ydist == 0.0 ? 0.0 : (dest.b - b) / p1p2ydist;
00729
00730
00731 for (y = y1; y < y2; ++y) {
00732 if (lefty) {
00733 leftColors[y] = DoubleColor(r, g, b);
00734 leftX[y] = x;
00735 } else {
00736 rightColors[y] = DoubleColor(r, g, b);
00737 rightX[y] = x;
00738 }
00739
00740 r += rdelta;
00741 g += gdelta;
00742 b += bdelta;
00743 x += xdelta;
00744 }
00745
00746
00747
00748 x = p2->point.x();
00749 source = p2->color;
00750 dest = p3->color;
00751 r = source.r;
00752 g = source.g;
00753 b = source.b;
00754 y1 = (int) floor(p2->point.y());
00755 y2 = (int) floor(p3->point.y());
00756
00757
00758
00759 xdelta = p2p3ydist == 0.0 ? 0.0 : p2p3xdist / p2p3ydist;
00760 rdelta = p2p3ydist == 0.0 ? 0.0 : (dest.r - r) / p2p3ydist;
00761 gdelta = p2p3ydist == 0.0 ? 0.0 : (dest.g - g) / p2p3ydist;
00762 bdelta = p2p3ydist == 0.0 ? 0.0 : (dest.b - b) / p2p3ydist;
00763
00764
00765 for (y = y1; y < y2; ++y) {
00766 if (lefty) {
00767 leftColors[y] = DoubleColor(r, g, b);
00768 leftX[y] = x;
00769 } else {
00770 rightColors[y] = DoubleColor(r, g, b);
00771 rightX[y] = x;
00772 }
00773
00774 r += rdelta;
00775 g += gdelta;
00776 b += bdelta;
00777 x += xdelta;
00778 }
00779
00780
00781
00782 const int p3yfloor = int(floor(p3->point.y()));
00783 for (int y = int(floor(p1->point.y())); y < p3yfloor; ++y) {
00784 double lx = leftX[y];
00785 double rx = rightX[y];
00786
00787 int lxi = (int) floor(lx);
00788 int rxi = (int) floor(rx);
00789 DoubleColor rc = rightColors[y];
00790 DoubleColor lc = leftColors[y];
00791
00792
00793 double xdist = rx - lx;
00794 if (xdist != 0.0) {
00795 double r = lc.r;
00796 double g = lc.g;
00797 double b = lc.b;
00798 double rdelta = (rc.r - r) / xdist;
00799 double gdelta = (rc.g - g) / xdist;
00800 double bdelta = (rc.b - b) / xdist;
00801
00802 QRgb *scanline = reinterpret_cast<QRgb *>(buf->scanLine(y));
00803 scanline += lxi;
00804
00805
00806 for (int i = lxi; i < rxi; ++i) {
00807 *scanline++ = qRgb((int) r, (int) g, (int) b);
00808 r += rdelta;
00809 g += gdelta;
00810 b += bdelta;
00811 }
00812 }
00813 }
00814 }
00815
00820 void QtColorTriangle::setColor(const QColor &col)
00821 {
00822 if (col == curColor)
00823 return;
00824
00825 curColor = col;
00826
00827 int h, s, v;
00828 curColor.getHsv(&h, &s, &v);
00829
00830
00831 if (h != -1)
00832 curHue = h;
00833
00834 a = (((360 - curHue) * TWOPI) / 360.0);
00835 a += PI / 2.0;
00836 if (a > TWOPI) a -= TWOPI;
00837
00838 b = a + TWOPI/3;
00839 c = b + TWOPI/3;
00840
00841 if (b > TWOPI) b -= TWOPI;
00842 if (c > TWOPI) c -= TWOPI;
00843
00844 double cx = (double) contentsRect().center().x();
00845 double cy = (double) contentsRect().center().y();
00846 double innerRadius = outerRadius - (outerRadius / 5.0);
00847 double pointerRadius = outerRadius - (outerRadius / 10.0);
00848
00849 pa = QPointF(cx + (cos(a) * innerRadius), cy - (sin(a) * innerRadius));
00850 pb = QPointF(cx + (cos(b) * innerRadius), cy - (sin(b) * innerRadius));
00851 pc = QPointF(cx + (cos(c) * innerRadius), cy - (sin(c) * innerRadius));
00852 pd = QPointF(cx + (cos(a) * pointerRadius), cy - (sin(a) * pointerRadius));
00853
00854 selectorPos = pointFromColor(curColor);
00855 update();
00856
00857 internalSetNewColor(curColor);
00858 }
00859
00864 QColor QtColorTriangle::color() const
00865 {
00866 return curColor;
00867 }
00868
00874 double QtColorTriangle::radiusAt(const QPointF &pos, const QRect &rect) const
00875 {
00876 double mousexdist = pos.x() - (double) rect.center().x();
00877 double mouseydist = pos.y() - (double) rect.center().y();
00878 return sqrt(mousexdist * mousexdist + mouseydist * mouseydist);
00879 }
00880
00888 double QtColorTriangle::angleAt(const QPointF &pos, const QRect &rect) const
00889 {
00890 double mousexdist = pos.x() - (double) rect.center().x();
00891 double mouseydist = pos.y() - (double) rect.center().y();
00892 double mouserad = sqrt(mousexdist * mousexdist + mouseydist * mouseydist);
00893 if (mouserad == 0.0)
00894 return 0.0;
00895
00896 double angle = acos(mousexdist / mouserad);
00897 if (mouseydist >= 0)
00898 angle = TWOPI - angle;
00899
00900 return angle;
00901 }
00902
00907 inline double qsqr(double a)
00908 {
00909 return a * a;
00910 }
00911
00916 inline double vlen(double x, double y)
00917 {
00918 return sqrt(qsqr(x) + qsqr(y));
00919 }
00920
00925 inline double vprod(double x1, double y1, double x2, double y2)
00926 {
00927 return x1 * x2 + y1 * y2;
00928 }
00929
00935 bool angleBetweenAngles(double p, double a1, double a2)
00936 {
00937 if (a1 > a2) {
00938 a2 += TWOPI;
00939 if (p < PI) p += TWOPI;
00940 }
00941
00942 return p >= a1 && p < a2;
00943 }
00944
00962 static bool pointAbovePoint(double x, double y, double px, double py,
00963 double ax, double ay, double bx, double by)
00964 {
00965 bool result = false;
00966
00967 if (floor(ax) > floor(bx)) {
00968 if (floor(ay) < floor(by)) {
00969
00970 if (floor(x) < floor(px) || floor(y) < floor(py))
00971 result = true;
00972 } else if (floor(ay) > floor(by)) {
00973
00974 if (floor(x) > floor(px) || floor(y) < floor(py))
00975 result = true;
00976 } else {
00977
00978 if (y < ay) result = true;
00979 }
00980 } else if (floor(ax) < floor(bx)) {
00981 if (floor(ay) < floor(by)) {
00982
00983 if (floor(x) < floor(px) || floor(y) > floor(py))
00984 result = true;
00985 } else if (floor(ay) > floor(by)) {
00986
00987 if (floor(x) > floor(px) || floor(y) > floor(py))
00988 result = true;
00989 } else {
00990
00991 if (y > ay)
00992 result = true;
00993 }
00994 } else {
00995
00996 if (floor(ay) < floor(by)) {
00997 if (x < ax) result = true;
00998 } else if (floor(ay) > floor(by)) {
00999 if (x > ax) result = true;
01000 } else {
01001 if (!(x == ax && y == ay))
01002 result = true;
01003 }
01004 }
01005
01006 return result;
01007 }
01008
01016 static int pointInLine(double x, double y, double ax, double ay,
01017 double bx, double by)
01018 {
01019 if (ax > bx) {
01020 if (ay < by) {
01021
01022
01023
01024
01025 if (y <= ay && x >= ax)
01026 return -1;
01027
01028
01029
01030 if (y >= by && x <= bx)
01031 return 1;
01032 } else {
01033
01034
01035
01036 if (floor(ay) == floor(by)) {
01037
01038
01039
01040 if (x >= ax)
01041 return -1;
01042 else if (x <= bx)
01043 return 1;
01044 } else {
01045
01046
01047 if (y >= ay && x >= ax)
01048 return -1;
01049
01050
01051
01052 if (y <= by && x <= bx)
01053 return 1;
01054 }
01055 }
01056 } else {
01057 if (ay < by) {
01058
01059
01060
01061
01062 if (y <= ay && x <= ax)
01063 return -1;
01064
01065
01066
01067 if (y >= by && x >= bx)
01068 return 1;
01069 } else {
01070
01071
01072
01073 if (floor(ay) == floor(by)) {
01074 if (x <= ax)
01075 return -1;
01076 else if (x >= bx)
01077 return 1;
01078 } else {
01079
01080
01081 if (y >= ay && x <= ax)
01082 return -1;
01083
01084
01085
01086 if (y <= by && x >= bx)
01087 return 1;
01088 }
01089 }
01090 }
01091
01092
01093
01094 return 0;
01095 }
01096
01112 QPointF QtColorTriangle::movePointToTriangle(double x, double y, const Vertex &a,
01113 const Vertex &b, const Vertex &c) const
01114 {
01115
01116
01117
01118 double v1xA = x - a.point.x();
01119 double v1yA = y - a.point.y();
01120 double v2xA = b.point.x() - a.point.x();
01121 double v2yA = b.point.y() - a.point.y();
01122 double vpA = vprod(v1xA, v1yA, v2xA, v2yA);
01123 double cosA = vpA / (vlen(v1xA, v1yA) * vlen(v2xA, v2yA));
01124 double alphaA = acos(cosA);
01125
01126
01127
01128 double v1xB = x - b.point.x();
01129 double v1yB = y - b.point.y();
01130 double v2xB = c.point.x() - b.point.x();
01131 double v2yB = c.point.y() - b.point.y();
01132 double vpB = vprod(v1xB, v1yB, v2xB, v2yB);
01133 double cosB = vpB / (vlen(v1xB, v1yB) * vlen(v2xB, v2yB));
01134 double alphaB = acos(cosB);
01135
01136
01137
01138 double v1xC = x - c.point.x();
01139 double v1yC = y - c.point.y();
01140 double v2xC = a.point.x() - c.point.x();
01141 double v2yC = a.point.y() - c.point.y();
01142 double vpC = vprod(v1xC, v1yC, v2xC, v2yC);
01143 double cosC = vpC / (vlen(v1xC, v1yC) * vlen(v2xC, v2yC));
01144 double alphaC = acos(cosC);
01145
01146
01147
01148
01149 double angleA = angleAt(a.point, contentsRect());
01150 double angleB = angleAt(b.point, contentsRect());
01151 double angleC = angleAt(c.point, contentsRect());
01152 double angleP = angleAt(QPointF(x, y), contentsRect());
01153
01154
01155 if (angleBetweenAngles(angleP, angleA, angleB)) {
01156
01157
01158
01159
01160 double pdist = sqrt(qsqr(x - a.point.x()) + qsqr(y - a.point.y()));
01161
01162
01163 double p0x = a.point.x() + ((b.point.x() - a.point.x()) / vlen(v2xB, v2yB)) * cos(alphaA) * pdist;
01164 double p0y = a.point.y() + ((b.point.y() - a.point.y()) / vlen(v2xB, v2yB)) * cos(alphaA) * pdist;
01165
01166
01167
01168 if (pointAbovePoint(x, y, p0x, p0y, a.point.x(), a.point.y(), b.point.x(), b.point.y())) {
01169
01170
01171 int n = pointInLine(p0x, p0y, a.point.x(), a.point.y(), b.point.x(), b.point.y());
01172 if (n < 0)
01173 return a.point;
01174 else if (n > 0)
01175 return b.point;
01176
01177 return QPointF(p0x, p0y);
01178 }
01179 } else if (angleBetweenAngles(angleP, angleB, angleC)) {
01180
01181 double pdist = sqrt(qsqr(x - b.point.x()) + qsqr(y - b.point.y()));
01182
01183
01184 double p0x = b.point.x() + ((c.point.x() - b.point.x()) / vlen(v2xC, v2yC)) * cos(alphaB) * pdist;
01185 double p0y = b.point.y() + ((c.point.y() - b.point.y()) / vlen(v2xC, v2yC)) * cos(alphaB) * pdist;
01186
01187 if (pointAbovePoint(x, y, p0x, p0y, b.point.x(), b.point.y(), c.point.x(), c.point.y())) {
01188 int n = pointInLine(p0x, p0y, b.point.x(), b.point.y(), c.point.x(), c.point.y());
01189 if (n < 0)
01190 return b.point;
01191 else if (n > 0)
01192 return c.point;
01193 return QPointF(p0x, p0y);
01194 }
01195 } else if (angleBetweenAngles(angleP, angleC, angleA)) {
01196
01197 double pdist = sqrt(qsqr(x - c.point.x()) + qsqr(y - c.point.y()));
01198
01199
01200 double p0x = c.point.x() + ((a.point.x() - c.point.x()) / vlen(v2xA, v2yA)) * cos(alphaC) * pdist;
01201 double p0y = c.point.y() + ((a.point.y() - c.point.y()) / vlen(v2xA, v2yA)) * cos(alphaC) * pdist;
01202
01203 if (pointAbovePoint(x, y, p0x, p0y, c.point.x(), c.point.y(), a.point.x(), a.point.y())) {
01204 int n = pointInLine(p0x, p0y, c.point.x(), c.point.y(), a.point.x(), a.point.y());
01205 if (n < 0)
01206 return c.point;
01207 else if (n > 0)
01208 return a.point;
01209 return QPointF(p0x, p0y);
01210 }
01211 }
01212
01213
01214 return QPointF(x, y);
01215 }
01216
01231 QPointF QtColorTriangle::pointFromColor(const QColor &col) const
01232 {
01233
01234 if (col == Qt::black)
01235 return pb;
01236 else if (col == Qt::white)
01237 return pc;
01238
01239
01240 double ab_deltax = pb.x() - pa.x();
01241 double ab_deltay = pb.y() - pa.y();
01242 double bc_deltax = pc.x() - pb.x();
01243 double bc_deltay = pc.y() - pb.y();
01244 double ac_deltax = pc.x() - pa.x();
01245 double ac_deltay = pc.y() - pa.y();
01246
01247
01248 int hue,sat,val;
01249 col.getHsv(&hue, &sat, &val);
01250
01251
01252
01253 double p1 = pa.x() + (ab_deltax * (double) (255 - val)) / 255.0;
01254 double q1 = pa.y() + (ab_deltay * (double) (255 - val)) / 255.0;
01255 double p2 = pb.x() + (bc_deltax * (double) val) / 255.0;
01256 double q2 = pb.y() + (bc_deltay * (double) val) / 255.0;
01257
01258
01259
01260 double p3 = pa.x() + (ac_deltax * (double) (255 - sat)) / 255.0;
01261 double q3 = pa.y() + (ac_deltay * (double) (255 - sat)) / 255.0;
01262 double p4 = pb.x();
01263 double q4 = pb.y();
01264
01265
01266 double x = 0;
01267 double y = 0;
01268 if (p1 != p2) {
01269 double a = (q2 - q1) / (p2 - p1);
01270 double c = (q4 - q3) / (p4 - p3);
01271 double b = q1 - a * p1;
01272 double d = q3 - c * p3;
01273
01274 x = (d - b) / (a - c);
01275 y = a * x + b;
01276 }
01277 else {
01278 x = p1;
01279 y = q3 + (x - p3) * (q4 - q3) / (p4 - p3);
01280 }
01281
01282 return QPointF(x, y);
01283 }
01284
01292 QColor QtColorTriangle::colorFromPoint(const QPointF &p) const
01293 {
01294
01295 int outerRadius = (contentsRect().width() - 1) / 2;
01296 if ((contentsRect().height() - 1) / 2 < outerRadius)
01297 outerRadius = (contentsRect().height() - 1) / 2;
01298
01299
01300 double cx = (double) contentsRect().center().x();
01301 double cy = (double) contentsRect().center().y();
01302
01303
01304
01305 QPointF pa(cx + (cos(a) * (outerRadius - (outerRadius / 5.0))),
01306 cy - (sin(a) * (outerRadius - (outerRadius / 5.0))));
01307 QPointF pb(cx + (cos(b) * (outerRadius - (outerRadius / 5.0))),
01308 cy - (sin(b) * (outerRadius - (outerRadius / 5.0))));
01309 QPointF pc(cx + (cos(c) * (outerRadius - (outerRadius / 5.0))),
01310 cy - (sin(c) * (outerRadius - (outerRadius / 5.0))));
01311
01312
01313 double angle = a - PI/2.0;
01314 if (angle < 0) angle += TWOPI;
01315 double hue = (360.0 * angle) / TWOPI;
01316
01317
01318
01319 QColor color;
01320 color.setHsv(360 - (int) floor(hue), 255, 255);
01321
01322
01323
01324 Vertex aa(color, pa);
01325 Vertex bb(Qt::black, pb);
01326 Vertex cc(Qt::white, pc);
01327
01328
01329 Vertex *p1 = &aa;
01330 Vertex *p2 = &bb;
01331 Vertex *p3 = &cc;
01332 if (p1->point.y() > p2->point.y()) swap(&p1, &p2);
01333 if (p1->point.y() > p3->point.y()) swap(&p1, &p3);
01334 if (p2->point.y() > p3->point.y()) swap(&p2, &p3);
01335
01336
01337
01338 double p1p2ydist = p2->point.y() - p1->point.y();
01339 double p1p3ydist = p3->point.y() - p1->point.y();
01340 double p2p3ydist = p3->point.y() - p2->point.y();
01341 double p1p2xdist = p2->point.x() - p1->point.x();
01342 double p1p3xdist = p3->point.x() - p1->point.x();
01343 double p2p3xdist = p3->point.x() - p2->point.x();
01344
01345
01346
01347
01348
01349
01350 bool lefty = p1p2xdist < 0;
01351
01352
01353
01354
01355 bool firstshorty = (p.y() >= p1->point.y() && p.y() < p2->point.y());
01356
01357
01358
01359 double leftx;
01360 double rightx;
01361 if (lefty) {
01362 if (firstshorty) {
01363 leftx = p1->point.x();
01364 if (floor(p1p2ydist) != 0.0) {
01365 leftx += (p1p2xdist * (p.y() - p1->point.y())) / p1p2ydist;
01366 } else {
01367 leftx = qMin(p1->point.x(), p2->point.x());
01368 }
01369 } else {
01370 leftx = p2->point.x();
01371 if (floor(p2p3ydist) != 0.0) {
01372 leftx += (p2p3xdist * (p.y() - p2->point.y())) / p2p3ydist;
01373 } else {
01374 leftx = qMin(p2->point.x(), p3->point.x());
01375 }
01376 }
01377
01378 rightx = p1->point.x();
01379 rightx += (p1p3xdist * (p.y() - p1->point.y())) / p1p3ydist;
01380 } else {
01381 leftx = p1->point.x();
01382 leftx += (p1p3xdist * (p.y() - p1->point.y())) / p1p3ydist;
01383
01384 if (firstshorty) {
01385 rightx = p1->point.x();
01386 if (floor(p1p2ydist) != 0.0) {
01387 rightx += (p1p2xdist * (p.y() - p1->point.y())) / p1p2ydist;
01388 } else {
01389 rightx = qMax(p1->point.x(), p2->point.x());
01390 }
01391 } else {
01392 rightx = p2->point.x();
01393 if (floor(p2p3ydist) != 0.0) {
01394 rightx += (p2p3xdist * (p.y() - p2->point.y())) / p2p3ydist;
01395 } else {
01396 rightx = qMax(p2->point.x(), p3->point.x());
01397 }
01398 }
01399 }
01400
01401
01402
01403 double rshort = 0, gshort = 0, bshort = 0;
01404 double rlong = 0, glong = 0, blong = 0;
01405 if (firstshorty) {
01406 if (floor(p1p2ydist) != 0.0) {
01407 rshort = p2->color.r * (p.y() - p1->point.y()) / p1p2ydist;
01408 gshort = p2->color.g * (p.y() - p1->point.y()) / p1p2ydist;
01409 bshort = p2->color.b * (p.y() - p1->point.y()) / p1p2ydist;
01410 rshort += p1->color.r * (p2->point.y() - p.y()) / p1p2ydist;
01411 gshort += p1->color.g * (p2->point.y() - p.y()) / p1p2ydist;
01412 bshort += p1->color.b * (p2->point.y() - p.y()) / p1p2ydist;
01413 } else {
01414 if (lefty) {
01415 if (p1->point.x() <= p2->point.x()) {
01416 rshort = p1->color.r;
01417 gshort = p1->color.g;
01418 bshort = p1->color.b;
01419 } else {
01420 rshort = p2->color.r;
01421 gshort = p2->color.g;
01422 bshort = p2->color.b;
01423 }
01424 } else {
01425 if (p1->point.x() > p2->point.x()) {
01426 rshort = p1->color.r;
01427 gshort = p1->color.g;
01428 bshort = p1->color.b;
01429 } else {
01430 rshort = p2->color.r;
01431 gshort = p2->color.g;
01432 bshort = p2->color.b;
01433 }
01434 }
01435 }
01436 } else {
01437 if (floor(p2p3ydist) != 0.0) {
01438 rshort = p3->color.r * (p.y() - p2->point.y()) / p2p3ydist;
01439 gshort = p3->color.g * (p.y() - p2->point.y()) / p2p3ydist;
01440 bshort = p3->color.b * (p.y() - p2->point.y()) / p2p3ydist;
01441 rshort += p2->color.r * (p3->point.y() - p.y()) / p2p3ydist;
01442 gshort += p2->color.g * (p3->point.y() - p.y()) / p2p3ydist;
01443 bshort += p2->color.b * (p3->point.y() - p.y()) / p2p3ydist;
01444 } else {
01445 if (lefty) {
01446 if (p2->point.x() <= p3->point.x()) {
01447 rshort = p2->color.r;
01448 gshort = p2->color.g;
01449 bshort = p2->color.b;
01450 } else {
01451 rshort = p3->color.r;
01452 gshort = p3->color.g;
01453 bshort = p3->color.b;
01454 }
01455 } else {
01456 if (p2->point.x() > p3->point.x()) {
01457 rshort = p2->color.r;
01458 gshort = p2->color.g;
01459 bshort = p2->color.b;
01460 } else {
01461 rshort = p3->color.r;
01462 gshort = p3->color.g;
01463 bshort = p3->color.b;
01464 }
01465 }
01466 }
01467 }
01468
01469
01470 rlong = p3->color.r * (p.y() - p1->point.y()) / p1p3ydist;
01471 glong = p3->color.g * (p.y() - p1->point.y()) / p1p3ydist;
01472 blong = p3->color.b * (p.y() - p1->point.y()) / p1p3ydist;
01473 rlong += p1->color.r * (p3->point.y() - p.y()) / p1p3ydist;
01474 glong += p1->color.g * (p3->point.y() - p.y()) / p1p3ydist;
01475 blong += p1->color.b * (p3->point.y() - p.y()) / p1p3ydist;
01476
01477
01478
01479
01480
01481 double rl, gl, bl, rr, gr, br;
01482 if (lefty) {
01483 rl = rshort; gl = gshort; bl = bshort;
01484 rr = rlong; gr = glong; br = blong;
01485 } else {
01486 rl = rlong; gl = glong; bl = blong;
01487 rr = rshort; gr = gshort; br = bshort;
01488 }
01489
01490
01491
01492
01493
01494 double xdist = rightx - leftx;
01495 double saxdist = p.x() - leftx;
01496 double saxdist2 = xdist - saxdist;
01497
01498
01499
01500 double r, g, b;
01501 if (xdist != 0.0) {
01502 r = (saxdist2 * rl / xdist) + (saxdist * rr / xdist);
01503 g = (saxdist2 * gl / xdist) + (saxdist * gr / xdist);
01504 b = (saxdist2 * bl / xdist) + (saxdist * br / xdist);
01505 } else {
01506
01507
01508
01509
01510
01511 r = (rl + rr) / 2;
01512 g = (gl + gr) / 2;
01513 b = (bl + br) / 2;
01514 }
01515
01516
01517
01518
01519 int ri = (int) floor(r);
01520 int gi = (int) floor(g);
01521 int bi = (int) floor(b);
01522 if (ri < 0) ri = 0;
01523 else if (ri > 255) ri = 255;
01524 if (gi < 0) gi = 0;
01525 else if (gi > 255) gi = 255;
01526 if (bi < 0) bi = 0;
01527 else if (bi > 255) bi = 255;
01528
01529
01530 return QColor(ri, gi, bi);
01531 }