Excessive curve plotted points in QT

Drawing too many points of the curve is significant. But through trial, QT's PainterPath not very smug. When a multi-region surrounded by the curve, the area PainterPath does not contain all of the region, and the area under the curve containing only the chord thereof.

To solve this problem, use the following method:

1. bezier curve generates its own set of points

2. The plurality of bezier curves associated head and tail, the whole set of points forming a polygon

3. The polygon into a PainterPath, and draw;

4. The PainterPath left to return next use.

Here is the code:

1. header graphic.h

#ifndef GRAPHIC_H
#define GRAPHIC_H
#include <QPainter>
#include <QPoint>
#include <QColor>
#include <QVector>
// step is the step size, i.e., the amount of each increment t, traceSet returns all points of this curve is generated
void getBezier3(const QPointF& startPos, const QPointF& controlPos1, const QPointF& controlPos2, const QPointF& endPos,
                const double step, QVector<QPointF>& traceSet);
// draw a polygonal external profile, is the set of vertices of polygons Points, CCW direction or CW; k_c sharpness junction is, the larger the smoother, typically selected 0.6; path is the amount of return, which is an external profile comprising a All points of the polygon area, can be used
// test whether a point in this area, the two areas intersect, or the like, may also be drawn to complete the path.
void drawEncloseCurve(QPainter& painter, const QVector<QPoint>& points, float k_c, const QColor& color, int strokWidth, QPainterPath& path);
#endif // GRAPHIC_H

2. Draw achieve graphic.cpp

#include "graphic.h"
// seek distance between two points
double distance(const QPoint& p1, const QPoint& p2)
{
        return sqrt(((p1.x() - p2.x()) * (p1.x() - p2.x()) + (p1.y() - p2.y()) * (p1.y() - p2.y())));
}
// adjust the location of the point according to the ratio
QPoint ratioPointConvert(const QPoint& p1, const QPoint& p2, const double ratio)
{
        QPoint p;
        p.setX((int) (ratio * (p1.x() - p2.x()) + p2.x()));
        p.setY ((int) (* ratio (p1.y () - p2.y ()) + p2.y ()));
        return p;
}
 
void getBezier3(const QPointF& startPos, const QPointF& controlPos1, const QPointF& controlPos2, const QPointF& endPos,
                const double step, QVector<QPointF>& traceSet)
{
    double t = 0.0;
    double x_t, y_t;
    while (t <= 1.0) {
        x_t = startPos.x() * (1 - t) * (1 - t) * (1 - t) + 3 * controlPos1.x() * t * (1 - t) * (1 - t) + 3 * controlPos2.x() * t * t * (1 - t) + endPos.x() * t * t * t;
        y_t = startPos.y() * (1 - t) * (1 - t) * (1 - t) + 3 * controlPos1.y() * t * (1 - t) * (1 - t) + 3 * controlPos2.y() * t * t * (1 - t) + endPos.y() * t * t * t;
        traceSet.push_back(QPointF(x_t, y_t));
        t += step;
    }
}
 
void drawEncloseCurve(QPainter& painter, const QVector<QPoint>& points, float k_c, const QColor& color, int strokWidth, QPainterPath& path)
{
    //path.clear();
    int size = points.size();
    QVector<QPoint> midpoints;
    // Calculate the midpoint
    for(int i = 0; i < size; i++)
    {
        int j = (i + 1) % size;
        midpoints.push_back(QPoint((points[i].x() + points[j].x()) / 2, (points[i].y() + points[j].y()) / 2));
    }
    // Calculate the ratio point
    QVector<QPoint> ratioPoints;
    for(int i = 0; i < size; i++)
    {
        int j = (i + 1) % size;
        int m = (i + 2) % size;
        double l1 = distance(points[i], points[j]);
        double l2 = distance(points[j], points[m]);
        double ratio = l1 / (l1 + l2);
        ratioPoints.push_back(ratioPointConvert(midpoints[i], midpoints[j], ratio));
    }
 
    // moving segment, calculated control point
    QVector<QPoint> controlPoints;
    for (int i = 0; i < size; i++)
    {
        QPoint ratioPoint = ratioPoints[i];
        QPoint verPoint = points[(i + 1) % size];
        int dx = ratioPoint.x() - verPoint.x();
        int dy = ratioPoint.y() - verPoint.y();
        QPoint controlPoint1 = QPoint(midpoints[i].x() - dx, midpoints[i].y() - dy);
        QPoint controlPoint2 = QPoint(midpoints[(i + 1) % size].x() - dx, midpoints[(i + 1) % size].y() - dy);
        controlPoints.push_back(ratioPointConvert(controlPoint1, verPoint, k_c));
        controlPoints.push_back(ratioPointConvert(controlPoint2, verPoint, k_c));
    }
 
    // vertices connected with the third-order Bezier curve
    //QPainterPath path;
    QVector<QPointF> polypoints;
    QPen pen;
    pen.setColor(color);
    pen.setWidth(strokWidth);
    pen.setCapStyle(Qt::RoundCap);
    pen.setJoinStyle(Qt::RoundJoin);
    painter.setPen(pen);
 
    for (int i = 0; i < size; i++)
    {
        QPoint startPoint = points[i];
        QPoint endPoint = points[(i + 1) % size];
        QPoint controlPoint1 = controlPoints[(i * 2 + controlPoints.size() - 1) % controlPoints.size()];
        QPoint controlPoint2 = controlPoints[(i * 2) % controlPoints.size()];
//        path.moveTo(startPoint.x(), startPoint.y());
//        path.cubicTo(controlPoint1.x(), controlPoint1.y(), controlPoint2.x(), controlPoint2.y(), endPoint.x(), endPoint.y());
        QVector<QPointF> bezier;
        getBezier3(startPoint, controlPoint1, controlPoint2, endPoint, 0.01, bezier);
        bezier.removeLast();
        polypoints += bezier;
    }
    QPolygonF poly (polypoints);
    path.addPolygon(poly);
    painter.drawPath(path);
}

3. Test (mainwindow.cpp)

When testing found the problem: When Qdebug () << input Chinese, debugging directly jump away, unable to continue stepping into English but if there is no problem.

void MainWindow::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    // Draw a closed curve external
    painter.setRenderHint(QPainter::Antialiasing, true);
    QVector<QPoint> points;
    points.push_back(QPoint(200, 200));
    points.push_back(QPoint(400, 100));
    points.push_back(QPoint(600, 200));
    points.push_back(QPoint(400, 400));
    drawEncloseCurve(painter, points, 0.6, QColor(Qt::black), 2, npath);
 
    painter.save();
    painter.translate(400, 0);
    painter.fillPath(npath, QBrush(Qt::green));
    painter.restore (); 
}

test whether this region in the mouse
void MainWindow::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        QPointF p = event->pos();
        if(npath.contains(p))
            qDebug() << ("you hit it path");
        // pass the test, and sometimes ineffective npath test, but always effective poly
        QPolygonF poly = npath.toFillPolygon ();
 
        if(poly.containsPoint(p, Qt::WindingFill))
        {
            qDebug() << ("you hit it poly");
            startDrawing = false;
        }
        else
        {
            startDrawing = true;
            startPos = event->pos();
        }
    }
}

4. Results: 
By closed curve four points, and by the mouse to select the test

 

 

 

Guess you like

Origin www.cnblogs.com/myboat/p/11535760.html