先看效果:
以上绘制的过程都是基于点绘制的,根据网上查找到的资料修改的:
以下是源码:
class MyBezier : public QMainWindow {
Q_OBJECT
public:
MyBezier(QWidget *parent = Q_NULLPTR);
void mousePressEvent(QMouseEvent *event)override;
void mouseMoveEvent(QMouseEvent*event)override;
void mouseReleaseEvent(QMouseEvent*event)override;
void paintEvent(QPaintEvent *event)override;
private:
QPointF bezierInterpolation(float t, QPointF *points);
void drawBezierCurves(QPointF *points, QPointF *out_points);
void bezier(QVector<QPoint> point);
void pointColor(QImage &image, int x, int y, QColor col);
void pointColorPink(QImage &image, QPoint p);
void drawLine(QImage &image, QPoint pt1, QPoint pt2, QColor col);
void printCross(QImage &image, QPoint pt);
void printAllCross(QImage &image, QVector<QPoint> pt);
private:
Ui::MyBezierClass ui;
QImage* _image = nullptr;
int _width, _height;
QPoint startPt, endPt, currentPt;
QVector<QPoint> _ctrlPoint;//控制点
QVector<QPoint> _bezierPoint;//贝塞尔曲线点
int _pointCount = 0;
int _con = 0;
int _now = 0;
};
#define NUM 9000 //点数
MyBezier::MyBezier(QWidget *parent)
: QMainWindow(parent) {
ui.setupUi(this);
_width = size().width();
_height = size().height();
_image =new QImage(_width, _height, QImage::Format_RGB888);
}
void MyBezier::mousePressEvent(QMouseEvent *event) {
if (event->button() == Qt::RightButton) {
currentPt = event->pos();
_ctrlPoint.push_back(currentPt);
_pointCount++;
if (_pointCount > 2) {
_bezierPoint.clear();
bezier(_ctrlPoint);
}
update();
} else if (event->button() == Qt::LeftButton) {
update();
} else if (event->button() == Qt::MidButton) {
if (_pointCount > 0) {
--_pointCount;
_ctrlPoint.pop_back();
_bezierPoint.clear();
bezier(_ctrlPoint);
update();
}
}
}
void MyBezier::mouseMoveEvent(QMouseEvent*event) {
QPoint p1;
int x, y;
int i;
bool if_in;
if (_pointCount > 0) {
p1 = event->pos();
x = p1.x();
y = p1.y();
if (_now == 0) {
for (i = 0; i < _pointCount; i++) {
if (x > _ctrlPoint[i].x() - 10 && x < _ctrlPoint[i].x() + 10 && y > _ctrlPoint[i].y() - 10 && y < _ctrlPoint[i].y() + 10) {
_now = i;
break;
}
}
}
if (_con > 0 || x > _ctrlPoint[_now].x() - 40 && x < _ctrlPoint[_now].x() + 40 && y > _ctrlPoint[_now].y() - 40 && y < _ctrlPoint[_now].y() + 40) {
if_in = true;
} else {
if_in = false;
}
if (if_in == true) {
_con = 5;
_ctrlPoint[_now].setX(x);
_ctrlPoint[_now].setY(y);
}
if (_pointCount > 2) {
_bezierPoint.clear();
bezier(_ctrlPoint);
}
update();
}
}
void MyBezier::mouseReleaseEvent(QMouseEvent*event) {
_con = 0;
_now = 0;
}
void MyBezier::paintEvent(QPaintEvent *event) {
QPainter painter(this);
_image->fill(QColor(255, 255, 255));
for (int i = 0; i < _pointCount - 1; i++) {
drawLine(*_image, _ctrlPoint[i], _ctrlPoint[i + 1], QColor(0, 0, 255));
}
for (int i = 0; i < _bezierPoint.size(); ++i) {
pointColorPink(*_image, _bezierPoint[i]);
}
printAllCross(*_image, _ctrlPoint);
painter.drawImage(0, 0, *_image);
}
QPointF MyBezier::bezierInterpolation(float t, QPointF *points) {
QPointF tmpPts[300];
for (int i = 1; i < _pointCount; ++i) {
for (int j = 0; j < _pointCount - i; ++j) {
if (i == 1) {
tmpPts[j].setX((float)(points[j].x() * (1 - t) + points[j + 1].x() * t));
tmpPts[j].setY((float)(points[j].y() * (1 - t) + points[j + 1].y() * t));
continue;
}
tmpPts[j].setX ((float)(tmpPts[j].x() * (1 - t) + tmpPts[j + 1].x() * t));
tmpPts[j].setY((float)(tmpPts[j].y() * (1 - t) + tmpPts[j + 1].y() * t));
}
}
return tmpPts[0];
}
void MyBezier::drawBezierCurves(QPointF *points, QPointF *out_points) {
float step = 1.0 / NUM;
float t = 0;
for (int i = 0; i < NUM; i++) {
QPointF tempPt = bezierInterpolation(t, points); // 计算插值点
t += step;
out_points[i] = tempPt;
}
}
void MyBezier::bezier(QVector<QPoint> point) {
QPoint bpoint;
QPointF pointf; // 输入点
int x, y;
QPointF *in = (QPointF *)malloc(_pointCount * sizeof(QPointF));
for (int i = 0; i < _pointCount; i++) {
in[i].setX(point[i].x());
in[i].setY(point[i].y());
}
QPointF out[NUM];
drawBezierCurves(in, out); // 二阶贝塞尔曲线
for (int j = 0; j < NUM; j++){ // 输出路径点
bpoint.setX(out[j].x());
bpoint.setY(out[j].y());
_bezierPoint.push_back(bpoint);
}
free(in);
}
void MyBezier::pointColor(QImage &image, int x, int y, QColor color) {
unsigned char *ptrRow = image.scanLine(y);
ptrRow[x * 3 + 0] = color.red(); //red
ptrRow[x * 3 + 1] = color.green(); //green
ptrRow[x * 3 + 2] = color.blue(); //blue
}
void MyBezier::pointColorPink(QImage &image, QPoint p) {
if (p.x() > 1 && p.x() < _width - 1 && p.y() > 1 && p.y() < _height - 1) {
int x = p.x();
int y = p.y();
unsigned char *ptrRow = image.scanLine(y);
ptrRow[x * 3 + 0] = 0; //red
ptrRow[x * 3 + 1] = 0; //green
ptrRow[x * 3 + 2] = 0; //blue
}
}
void MyBezier::drawLine(QImage &image, QPoint pt1, QPoint pt2, QColor col) {
QPainter painter(&image);
int flag = -1; //1为扫描x,2为扫描y
int x = 0;
int y = 0;
int p1x = pt1.x();
int p1y = pt1.y();
int p2x = pt2.x();
int p2y = pt2.y();
int a, b;
int d, d1;
a = p2x - p1x;
b = p2y - p1y;
if (a >= 0 && b <= 0 && a >= -b || a <= 0 && b >= 0 && -a >= b) {
a = p2x - p1x;
b = p1y - p2y;
d = b - 0.5 * a;
d1 = b - a;
flag = 11;
} else if (a > 0 && b > 0 && a >= b || a < 0 && b < 0 && -a > -b) {
a = p2x - p1x;
b = p2y - p1y;
d = b - 0.5 * a;
d1 = b - a;
flag = 12;
} else if (b >= 0 && a >= 0 && a < b || b <= 0 && a <= 0 && -a < -b) {
b = p1x - p2x;
a = p1y - p2y;
d = b - 0.5 * a;
d1 = b - a;
flag = 21;
} else if (b < 0 && a > 0 && a < -b || b > 0 && a < 0 && -a < b) {
b = p2x - p1x;
a = p1y - p2y;
d = b - 0.5 * a;
d1 = b - a;
flag = 22;
}
if (flag == 11) {
if (p1x < p2x) {
for (x = p1x, y = p1y; x < p2x; x++) {
if (x < 1 || x > _width - 1 || y < 1 || y > _height - 1) {
continue;
}
pointColor(image, x, y, col);
if (d >= 0) {
d += d1;
--y;
} else {
d += b;
}
}
} else {
for (x = p1x, y = p1y; x > p2x; x--) {
if (x < 1 || x > _width - 1 || y < 1 || y > _height - 1) {
continue;
}
pointColor(image, x, y, col);
if (d <= 0) {
d += d1;
++y;
} else {
d += b;
}
}
}
} else if (flag == 12) {
if (p1x < p2x) {
for (x = p1x, y = p1y; x < p2x; x++) {
if (x < 1 || x > _width - 1 || y < 1 || y > _height - 1) {
continue;
}
pointColor(image, x, y, col);
if (d >= 0) {
d += d1;
++y;
} else {
d += b;
}
}
} else {
for (x = p1x, y = p1y; x > p2x; x--) {
if (x < 1 || x > _width - 1 || y < 1 || y > _height - 1) {
continue;
}
pointColor(image, x, y, col);
if (d <= 0) {
d += d1;
--y;
} else {
d += b;
}
}
}
} else if (flag == 21) {
if (p1y < p2y) {
for (x = p1x, y = p1y; y < p2y; y++) {
if (x < 1 || x > _width - 1 || y < 1 || y > _height - 1) {
continue;
}
pointColor(image, x, y, col);
if (d <= 0) {
d += d1;
++x;
} else {
d += b;
}
}
} else {
for (x = p1x, y = p1y; y > p2y; y--) {
if (x < 1 || x > _width - 1 || y < 1 || y > _height - 1) {
continue;
}
pointColor(image, x, y, col);
if (d >= 0) {
d += d1;
--x;
} else {
d += b;
}
}
}
} else if (flag == 22) {
if (p1y < p2y) {
for (x = p1x, y = p1y; y < p2y; y++) {
if (x < 1 || x > _width - 1 || y < 1 || y > _height - 1) {
continue;
}
pointColor(image, x, y, col);
if (d <= 0) {
d += d1;
--x;
} else {
d += b;
}
}
} else {
for (x = p1x, y = p1y; y > p2y; y--) {
if (x < 1 || x > _width - 1 || y < 1 || y > _height - 1) {
continue;
}
pointColor(image, x, y, col);
if (d >= 0) {
d += d1;
++x;
} else {
d += b;
}
}
}
}
}
void MyBezier::printCross(QImage &image, QPoint pt) {
QPoint ptup = pt, ptdown = pt, ptleft = pt, ptright = pt;
ptup.setY(pt.y() + 5);
ptdown.setY(pt.y() - 5);
ptleft.setX(pt.x() - 5);
ptright.setX(pt.x() + 5);
drawLine(image, ptleft, ptright, QColor(0,255,255));
drawLine(image, ptup, ptdown, QColor(255, 0, 255));
}
void MyBezier::printAllCross(QImage &image, QVector<QPoint> pt) {
for (int i = 0; i < _pointCount; i++) {
printCross(image, _ctrlPoint[i]);
}
}
aaa