目录
QPoint类
QPoint的构造
QPoint公有方法
isNull()
rx() ry()
setX() setY()
toCGPoint()
toPointF()
transposed()
x() y()
manhattanLength()
各类重载运算符
QPoint的静态方法
dotproduct()
QPoint类
在 Qt 框架中,QPoint
是一个简单且常用的类,用于表示二维平面上的点(Point),其坐标通过整型值 ((x, y)) 表示。它是 Qt 的核心数据类型之一,广泛用于处理图形界面和几何计算。对于几何类型,自然离不开点,线,以及面等元素。而这些元素则依赖于相关的坐标系的建立。
这里先来看看Qt中的坐标系:
在常规的坐标系中,我们可能最常见到的是这种形式:
此类直角坐标系原点通常位于左下角,而qt则与此不同。Qt 使用的是 左手坐标系,并且坐标原点(0,0)通常位于屏幕或窗口的 左上角。
-
X轴:从左到右,正方向是向右。
-
Y轴:从上到下,正方向是向下。
这意味着:
-
窗口左上角的坐标是
(0, 0)
。 -
X轴增大时,位置向右移动。
-
Y轴增大时,位置向下移动。
对于QPoint类,其封装了以下方法(注:需要包含相关头文件<QPoint>):
(公有方法)
(静态方法)
接下来以此为基础,聊聊QPoint
类。
QPoint的构造
默认构造:
QPoint()
默认构造将会生成一个位于原点的点(坐标为(0,0))。
qDebug() << QPoint();
--Output:
QPoint(0,0)
参数构造:
QPoint::QPoint(int xpos, int ypos)
该构造接收两个参数,并以这两个参数为其坐标来构造点。
-
xpos:点的x坐标(横坐标)。
-
ypos:点的y坐标(纵坐标)。
QPoint p(4,5);
qDebug() << p;
--Output:
QPoint(4,5)
有了这两个构造函数,我们便可以在一个二维坐标系中描述出任意一个点的位置。
QPoint公有方法
isNull()
原型:
bool QPoint::isNull() const
该方法用于检查某个点是否是空点(即(0,0)点,一般认为没有具体的空间位置)。返回bool类型,若某点x,y坐标均为0则返回true,否则返回false。
QPoint p1;
QPoint p2(1,1);
qDebug() << "is p1 null?" << p1.isNull()
<< "\nis p2 null?" << p2.isNull();
--Output:
is p1 null? true
is p2 null? false
rx() ry()
原型:
int &rx() | int &ry()
该方法将返回x横坐标(或y纵坐标)的引用,使得用户可以直接对点的坐标点就行操纵:
QPoint p1(4,6);
--p1.rx();
++p1.ry();
qDebug() << p1;
--Output:
QPoint(3,7)
如上示例,可以对其进行自增或自减。
setX() setY()
函数原型:
void QPoint::setX(int x) | void QPoint::setY(int y)
该方法需要将其中传入新的x坐标的值(或y坐标的值),用于更新点的空间位置。例如下列我们已经有了一个点p(-3,5).需要将其移到(2,9)的位置:
QPoint p(-3,5);
qDebug() << "before move p:" << p;
p.setX(2); p.setY(9);
qDebug() << "after mvoe p:" << p;
--Output:
before move p: QPoint(-3,5)
after mvoe p: QPoint(2,9)
toCGPoint()
函数原型:
CGPoint QPoint::toCGPoint() const
这个函数返回的是一个CGPoint(Core Graphics Point)类型,但是有的朋友可能会发现在Qt强大的帮助手册中却找不到有关该类型的任何信息。这里我们先来简单了解一下何为CGPoint
。
Core Graphics 是由苹果公司自主研发的一套图形和绘图框架,用于在 macOS 和 iOS 操作系统上创建和处理图形。它提供了一系列的 API 和工具,允许开发者创建高质量的图形和用户界面。而CGPoint
是 Core Graphics 框架中的一个基本类型,代表一个二维坐标点(与QPoint
一样)。
而我们的Qt使用的是自己的QPoint
类型,并没有使用CG框架,因而你自然无法在Qt的帮助手册之中找到有关CGPoint
的信息。
但为什么Qt要在QPoint类中提供这么一个方法呢?
这么做其实主要是为了方便在 Qt 应用程序中使用 Core Graphics 框架的 API。虽然 Qt 有自己的图形和绘图 API,但是有些开发者可能需要使用 Core Graphics 框架的特定功能,而且有的第三方库可能使用的是CGPoint类型的坐标点。 官方提供这么一个API,便省去了手动进行类型转换的麻烦。
这里我并没有连上CG框架,就不给出演示了。
toPointF()
函数原型:
QPointF QPoint::toPointF() const
该方法将会使对应的点对象所描述的二维空间位置的精度提高到浮点精度。QPointF
与QPoint
是一样的,唯一的区别是QPointF
的精度更高。
QPoint p_low(1,2);
qDebug() << "Low Accuracy:" << p_low;
QPointF p_high = p_low.toPointF();
p_high.setX(1.5); p_high.setY(2.5);
qDebug() << "High Accuracy:" << p_high;
--Output:
Low Accuracy: QPoint(1,2)
High Accuracy: QPointF(1.5,2.5)
如上述用例,当你有一个 QPoint
对象,但是你需要使用浮点数精度来进行计算或表示坐标值时,你可以通过 toPointF()
将其转换为 QPointF
对象。
transposed()
函数原型:
QPoint QPoint::transposed() const
该方法将会调换当前点的x,y坐标,并将其构造成一个新的QPoint
对象返回。
QPoint p(5,-7);
qDebug() << "before transposed:" << p;
qDebug() << "after transposed:" << p.transposed();
--Output:
before transposed: QPoint(5,-7)
after transposed: QPoint(-7,5)
x() y()
函数原型:
int QPoint::x() const | int QPoint::y() const
该方法返回点的横纵坐标。(注意与rx(),ry()方法区别开来,这里返回的不是引用,而是单纯的值)。
QPoint p(2,6);
//p.x()++; //invalid.
int x_coordinate = p.x();
int y_coordinate = p.y();
qDebug() << "x:" << x_coordinate
<< "y:" << y_coordinate;
--Output:
x: 2 y: 6
manhattanLength()
函数原型:
int QPoint::manhattanLength() const
该方法用于计算该点与原点之间的曼哈顿距离。何为曼哈顿距离?
(图片源自于百度百科)
曼哈顿距离是数学当中一种距离的度量方式。我们假设上图为坐标系,原点是位于左下角的点A。点A到右上角点B的直线距离(绿色的线)称之为欧几里得距离。
在知道点的坐标后我们可以使用勾股定理来求解绿色线段的长度。但是欧几里得距离的计算涉及平方与开平方,计算效率是比较低的。
因此,引入了曼哈顿距离:两个点在标准坐标系上的绝对轴距总和。曼哈顿距离只涉及加法和绝对值运算,没有平方或平方根,因此比欧几里得距离计算更快,尤其在大规模数据计算时节约资源。上述红色线段便是曼哈顿距离,而蓝色与黄色线段则代表的是等价的曼哈顿距离。
曼哈顿距离特别适合在网格状空间或离散的环境中使用,它的名称来源于曼哈顿市的街道布局,因为它模拟了在城市的直角网格街道中,从一个点到另一个点的最短路径。
用一个简单的例子来说:假如你在城市街道中从一个十字路口走到另一个十字路口,你只能沿街道的直线方向(横或竖)行走,不能直接穿过建筑物。曼哈顿距离就是你需要走的水平和垂直路段的总长度。
其计算公式如下:
d(P,Q)=∣x2−x1∣+∣y2−y1∣
在Qt中,manhattanLength()
方法返回的是该点与原点之间的曼哈顿距离。
QPoint p(6,8);
int length = p.manhattanLength(); //|6-0|+|8-0|
qDebug() << length;
--Output:
14
qt中若要计算两点之间的曼哈顿距离,根据公式,应先求两点之间的差值,而后再调用该方法返回两点之间的曼哈顿距离:
QPoint p1(3,4);
QPoint p2(6,9);
QPoint diff_point = p2 - p1; // |6-3|+|9-4|
qDebug() << "manhattanLength of p1 and p2:" << diff_point.manhattanLength();
--Output:
manhattanLength of p1 and p2: 8
各类重载运算符
从上图可以看到QPoint类型适用于很多基本的运算符。下面统一进行说明:
QPoint类型的加减运算:
QPoint类型重载了+-
运算符,在进行此类运算时,qt是将其二维点视为向量,并执行向量中的代数形式的加减运算:
QPoint p1(4,5);
QPoint p2(2,8);
qDebug() << p1 + p2;
qDebug() << p1 - p2;
--Output:
QPoint(6,13)
QPoint(2,-3)
既然重载了+-
,相对应的,+=
与-=
运算符便也适用:
QPoint p1(4,5);
QPoint p2(2,8);
QPoint p3(-6,4);
p1 += p2;
qDebug() << "p1 += p2 = " << p1;
p1 -= p3;
qDebug() << "p1 -= p3 = " << p1;
--Output:
p1 += p2 = QPoint(6,13)
p1 -= p3 = QPoint(12,9)
QPoint类型的乘除运算:
我们知道数学中,向量乘积有数量积与叉积的概念,但是对于QPoint类只提供了点积与向量的数乘运算(至于为什么不提供叉积,因为qt的工作主要涉及的是2D的平面空间,2D空间中的叉积意义并不大):
//数乘演示
QPoint p1(4,6);
QPoint p2(3,7);
//qDebug() << p1 * p2; //invalid.
qDebug() << p1 * 2;
qDebug() << p2 * 3;
--Output:
QPoint(8,12)
QPoint(9,21)
数乘可以乘以浮点数,但是相对应得用QPointF类型接收,否则数据会被截断。
QPoint p1(4,6);
qDebug() << p1 * 2.1;
qDebug() << (QPointF)p1 * 2.1;
--Output:
QPoint(8,13)
QPointF(8.4,12.6)
除法运算应注意精度问题。如果点以整数形式保存,因此结果将四舍五入到最接近的整数。使用QPointF的话可以拿到精确精度。
QPoint p1(2,3);
qDebug() << p1 / 2;
qDebug() << (QPointF)p1 / 2;
--Output:
QPoint(1,2)
QPointF(1,1.5)
既然满足数乘与除法,则相对应,*=
与 /=
运算符也适用:
QPoint p1(4,6);
QPoint p2(2,3);
p1 *= 4;
p2 /= 3;
qDebug() << "p1:" << p1 << " : " << "p2:" << p2;
--Output:
p1: QPoint(16,24) : p2: QPoint(1,1)
同时,QPoint
也重载了 !=
,==
运算符,返回值为bool
类型,用于判断两个点是否相等:
QPoint p(5,2);
QPoint pt(2,5);
if (p == pt.transposed()) {
qDebug() << "The two points are Equaled";
}
--Output:
The two points are Equaled
QPoint的静态方法
dotproduct()
函数原型:
int QPoint::dotProduct(const QPoint &p1, const QPoint &p2)
该方法返回两个向量之间的数量积(点积)。
QPoint p1(2,6);
QPoint p2(1,4);
int dotpro = QPoint::dotProduct(p1,p2); //(2*1)+(4*6)
qDebug() << "The dotProduct of p1,p2 is :" << dotpro;
--Output:
The dotProduct of p1,p2 is : 26
至此,QPoint
类型已全部介绍完毕了。QPointF
与QPoint
除了精度之外其余是一致的,可直接套用QPoint
的方法。