思想记录--QWT如何绘制切线?

本文介绍了一种在QWT中实现数据点切线绘制的方法。通过选取数据点及其相邻点来确定切线的斜率,并据此计算切线的解析式。文章详细描述了如何根据鼠标点击位置匹配数据点,并讨论了不同情况下相邻点的选择策略。

本文需要结合此文观看:QWT如果点选数据?

一、效果展示

在这里插入图片描述


本文需要结合此文观看:QWT如果点选数据?

二、切线绘制思想

2.1、原理

策略:根据切点、切点的左相邻点和切点的右相邻点三个点,来求切线

在这里插入图片描述

已知左相邻点n1(x1, y1),右相邻点n2(x2, y2),和切点m(x, y),根据n1和n2可求出y = k1 * x + b1;

此时的n1n2线段平移到红线处就是切线,所以切线的斜率和n1n2线段的斜率相等,即k = k1;

然后再代入切点的坐标,求出b,则可求出切线的解析式,然后根据解析式确定起点和终点即可绘制出切线;


2.2、具体操作

取出数据

  • 首先定位到一个数据点m
  • 然后去定位该数据点的左相邻点n1右相邻点n2
    • 如果m是第一个节点里的第一个点,则n1=m;
    • 如果m是最后一个节点里的最后一个点,则n2=m;
    • 如果n1、m、n2在同一个节点里,直接取;
    • 如果n1单独在一个节点里,m、n2在同一个节点里,则n1取上一个节点最后一个数,如果上一个节点不存在则与①情况相同
    • 如果n1、m在同一个节点里,n2单独在一个节点里,则n2取下一个节点第一个数,如果下一个节点不存在则与②情况相同;
QPointF P = this->canvas()->mapFromGlobal(QCursor::pos());  //获取鼠标点击处的坐标(物理) 
QPointF Q = QPointF(this->invTransform(current_x,P.x()),this->invTransform(current_y,P.y())); //将物理坐标转换为画布坐标
for(int i=0; i<Data_solve.size(); i++)//遍历n条曲线
{
	for(int j=0; j<Data_solve[i].size(); j++)//遍历每条曲线的节点
	{
		//找到合适的节点
		if(Q.x()>=Data_solve[i][j]->data_min && Q.x()<=Data_solve[i][j]->data_max)
		{
			for(int k=0; k<Data_solve[i][j]->data.size(); k++)//进入节点遍历匹配数据
			{
				double dist_result = cal_twoPoint_dis(Q,Data_solve[i][j]->data[k]); //计算“数据坐标”和“鼠标点击点”两点之间的距离
				if(dist_result <= R) //以鼠标点击点为圆心,如果有数据坐标在圆内(两点之间的距离小于半径)
				{
					choose_point->setXValue(Data_solve[i][j]->data[k].x()); //给标记点QwtPlotMarker设置坐标
					choose_point->setYValue(Data_solve[i][j]->data[k].y());
					current_pos = QPointF(Data_solve[i][j]->data[k].x(),Data_solve[i][j]->data[k].y()); //记录当前选中的数据点
							
					if(k==0)//左相邻点与切点不在同一节点里,左相邻点取上一节点最后一个数据点
					{
						if(j==0)//如果没有上一节点
						{
							current_pos_left = current_pos;
							current_pos_right = QPointF(Data_solve[i][j]->data[k+1].x(),Data_solve[i][j]->data[k+1].y());
						}
						else
						{
							int pos = Data_solve[i][j-1]->data.size()-1;//上一个节点的最后一个值的下标
							current_pos_left = QPointF(Data_solve[i][j-1]->data[pos].x(),Data_solve[i][j-1]->data[pos].y());
							current_pos_right = QPointF(Data_solve[i][j]->data[k+1].x(),Data_solve[i][j]->data[k+1].y());
						}
					}
					else if(k==Data_solve[i][j]->data.size()-1)//右相邻点与切点不在同一节点里,右相邻点取下一节点第一个数据点
					{
						if(j==Data_solve[i].size()-1)//如果没有下一节点
						{
							current_pos_left = QPointF(Data_solve[i][j]->data[k-1].x(),Data_solve[i][j]->data[k-1].y());
							current_pos_right = current_pos;
						}
						else
						{
							current_pos_left = QPointF(Data_solve[i][j]->data[k-1].x(),Data_solve[i][j]->data[k-1].y());
							current_pos_right = QPointF(Data_solve[i][j+1]->data[0].x(),Data_solve[i][j+1]->data[0].y());
						}
					}
					else//三个点在同一个节点里
					{
						current_pos_left = QPointF(Data_solve[i][j]->data[k-1].x(),Data_solve[i][j]->data[k-1].y());
						current_pos_right = QPointF(Data_solve[i][j]->data[k+1].x(),Data_solve[i][j]->data[k+1].y());
					}		

					tangous_draw->cal_tangous_line(current_pos_left,current_pos,current_pos_right);//求出解析式,并计算出绘制切线的起点和终点
					//上述求出的解析式是画布解析式,绘制图形是绘制在物理坐标系上,需要转换坐标
					tangous_draw->start_pos = QPointF(this->transform(current_x,tangous_draw->start_pos.x()),this->transform(current_y,tangous_draw->start_pos.y()));
					tangous_draw->end_pos = QPointF(this->transform(current_x,tangous_draw->end_pos.x()),this->transform(current_y,tangous_draw->end_pos.y()));

					this->replot(); //更新绘图事件
					break; //只要点击坐标匹配到数据坐标则退出
				}
			}
		}
	}
}

求切线解析式

void cal_tangous_line(QPointF tangous_left,QPointF tangous,QPointF tangous_right)
{
	k = (tangous_right.y() - tangous_left.y())/(tangous_right.x() - tangous_left.x());
	b = tangous.y() - k * tangous.x();
	QString expression = QString("y=%1 * x + %2").arg(k).arg(b);
	qDebug()<<"切线表达式: "<<expression;
}


绘制切线

依据求出的解析式,给x设置一定的偏移量求出起点和终点,知道起点和终点之后就直接绘制切线段就可以了,可以参考:自定义图元项

//起点和终点坐标
start_pos.setX(tangous.x()-tangous_offset);
start_pos.setY(k*start_pos.x()+b);
end_pos.setX(tangous.x()+tangous_offset);
end_pos.setY(k*end_pos.x()+b);
void Tangous_draw::draw( QPainter *p,
				  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
				  const QRectF &rect ) const
{
	p->setRenderHints(QPainter::Antialiasing, true);//设置反走样
	p->setPen(QPen(tangous_color,tangous_width));//设置画笔
	QwtPainter::drawLine(p,start_pos,end_pos);//绘制切线
}

本文需要结合此文观看:QWT如果点选数据?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

贝勒里恩

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

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

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

打赏作者

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

抵扣说明:

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

余额充值