贝塞尔曲线的绘制

16 篇文章 2 订阅

先看效果:
在这里插入图片描述
以上绘制的过程都是基于点绘制的,根据网上查找到的资料修改的:
以下是源码:

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

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wb175208

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值