- 1. Point and vector
- 2. Plane
- 3. Straight
- 4. Conclusion
By means of this article, I want to share my experience in using computer geometry, which I have accumulated in the process of working on my dissertation. Not everyone knows Qt Creator contains tools for working with geometry (in particular QVector3D), for which there is no detailed manual in Russian. Therefore, here I will try to summarize the necessary theory and its implementation as briefly as possible.
Point and vector
To describe a point in Qt, the QVector2D, QVector3D and QVector4D classes (not to be confused with the QVector class) are provided for two-dimensional, three-dimensional and four-dimensional spaces, respectively. In fact, these are arrays of two, three and four float variables with a set of geometric functions. Therefore, I will give all the examples only for the most useful QVector3D in practice.
QVector3D v1(1,1,1) v2(1,1,1), v3(1.1f,2.5f,3.8f);
In the example, 3 vectors are given. The brackets contain x, y, z coordinates. Any of the vector components can be obtained or redefined.
v3.setX(0.5); v3.setY(0.6); v3.setZ(0.7); qDebug() << v3.x() << v3.y() << v3.z() << v3;
0.5 0.6 0.7 QVector3D(0.5, 0.6, 0.7)
The same classes are used to describe vectors. Therefore, some of the functions will have different meanings for vectors and points. So, for example, normalization is an operation that transforms a given vector into a vector of unit length:
where is the length (modulus) of the vector. QVector3D has two functions for this:
v1.normalize(); // функция, изменяющая переменные объект qDebug() << v1 << v2.normalized(); // функция, не переменные объект
QVector3D(0.57735, 0.57735, 0.57735) QVector3D(0.57735, 0.57735, 0.57735)
In the example, the vector, which had a length root of three, was recalculated into a unit vector (such normalized vectors in geometry are necessary for various geometric operations). This is easy to check with the length() function, which returns the length of the vector.
float L = v1.length(); // длина вектора или расстояние от точки до начала координат
In some problems, we are not interested in the length of the vector, but its square. For this, the lengthSquared() function is provided, which reduces the number of calculations
float L2 = v1.lengthSquared();
Before carrying out many calculations, it is necessary to check whether the vectors used are not zero (all components are zero). Otherwise, the result will be inadequate (even errors are possible).
bool b = v1.isNull(); // проверка: является ли вектор нулевым?
Vectors can be added and subtracted (adding their respective coordinates). Also, a vector can be multiplied or divided by a number (gets a vector n times larger or smaller in length). You should be more careful with the multiplication operation, because. the expression v1*v2 will be reduced to the multiplication of the corresponding coordinates of the vectors. The division operation v1/v2 works similarly. Geometric interpretation of the two previous operations - stretching and shrinking the coordinate system along the corresponding axes by the values specified in v2. The dotProduct(v1, v2) and crossProduct(v1, v2) functions are provided to implement the dot and vector products.
QVector3D v11(1,0,0), v12(0,1,0); qDebug() << v11*v12 << QVector3D::dotProduct(v11, v12) << QVector3D::crossProduct(v11, v12);
QVector3D(0, 0, 0) 0 QVector3D(0, 0, 1)
Let me remind you that the scalar product of two vectors is a number defined as
and in the case of multiplication of normal vectors is equal to the cosine of the angle between them.
The cross product can be calculated as
where i, j, k are the orts of the Cartesian coordinate system, direct brackets (here and below) are the determinant of the matrix. The result of this operation is a vector perpendicular to the plane in which two factor vectors lie, or a zero vector if v1 and v2 are collinear. The module of the vector product is equal to the product of the modules of the factors and the sine of the angle between them.
Vectors can be checked for equality. Two vectors are equal when all their corresponding coordinates are equal. However, it should be remembered that with complex calculations, an error can accumulate. Therefore, the developers have provided the possibility of a "soft" comparison.
v2 = v1 + QVector3D(0.000001f, 0.000001f, 0.000001f); qDebug() << (v1 == v2) << qFuzzyCompare(v1, v2);
false true
The distance between two points is given by
embedded in the distanceToPoint(v2) function
QVector3D v1(0,1,1), v2(1,0,1); qDebug() << v1.distanceToPoint(v2);
1.41421
For vectors, the meaning of the last operation is the length of the vector of their difference.
qDebug() << (v1-v2).length();
1.41421
Plane
Any plane can be defined by three pairwise noncoinciding points T1, T2 and T3 that do not lie on the same straight line. Another convenient description is using the plane equation:
where A, B, C and D are coefficients that are calculated through the coordinates of points T1, T2 and T3,
(A, B, C) is the normal vector to the plane, D is the free coefficient. The result obtained can be normalized
(a, b, c) is the unit normal vector to the plane, d is the distance from the plane to the origin of coordinates (with “plus” if the normal vector is directed to the half-plane containing the origin, otherwise – with “minus”).
The normal vector to the plane can be calculated using the static function normal(…), whose arguments can be either three points (as shown above), or two non-collinear vectors. It is obvious that two vectors can be given as T1 – T2, T2 – T3, and the normal as their vector line.
QVector3D v1(0,0,1), v2(0,1,0), v3(1,0,0); // корректно заданная плоскость qDebug() << QVector3D::normal(v1, v2, v3), QVector3D::normal(v1 - v2, v2 - v3), QVector3D::crossProduct(v1 - v2, v2 - v3).normalized();
QVector3D(-0.57735, -0.57735, -0.57735) QVector3D(-0.57735, -0.57735, -0.57735) QVector3D(-0.57735, -0.57735, -0.57735)
If the input data requirements described above are not met, the result will be a null vector
QVector3D v01(0,0,10), v02(0,0,20), v03(0,0,30); // некорректно заданная плоскость qDebug() << QVector3D::normal(v01, v02, v03) << QVector3D::normal(v01 - v02, v02 - v03);
QVector3D(0, 0, 0) QVector3D(0, 0, 0)
The above description of the plane is the most compact (4 numbers). But the most convenient is the description of the plane by one point (T0) and a normal vector (6 numbers). This view makes it easy to organize the following operations.
Belonging plane
If the point T lies on a plane, then substituting its coordinates into the equation of the plane, we get 0. In the representation through a point and a vector
In other words, the vector T - T0 is perpendicular to the normal vector n.
In one half-space
The plane divides the space into two half-spaces. The previous expression takes positive values if the point T lies in one of them and negative values if in the other. Therefore, 2 points T1 and T2 lie in the same half-space if
Projection of point T onto a plane
Distance from point to plane
is the distance from a point to its projection onto a plane
It is defined using the distanceToPlane(...) function, whose arguments are the plane parameters (a point and a vector or three points).
QVector3D T(2,2,2);// точка QVector3D n(-1,-1,-1), T0(1,1,1);// плоскость qDebug() << T.distanceToPlane(T0,n) << QVector3D::dotProduct(T-T0, n);// неправильный расчёт: нормальный вектор не нормализован qDebug() << T.distanceToPlane(T0,n.normalized()) << QVector3D::dotProduct(T-T0, n)/n.length();//правильный расчёт
-3 -3
-1.73205 -1.73205
Note that the resulting value is signed according to which half-plane T lies in.
Mirror reflection of the T point from the plane
Straight
A line in space is completely described by two (noncoinciding) points T1 and T2. In Qt, it is customary to describe a straight line with a point T1 and a direction vector K = T2 – T1.
or
where (ΔX, ΔY, ΔZ) = K. It is also expedient to normalize this vector
Belonging of point T to a straight line
It is necessary to check the vectors (T – T1) and k for collinearity (cross product – zero vector).
Projection of point T straight
The following expression can be easily obtained by analyzing the solutions of the problem of the projection of a point onto a plane
Distance from point T to straight line
In accordance with the above
The distance from a point to a line is determined by the distanceToLine(...) function, whose arguments are a point and a direction vector of the line.
QVector3D T(2,2,2);// точка QVector3D k(1,1,0), T1(0,0,1);// плоскость QVector3D R = T - T1 - k*QVector3D::dotProduct(k, T - T1); qDebug() << T.distanceToLine(T1,k) << R.length(); // неправильный расчёт: направляющий вектор не нормализован R = T - T1 - k*QVector3D::dotProduct(k, T - T1)/k.lengthSquared(); qDebug() << T.distanceToLine(T1,k.normalized()) << R.length(); // правильный расчёт
3 3
1 1
Intersection of a line and a plane
The line (k, T1) may be parallel to the plane (n, T0). In this case, the defining vectors are perpendicular, which is checked by checking for equality of their scalar product. Otherwise, the line and plane have an intersection point defined as
In the above formula, unlike the previous ones, it is not necessary to use normalized vectors. If there is no intersection, it is possible to check whether the point T1 belongs to the plane, and to determine whether the line lies on it.
Conclusion
Thanks to everyone who read the article to the end. In the future, I plan to develop this topic. Therefore, if you have questions on the topic, write them in the comments.
У меня руки так и не дошли написать статью, где показан пример движения круга с отражениями от условных границ в графической сцене с использованием скалярных векторов.
Вообще прлюс использования скалярной математики при расчётах углов отражений в том, что это менее затратный операции, чем использование тригонометрии (синусы/косинусы и т.д.)
Скалярная математика и тригонометрия - суть одно и тоже. Просто разные языки описания одного предмета. В конечном итоге для расчёта коэффициента отражения нужно знать косинус угла падения.
Подскажите, какой инструмент лучше использовать для визуализации 3D объектов.
Вы очень сильно заблуждаетесь.
Вот формула для расчёта отражённого вектора. Расчёт углов через косинусы и синусы не требуется от слова совсем .
Подробнее обсуждение в этом топике
При написании арканоида для медицинского оборудования я пользовался именно математикой скалярных векторов. Поэтому и утверждаю, что использование скалярной математики в разы разгружает процессорные мощности. Это основы написания игровых движков.
Визуализацию можно и в Qt делать. Насколько помню по новостям там есть поддержка импорта 3D объектов даже. Также есть примеры визуализации некоторых вещей в самом Qt Creator.
На нашем проекте используется OpenCascade - достаточно мощная вещь. Главное написать код для QWidget, чтобы отображать результат. Но сам я в той части кода не работаю. Не моя область проекта.
Не согласен. Произведение l на n - это косинус угла между ними умноженный на их длины. Если бы оба вектора были единичными, то остался бы "чистый" косинус. Просто при используемом описании тригонометрия скрыта от нас.
А в плане того, что здесь не нужно вычислять угол, а потом по нему считать косинус я согласен. Непосредственного использования пригонометрических функций не требуется.
Да, согласен. Освежил в памяти. Вот определение из лекций
Тем не менее, косинус здесь знать не нужно, вот к чему я это говорил
Естественно, что скалярное произведение векторов отражает явления тригономитреческих функций и может быть сопоставлено. Иначе это было бы странно. Насколько помню - это выводится через последовательное доказательство леммами, но не через прямые расчёты и формулы. Поэтому утверждение имеет доказательную базу, а знать косинус не нужно ;-)