コード例 #1
0
ファイル: qtcolortriangle.cpp プロジェクト: dmt4/klf5
/*!
    \internal

    When the left mouse button is pressed, this function determines
    what part of the color triangle the cursor is, and from that it
    initiates either selecting the hue (outside the triangle's area)
    or the saturation/value (inside the triangle's area).
*/
void QtColorTriangle::mousePressEvent(QMouseEvent *e)
{
    // Only respond to the left mouse button.
    if (e->button() != Qt::LeftButton)
	return;

    QPointF depos((double) e->pos().x(), (double) e->pos().y());
    double rad = radiusAt(depos, contentsRect());
    bool newColor = false;

    // As in mouseMoveEvent, either find the a,b,c angles or the
    // radian position of the selector, then order an update.
    if (rad > (outerRadius - (outerRadius / 5))) {
	selMode = SelectingHue;

	a = angleAt(depos, contentsRect());
	b = a + TWOPI / 3.0;
	c = b + TWOPI / 3.0;
	if (b > TWOPI) b -= TWOPI;
	if (c > TWOPI) c -= TWOPI;

	double am = a - PI/2;
	if (am < 0) am += TWOPI;

	curHue = 360 - (int) ((am * 360.0) / TWOPI);
	int h,s,v;
	curColor.getHsv(&h, &s, &v);

	if (h != curHue) {
	    newColor = true;
	    curColor.setHsv(curHue, s, v, curColor.alpha());
	}

	double cx = (double) contentsRect().center().x();
	double cy = (double) contentsRect().center().y();

	pa = QPointF(cx + (cos(a) * (outerRadius - (outerRadius / 5.0))),
			 cy - (sin(a) * (outerRadius - (outerRadius / 5.0))));
	pb = QPointF(cx + (cos(b) * (outerRadius - (outerRadius / 5.0))),
			 cy - (sin(b) * (outerRadius - (outerRadius / 5.0))));
	pc = QPointF(cx + (cos(c) * (outerRadius - (outerRadius / 5.0))),
			 cy - (sin(c) * (outerRadius - (outerRadius / 5.0))));
	pd = QPointF(cx + (cos(a) * (outerRadius - (outerRadius / 10.0))),
			 cy - (sin(a) * (outerRadius - (outerRadius / 10.0))));

	selectorPos = pointFromColor(curColor);
	internalSetNewColor(curColor);
    } else {
	selMode = SelectingSatValue;

	Vertex aa(Qt::black, pa);
	Vertex bb(Qt::black, pb);
	Vertex cc(Qt::black, pc);

	Vertex *p1 = &aa;
	Vertex *p2 = &bb;
	Vertex *p3 = &cc;
	if (p1->point.y() > p2->point.y()) swap(&p1, &p2);
	if (p1->point.y() > p3->point.y()) swap(&p1, &p3);
	if (p2->point.y() > p3->point.y()) swap(&p2, &p3);

	selectorPos = movePointToTriangle(depos.x(), depos.y(), aa, bb, cc);
	QColor col = colorFromPoint(selectorPos);
	if (col != curColor) {
	    int tempalpha = curColor.alpha();
	    curColor = col;
	    curColor.setAlpha(tempalpha);
	    newColor = true;
	}
    }

    if (newColor)
	internalSetNewColor(curColor);

    update();
}
コード例 #2
0
ファイル: qtcolortriangle.cpp プロジェクト: dmt4/klf5
/*! \internal

    \a a, \a b and \a c are corner points of an equilateral triangle.
    (\a x,\a y) is an arbitrary point inside or outside this triangle.

    If (x,y) is inside the triangle, this function returns the double
    point (x,y).

    Otherwise, the intersection of the perpendicular projection of
    (x,y) onto the closest triangle edge is returned, unless this
    intersection is outside the triangle's bounds, in which case the
    corner closest to the intersection is returned instead.

    Yes, it's trigonometry.
*/
QPointF QtColorTriangle::movePointToTriangle(double x, double y, const Vertex &a,
					       const Vertex &b, const Vertex &c) const
{
    // Let v1A be the vector from (x,y) to a.
    // Let v2A be the vector from a to b.
    // Find the angle alphaA between v1A and v2A.
    double v1xA = x - a.point.x();
    double v1yA = y - a.point.y();
    double v2xA = b.point.x() - a.point.x();
    double v2yA = b.point.y() - a.point.y();
    double vpA = vprod(v1xA, v1yA, v2xA, v2yA);
    double cosA = vpA / (vlen(v1xA, v1yA) * vlen(v2xA, v2yA));
    double alphaA = acos(cosA);

    // Let v1B be the vector from x to b.
    // Let v2B be the vector from b to c.
    double v1xB = x - b.point.x();
    double v1yB = y - b.point.y();
    double v2xB = c.point.x() - b.point.x();
    double v2yB = c.point.y() - b.point.y();
    double vpB = vprod(v1xB, v1yB, v2xB, v2yB);
    double cosB = vpB / (vlen(v1xB, v1yB) * vlen(v2xB, v2yB));
    double alphaB = acos(cosB);

    // Let v1C be the vector from x to c.
    // Let v2C be the vector from c back to a.
    double v1xC = x - c.point.x();
    double v1yC = y - c.point.y();
    double v2xC = a.point.x() - c.point.x();
    double v2yC = a.point.y() - c.point.y();
    double vpC = vprod(v1xC, v1yC, v2xC, v2yC);
    double cosC = vpC / (vlen(v1xC, v1yC) * vlen(v2xC, v2yC));
    double alphaC = acos(cosC);

    // Find the radian angles between the (1,0) vector and the points
    // A, B, C and (x,y). Use this information to determine which of
    // the edges we should project (x,y) onto.
    double angleA = angleAt(a.point, contentsRect());
    double angleB = angleAt(b.point, contentsRect());
    double angleC = angleAt(c.point, contentsRect());
    double angleP = angleAt(QPointF(x, y), contentsRect());

    // If (x,y) is in the a-b area, project onto the a-b vector.
    if (angleBetweenAngles(angleP, angleA, angleB)) {
	// Find the distance from (x,y) to a. Then use the slope of
	// the a-b vector with this distance and the angle between a-b
	// and a-(x,y) to determine the point of intersection of the
	// perpendicular projection from (x,y) onto a-b.
	double pdist = sqrt(qsqr(x - a.point.x()) + qsqr(y - a.point.y()));

        // the length of all edges is always > 0
	double p0x = a.point.x() + ((b.point.x() - a.point.x()) / vlen(v2xB, v2yB)) * cos(alphaA) * pdist;
	double p0y = a.point.y() + ((b.point.y() - a.point.y()) / vlen(v2xB, v2yB)) * cos(alphaA) * pdist;

	// If (x,y) is above the a-b line, which basically means it's
	// outside the triangle, then return its projection onto a-b.
	if (pointAbovePoint(x, y, p0x, p0y, a.point.x(), a.point.y(), b.point.x(), b.point.y())) {
	    // If the projection is "outside" a, return a. If it is
	    // outside b, return b. Otherwise return the projection.
	    int n = pointInLine(p0x, p0y, a.point.x(), a.point.y(), b.point.x(), b.point.y());
	    if (n < 0)
		return a.point;
	    else if (n > 0)
		return b.point;

	    return QPointF(p0x, p0y);
	}
    } else if (angleBetweenAngles(angleP, angleB, angleC)) {
	// If (x,y) is in the b-c area, project onto the b-c vector.
	double pdist = sqrt(qsqr(x - b.point.x()) + qsqr(y - b.point.y()));

        // the length of all edges is always > 0
        double p0x = b.point.x() + ((c.point.x() - b.point.x()) / vlen(v2xC, v2yC)) * cos(alphaB) * pdist;
	double p0y = b.point.y() + ((c.point.y() - b.point.y()) / vlen(v2xC, v2yC)) * cos(alphaB) * pdist;

	if (pointAbovePoint(x, y, p0x, p0y, b.point.x(), b.point.y(), c.point.x(), c.point.y())) {
	    int n = pointInLine(p0x, p0y, b.point.x(), b.point.y(), c.point.x(), c.point.y());
	    if (n < 0)
		return b.point;
	    else if (n > 0)
		return c.point;
	    return QPointF(p0x, p0y);
	}
    } else if (angleBetweenAngles(angleP, angleC, angleA)) {
	// If (x,y) is in the c-a area, project onto the c-a vector.
	double pdist = sqrt(qsqr(x - c.point.x()) + qsqr(y - c.point.y()));

        // the length of all edges is always > 0
        double p0x = c.point.x() + ((a.point.x() - c.point.x()) / vlen(v2xA, v2yA)) * cos(alphaC) * pdist;
	double p0y = c.point.y() + ((a.point.y() - c.point.y()) / vlen(v2xA, v2yA)) * cos(alphaC) * pdist;

	if (pointAbovePoint(x, y, p0x, p0y, c.point.x(), c.point.y(), a.point.x(), a.point.y())) {
	    int n = pointInLine(p0x, p0y, c.point.x(), c.point.y(), a.point.x(), a.point.y());
	    if (n < 0)
		return c.point;
	    else if (n > 0)
		return a.point;
	    return QPointF(p0x, p0y);
	}
    }

    // (x,y) is inside the triangle (inside a-b, b-c and a-c).
    return QPointF(x, y);
}
コード例 #3
0
ファイル: qtcolortriangle.cpp プロジェクト: dmt4/klf5
/*!
    \internal

    Selects new hue or saturation/value values, depending on where the
    mouse button was pressed initially.
*/
void QtColorTriangle::mouseMoveEvent(QMouseEvent *e)
{
    if ((e->buttons() & Qt::LeftButton) == 0)
        return;

    QPointF depos((double) e->pos().x(), (double) e->pos().y());
    bool newColor = false;

    if (selMode == SelectingHue) {
	// If selecting hue, find the new angles for the points a,b,c
	// of the triangle. The following update() will then redraw
	// the triangle.
	a = angleAt(depos, contentsRect());
	b = a + TWOPI / 3.0;
	c = b + TWOPI / 3.0;
	if (b > TWOPI) b -= TWOPI;
	if (c > TWOPI) c -= TWOPI;

	double am = a - PI/2;
	if (am < 0) am += TWOPI;

	curHue = 360 - (int) (((am) * 360.0) / TWOPI);
	int h,s,v;
	curColor.getHsv(&h, &s, &v);

	if (curHue != h) {
	    newColor = true;
	    curColor.setHsv(curHue, s, v, curColor.alpha());
	}

	double cx = (double) contentsRect().center().x();
	double cy = (double) contentsRect().center().y();

	pa = QPointF(cx + (cos(a) * (outerRadius - (outerRadius / 5.0))),
                     cy - (sin(a) * (outerRadius - (outerRadius / 5.0))));
	pb = QPointF(cx + (cos(b) * (outerRadius - (outerRadius / 5.0))),
                     cy - (sin(b) * (outerRadius - (outerRadius / 5.0))));
	pc = QPointF(cx + (cos(c) * (outerRadius - (outerRadius / 5.0))),
                     cy - (sin(c) * (outerRadius - (outerRadius / 5.0))));
	pd = QPointF(cx + (cos(a) * (outerRadius - (outerRadius / 10.0))),
                     cy - (sin(a) * (outerRadius - (outerRadius / 10.0))));

	selectorPos = pointFromColor(curColor);
    } else {
	Vertex aa(Qt::black, pa);
	Vertex bb(Qt::black, pb);
	Vertex cc(Qt::black, pc);

	Vertex *p1 = &aa;
	Vertex *p2 = &bb;
	Vertex *p3 = &cc;
	if (p1->point.y() > p2->point.y()) swap(&p1, &p2);
	if (p1->point.y() > p3->point.y()) swap(&p1, &p3);
	if (p2->point.y() > p3->point.y()) swap(&p2, &p3);

	selectorPos = movePointToTriangle(depos.x(), depos.y(), aa, bb, cc);
	QColor col = colorFromPoint(selectorPos);
	if (col != curColor) {
	    // Ensure that hue does not change when selecting
	    // saturation and value.
	    int h,s,v;
	    col.getHsv(&h, &s, &v);
	    curColor.setHsv(curHue, s, v, curColor.alpha());
	    newColor = true;
	}
    }

    if (newColor)
	internalSetNewColor(curColor);

    update();
}
コード例 #4
0
void LineListLabel::draw()
{
    const Projector *proj = SkyMap::Instance()->projector();

    double comfyAngle = 40.0;  // the first valid candidate with an angle
    // smaller than this gets displayed.  If you set
    // this to > 90. then the first valid candidate
    // will be displayed, regardless of angle.

    // We store info about the four candidate points in arrays to make several
    // of the steps easier, particularly choosing the valid candidate with the
    // smallest angle from the horizontal.

    int		  idx[4];								  // index of candidate
    LineList* list[4];								  // LineList of candidate
    double	  a[4] = { 360.0, 360.0, 360.0, 360.0 };  // angle, default to large value
    QPointF	  o[4];								      // candidate point
    bool	  okay[4] = { true, true, true, true };	  // flag  candidate false if it
    // overlaps a previous label.

    // We no longer adjust the order but if we were to it would be here
    static int Order[4]  =
    { LeftCandidate, BotCandidate, TopCandidate, LeftCandidate };

    for ( int j = 0; j < 4; j++ ) {
        idx[j]	= m_labIndex[ Order[ j ] ];
        list[j] = m_labList[  Order[ j ] ];
    }

    // Make sure start with a valid candidate
    int first = 0;
    for ( ; first < 4; first++ ) {
        if ( idx[first] ) break;
    }

    // return if there are no valid candidates
    if ( first >= 4 ) return;


    // Try the points in order and print the label if we can draw it at
    // a comfortable angle for viewing;
    for ( int j = first; j < 4; j++ ) {
        o[j] = angleAt( proj, list[j], idx[j], &a[j] );

        if ( ! idx[j] || ! proj->checkVisibility( list[j]->at( idx[j] ) ) ) {
            okay[j] = false;
            continue;
        }

        if ( fabs( a[j] ) > comfyAngle )
            continue;

        if ( m_skyLabeler->drawGuideLabel( o[j], m_text, a[j] ) )
            return;

        okay[j] = false;
    }

    //--- No angle was comfy so pick the one with the smallest angle ---

    // Index of the index/angle/point that gets displayed
    int best = first;

    // find first valid candidate that does not overlap existing labels
    for ( ; best < 4; best++ ) {
        if ( idx[best] && okay[best] ) break;
    }

    // return if all candiates either overlap or are invalid
    if ( best >= 4 ) return;

    // find the valid non-overlap candidate with the smallest angle
    for ( int j = best + 1; j < 4; j++ ) {
        if ( idx[j] && okay[j] && fabs(a[j]) < fabs(a[best]) ) best = j;
    }

    m_skyLabeler->drawGuideLabel( o[best], m_text, a[best] );
}