利用Qt判断点是否在直线上

在计算机集合中一个常用的功能就是判断交集的关系,点是否在直线上也是常用的一种判断关系。

点是否在直线上使用的算法有两个:
1.利用向量的叉积来计算:
a.构成线段的两点 A (x1,y2)和 B (x2,y2)和点C(x,y)
b.线段的向量(x2-x1,y2-y1)
c.p点和p2构成的向量:(x2-x,y2-y)
d.这两个向量的叉积等于:(x2-x1)(y2-y)-(x2-x)(y2-y1)
结果:等于0则者三点在同一条直线上
e.在利用C点是否在以点A和点B构成的矩形内,判断C点在线段AB上还是在AB的线段外

2.利用距离和来计算:
a.计算出线段AB的长度
b.计算出AC的长度和BC的长度
c.如果AB=AC+BC,则说明C点在线段AB上

先看一下实现的效果:
在这里插入图片描述

定义直线:

#pragma once
#include <QPointF>
#include <QColor>
//线段

class LineSeg {
public:
	LineSeg();
	~LineSeg();

	inline void setStartPoint(QPointF pt) {
		_ptStart = pt;
	}

	inline void setEndPoint(QPointF pt) {
		_ptEnd = pt;
	}

	inline QPointF&getStartPoint() {
		return _ptStart;
	}

	inline QPointF&getEndPoint() {
		return _ptEnd;
	}

	inline void setLineColor(QColor color) {
		_color = color;
	}

	inline QColor&getLineColor() {
		return _color;
	}

	inline void setLineWidth(int w) {
		_width = w;
	}
	inline int&getLineWidth() {
		return _width;
	}

	QPointF getVector();//获取线段的向量
	double getLength();//获取线段的长度
private:
	QPointF _ptStart;//线段的起点
	QPointF _ptEnd;//线段的终点

	QColor _color = QColor(255, 0, 0);
	int _width = 2;
};


#include "LineSeg.h"

LineSeg::LineSeg() {
}


LineSeg::~LineSeg() {
}

QPointF LineSeg::getVector() {
	return QPointF(_ptEnd.x() - _ptStart.x(), _ptEnd.y() - _ptStart.y());
}

double LineSeg::getLength() {
	return sqrt((_ptEnd.x() - _ptStart.x())*(_ptEnd.x() - _ptStart.x()) + (_ptEnd.y() - _ptStart.y())*(_ptEnd.y() - _ptStart.y()));
}

定义鼠标事件:

#pragma once

#include <QtWidgets/QMainWindow>
#include <QVector>
#include <QPen>
#include <QMenu>

#include "ui_QtGuiGeoPointInLine.h"

class QMouseEvent;
class LineSeg;

class QtGuiGeoPointInLine : public QMainWindow {
	Q_OBJECT

public:
	QtGuiGeoPointInLine(QWidget *parent = Q_NULLPTR);
private:
	void mousePressEvent(QMouseEvent *event)override;
	void mouseMoveEvent(QMouseEvent *event)override;
	void mouseReleaseEvent(QMouseEvent *event)override;

	void paintEvent(QPaintEvent *event)override;

	bool isInLine(QPointF&pt,LineSeg*line);

private slots:
	void slotActionPoint();
private:
	Ui::QtGuiGeoPointInLineClass ui;

	QPen _pen;
	bool _lbtnDown = false;
	QVector<LineSeg*> _lines;

	LineSeg* _oneLine = nullptr;

	QMenu* _menu = nullptr;
	QAction* _action = nullptr;
	bool _isStartPointInLine = false;
};

#include<QMouseEvent>
#include<QPainter>
#include<QRectF>
#include<QDebug>

#include "QtGuiGeoPointInLine.h"
#include "LineSeg.h"

QtGuiGeoPointInLine::QtGuiGeoPointInLine(QWidget *parent)
	: QMainWindow(parent) {
	ui.setupUi(this);
	ui.centralWidget->setMouseTracking(true);
	setMouseTracking(true);

	_pen.setStyle(Qt::SolidLine);

	_menu = new QMenu(QStringLiteral("测试"));
	_action = new QAction(QStringLiteral("点"));
	connect(_action, SIGNAL(triggered()), this, SLOT(slotActionPoint()));
	_menu->addAction(_action);
	ui.menuBar->addMenu(_menu);
}

void QtGuiGeoPointInLine::mousePressEvent(QMouseEvent *event) {

	switch (event->button()) {
	case Qt::LeftButton:
		_lbtnDown = true;
		_oneLine = new LineSeg;
		_oneLine->setStartPoint(event->localPos());
		_oneLine->setEndPoint(event->localPos());
		break;
	}
	update();
}

void QtGuiGeoPointInLine::mouseMoveEvent(QMouseEvent *event) {
	QPointF ptMove = event->localPos();

	if (_lbtnDown) {
		_oneLine->setEndPoint(ptMove);
	}
	if (_isStartPointInLine) {
		for (auto v : _lines) {
			if (isInLine(ptMove, v)) {
				v->setLineWidth(5);
			} else {
				v->setLineWidth(2);
			}
		}
	}
	update();
}

void QtGuiGeoPointInLine::mouseReleaseEvent(QMouseEvent *event) {
	switch (event->button()) {
	case Qt::LeftButton:
		_lbtnDown = false;
		_oneLine->setEndPoint(event->pos());
		_lines.push_back(_oneLine);
		break;
	}
	update();
}

void QtGuiGeoPointInLine::paintEvent(QPaintEvent *event) {
	QPainter painter(this);
	painter.setRenderHint(QPainter::Antialiasing, true);  //设置渲染,启动反锯齿
	
	int numLine = _lines.size();
	for (auto v:_lines){
		_pen.setColor(v->getLineColor());
		_pen.setWidth(v->getLineWidth());
		painter.setPen(_pen);
		painter.drawLine(v->getStartPoint(), v->getEndPoint());
	}
	//绘制弹簧线条
	if (_lbtnDown){
		painter.drawLine(_oneLine->getStartPoint(), _oneLine->getEndPoint());
	}
}

bool QtGuiGeoPointInLine::isInLine(QPointF&pt, LineSeg*line) {
#if 0//利用叉积计算
	QPointF v1 = QPointF(pt.x() - line->getEndPoint().x(), pt.y() - line->getEndPoint().y());
	QPointF v2 = line->getVector();

	double v3 = v1.x()*v2.y() - v1.y()*v2.x();

	qDebug() << "v1 = " << v1 << "  v2 = " << v2 << "  v3 = " << v3;

	QRectF rect(line->getStartPoint(), line->getEndPoint());

	if (abs(v3) < 1e-8 &&rect.contains(pt.toPoint())) {
		return true;
	}
	return false;
#else//点如果在线段上,则点到线段两个端点之间的距离和等于线段的长度

	double len1 = sqrt((line->getStartPoint().x() - pt.x())*(line->getStartPoint().x() - pt.x()) + (line->getStartPoint().y() - pt.y())*(line->getStartPoint().y() - pt.y()));
	double len2 = sqrt((line->getEndPoint().x() - pt.x())*(line->getEndPoint().x() - pt.x()) + (line->getEndPoint().y() - pt.y())*(line->getEndPoint().y() - pt.y()));

	double lenLine = line->getLength();
	qDebug() << "line->getLength() = " << lenLine << "  len1 + len2 = " << len1 + len2;
	if (lenLine + 0.01 >= (len1+len2)&& (len1 + len2)>= lenLine)	{
		return true;
	}else {
		return false;
	}

#endif
}

void QtGuiGeoPointInLine::slotActionPoint() {
	_isStartPointInLine = !_isStartPointInLine;
	if (_isStartPointInLine){
		setCursor(Qt::CrossCursor);
	} else {
		setCursor(Qt::ArrowCursor);
	}
}


主函数调用:

#include "QtGuiGeoPointInLine.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	QtGuiGeoPointInLine w;
	w.show();
	return a.exec();
}

aaa

  • 1
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
判断一个是否直线上,您可以使用以下方法: 1. 获取直线的两个端坐标,假设它们是 (x1, y1) 和 (x2, y2)。 2. 获取的坐标,假设它是 (x, y)。 3. 计算 (x, y) 到直线 (x1, y1) - (x2, y2) 的垂线的垂足坐标 (xv, yv),可以使用以下公式计算: ``` xv = ((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1)) / ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) * (x2 - x1) + x1; yv = ((x - x1) * (y2 - y1) - (y - y1) * (x2 - x1)) / ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) * (y2 - y1) + y1; ``` 4. 如果 (xv, yv) 在直线的端之间,那么 (x, y) 就在直线上。 以下是一个示例代码,演示如何判断一个是否直线上: ```cpp QPointF lineStart = lineItem->line().p1(); QPointF lineEnd = lineItem->line().p2(); QPointF point = QPointF(x, y); // Calculate the projection of the point onto the line qreal xv = ((point.x() - lineStart.x()) * (lineEnd.x() - lineStart.x()) + (point.y() - lineStart.y()) * (lineEnd.y() - lineStart.y())) / ((lineEnd.x() - lineStart.x()) * (lineEnd.x() - lineStart.x()) + (lineEnd.y() - lineStart.y()) * (lineEnd.y() - lineStart.y())) * (lineEnd.x() - lineStart.x()) + lineStart.x(); qreal yv = ((point.x() - lineStart.x()) * (lineEnd.y() - lineStart.y()) - (point.y() - lineStart.y()) * (lineEnd.x() - lineStart.x())) / ((lineEnd.x() - lineStart.x()) * (lineEnd.x() - lineStart.x()) + (lineEnd.y() - lineStart.y()) * (lineEnd.y() - lineStart.y())) * (lineEnd.y() - lineStart.y()) + lineStart.y(); // Check if the projection is between the endpoints of the line if (xv >= qMin(lineStart.x(), lineEnd.x()) && xv <= qMax(lineStart.x(), lineEnd.x()) && yv >= qMin(lineStart.y(), lineEnd.y()) && yv <= qMax(lineStart.y(), lineEnd.y())) { qDebug() << "The point is on the line."; } else { qDebug() << "The point is not on the line."; } ``` 请注意,此示例假定您已经有了一个 QGraphicsLineItem 对象,其中包含了您要查找的直线。还要注意,此示例中的坐标均为浮数。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

wb175208

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

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

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

打赏作者

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

抵扣说明:

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

余额充值