Дмитрий
ДмитрийJune 28, 2020, 8:03 a.m.

Computer Geometry with Qt Creator

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.

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

Evgenii Legotckoi
  • June 29, 2020, 4:05 a.m.

У меня руки так и не дошли написать статью, где показан пример движения круга с отражениями от условных границ в графической сцене с использованием скалярных векторов.

Вообще прлюс использования скалярной математики при расчётах углов отражений в том, что это менее затратный операции, чем использование тригонометрии (синусы/косинусы и т.д.)

Дмитрий
  • July 1, 2020, 5:56 a.m.

Скалярная математика и тригонометрия - суть одно и тоже. Просто разные языки описания одного предмета. В конечном итоге для расчёта коэффициента отражения нужно знать косинус угла падения.

Подскажите, какой инструмент лучше использовать для визуализации 3D объектов.

Evgenii Legotckoi
  • July 1, 2020, 6:09 a.m.
  • (edited)

Вы очень сильно заблуждаетесь.

Вот формула для расчёта отражённого вектора. Расчёт углов через косинусы и синусы не требуется от слова совсем .

Подробнее обсуждение в этом топике

При написании арканоида для медицинского оборудования я пользовался именно математикой скалярных векторов. Поэтому и утверждаю, что использование скалярной математики в разы разгружает процессорные мощности. Это основы написания игровых движков.

Визуализацию можно и в Qt делать. Насколько помню по новостям там есть поддержка импорта 3D объектов даже. Также есть примеры визуализации некоторых вещей в самом Qt Creator.

На нашем проекте используется OpenCascade - достаточно мощная вещь. Главное написать код для QWidget, чтобы отображать результат. Но сам я в той части кода не работаю. Не моя область проекта.

Дмитрий
  • July 2, 2020, 6:16 a.m.

Не согласен. Произведение l на n - это косинус угла между ними умноженный на их длины. Если бы оба вектора были единичными, то остался бы "чистый" косинус. Просто при используемом описании тригонометрия скрыта от нас.

Дмитрий
  • July 2, 2020, 6:19 a.m.

А в плане того, что здесь не нужно вычислять угол, а потом по нему считать косинус я согласен. Непосредственного использования пригонометрических функций не требуется.

Evgenii Legotckoi
  • July 2, 2020, 6:50 a.m.

Да, согласен. Освежил в памяти. Вот определение из лекций

Скалярным произведением ненулевых векторов a и b называется число, равное произведению длин этих
векторов на косинус угла между ними. Если среди векторов a и b
есть хотя бы один нулевой, то скалярное произведение равно нулю.

Тем не менее, косинус здесь знать не нужно, вот к чему я это говорил

В конечном итоге для расчёта коэффициента отражения нужно знать косинус угла падения.

Естественно, что скалярное произведение векторов отражает явления тригономитреческих функций и может быть сопоставлено. Иначе это было бы странно. Насколько помню - это выводится через последовательное доказательство леммами, но не через прямые расчёты и формулы. Поэтому утверждение имеет доказательную базу, а знать косинус не нужно ;-)

Comments

Only authorized users can post comments.
Please, Log in or Sign up
B

C++ - Test 002. Constants

  • Result:16points,
  • Rating points-10
B

C++ - Test 001. The first program and data types

  • Result:46points,
  • Rating points-6
FL

C++ - Test 006. Enumerations

  • Result:80points,
  • Rating points4
Last comments
k
kmssrFeb. 8, 2024, 5:43 p.m.
Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVADec. 25, 2023, 9:30 a.m.
Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJoDec. 25, 2023, 7:38 a.m.
Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
GvozdikDec. 18, 2023, 8:01 p.m.
Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Now discuss on the forum
AC
Alexandru CodreanuJan. 19, 2024, 10:57 a.m.
QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…
BlinCT
BlinCTDec. 27, 2023, 7:57 a.m.
Растягивать Image на парент по высоте Ну и само собою дял включения scrollbar надо чтобы был Flickable. Так что выходит как то так Flickable{ id: root anchors.fill: parent clip: true property url linkFile p…
Дмитрий
ДмитрийJan. 10, 2024, 3:18 a.m.
Qt Creator загружает всю оперативную память Проблема решена. Удалось разобраться с помощью утилиты strace. Запустил ее: strace ./qtcreator Начал выводиться весь лог работы креатора. В один момент он начал считывать фай…
Evgenii Legotckoi
Evgenii LegotckoiDec. 12, 2023, 5:48 a.m.
Побуквенное сравнение двух строк Добрый день. Там случайно не высылается этот сигнал textChanged ещё и при форматировани текста? Если решиать в лоб, то можно просто отключать сигнал/слотовое соединение внутри слота и …

Follow us in social networks