Russian Qt Forum

Qt => Вопросы новичков => Тема начата: Skrypnyk от Март 17, 2013, 11:19



Название: От С++ к Qt C++
Отправлено: Skrypnyk от Март 17, 2013, 11:19
Здравствуйте!
Я делаю проект для учебы. Мне нужно создать массив атомов. В этом массиве юзер выбирает плоскость используя индексы Миллера. На экране должны быть отображены атомы, принадлежащие плоскости. Я написал код в С++:
Код:
/* I. Create a FCC lattice
   II. Determine the projection plane using Miller indices notation
   III. Calculate the angles between a projection of the normal to the projection plane
        on 3 different planes (XY, XZ and YZ) and axes X [1;0;0], Y [0;1;0] and Z [0;0;1] respectively
   IV. Rotate the grid (do the projection) */
 
#include <iostream>
#include <math.h>
 
using std::cout; // Using standart namespace
using std::cin;
using std::endl;
 
class Atom
{
  public:
    float x, y, z; // Coordinates of the atoms
};
 
typedef class Atom AtomType;
 
    AtomType Atom1 [10][10][10]; // Create a 3 dimensional array to fill the space with atoms of type 1
    AtomType Atom2 [10][10][10]; // Create a 3 dimensional array to fill the space with atoms of type 2
    AtomType Atom3 [10][10][10]; // Create a 3 dimensional array to fill the space with atoms of type 3
    AtomType Atom4 [10][10][10]; // Create a 3 dimensional array to fill the space with atoms of type 4
    AtomType Atom11 [10][10][10]; // Create a 3 dimensional array of atoms of type 1 that belong to projection plane
    AtomType Atom22 [10][10][10]; // Create a 3 dimensional array of atoms of type 2 that belong to projection plane
    AtomType Atom33 [10][10][10]; // Create a 3 dimensional array of atoms of type 3 that belong to projection plane
    AtomType Atom44 [10][10][10]; // Create a 3 dimensional array of atoms of type 4 that belong to projection plane
 
    //float x, y, z;
    int i, j, k; // Variables for array Atom [i][j][k]
    int a, b, c; // Integers, which represent reciprocal values of interceptions of the projection plane
                 // with axes X, Y and Z respectively & also represent a normal to the projection plane
 
void projection();
 
int main ()
{
    float angleX, angleY, angleZ; // Variables to represent angles between a projection of the normal to the projection plane
                                  // on 3 different planes (XY, XZ and YZ) and axes X [1;0;0], Y [0;1;0] and Z [0;0;1] respectively
    // Do item I
    // 3 nested 'for' loops create the grid of atoms of type 1, 2, 3 and 4
    cout << "Atom1                Atom2                   Atom3                Atom4" << endl;
    cout << "-----------------------------------------------------------------------" << endl;
 
    for (i=0; i<10; i++)
    {
        for (j=0; j<10; j++)
        {
            for (k=0; k<10; k++)
            {
                Atom1 [i][j][k].x=i-4; // We get '-4' because we want our origin to be in the centre of array
                Atom1 [i][j][k].y=j-4;
                Atom1 [i][j][k].z=k-4;
 
                Atom2 [i][j][k].x=i-4+0.5; // We get '+0.5' because the atoms of type 2 are shifted on 0.5 along X axis
                Atom2 [i][j][k].y=j-4+0.5; // We get '+0.5' because the atoms of type 2 are shifted on 0.5 along Y axis
                Atom2 [i][j][k].z=k-4;
 
                Atom3 [i][j][k].x=i-4;
                Atom3 [i][j][k].y=j-4+0.5; // We get '+0.5' because the atoms of type 2 are shifted on 0.5 along Y axis
                Atom3 [i][j][k].z=k-4+0.5; // We get '+0.5' because the atoms of type 2 are shifted on 0.5 along Z axis
 
                Atom4 [i][j][k].x=i-4+0.5; // We get '+0.5' because the atoms of type 2 are shifted on 0.5 along X axis
                Atom4 [i][j][k].y=j-4;
                Atom4 [i][j][k].z=k-4+0.5; // We get '+0.5' because the atoms of type 2 are shifted on 0.5 along Z axis
 
                cout << Atom1 [i][j][k].x << " " << Atom1 [i][j][k].y << " " << Atom1 [i][j][k].z << "          ";
                cout << Atom2 [i][j][k].x << " " << Atom2 [i][j][k].y << " " << Atom2 [i][j][k].z << "          ";
                cout << Atom3 [i][j][k].x << " " << Atom3 [i][j][k].y << " " << Atom3 [i][j][k].z << "          ";
                cout << Atom4 [i][j][k].x << " " << Atom4 [i][j][k].y << " " << Atom4 [i][j][k].z << "          " << endl;
            }
        }
    }
 
    // Do item II
    cout << "Please enter the projection plane using Miller indices notation (e.g. 111),\npressing Enter between integers:";
    cin >> a >> b >> c;
 
    // Do item III
    angleX=acos(fabs(a*1+b*0+0*0)/(sqrt(a*a+b*b+0*0)*sqrt(1*1+0*0+0*0))); // The angle is in radians, because any functions from
    angleY=acos(fabs(0*0+b*1+c*0)/(sqrt(0*0+b*b+c*c)*sqrt(0*0+1*1+0*0))); // 'math.h' that operate on angles use radians as the
    angleZ=acos(fabs(a*0+0*0+c*1)/(sqrt(a*a+0*0+c*c)*sqrt(0*0+0*0+1*1))); // unit of angle
 
    // Do item IV
    /* To obtain a new position of atoms we need to multiply the current position by rotation matrix.
       Current position:
 
       [AtomN [i][j][k].x, AtomN [i][j][k].y, AtomN [i][j][k].z] // N - any number from 1 to 4
 
       Rotation about X axis matrix:
 
       1        0               0
       0    cos(angleX)    sin(angleX)
       0   -sin(angleX)    cos(angleX)
 
       Rotation about Y axis matrix:
 
       cos(angleY)   0    -sin(angleY)
            0        1          0
       sin(angleY)   0     cos(angleY)
 
       Rotation about Z axis matrix:
 
       cos(angleZ)   sin(angleZ)   0
      -sin(angleZ)   cos(angleZ)   0
            0            0         1
       */
 
    cout << "Atom1                Atom2                   Atom3                Atom4" << endl;
    cout << "-----------------------------------------------------------------------" << endl;
 
    // Do rotation about X axis
    for (i=0; i<10; i++)
    {
        for (j=0; j<10; j++)
        {
            for (k=0; k<10; k++)
            {
                Atom1 [i][j][k].x=Atom1 [i][j][k].x*1+Atom1 [i][j][k].y*0+Atom1 [i][j][k].z*0;
                Atom1 [i][j][k].y=Atom1 [i][j][k].x*0+Atom1 [i][j][k].y*cos(angleX)+Atom1 [i][j][k].z*(-sin(angleX));
                Atom1 [i][j][k].z=Atom1 [i][j][k].x*0+Atom1 [i][j][k].y*sin(angleX)+Atom1 [i][j][k].z*cos(angleX);
 
                Atom2 [i][j][k].x=Atom2 [i][j][k].x*1+Atom2 [i][j][k].y*0+Atom2 [i][j][k].z*0;
                Atom2 [i][j][k].y=Atom2 [i][j][k].x*0+Atom2 [i][j][k].y*cos(angleX)+Atom2 [i][j][k].z*(-sin(angleX));
                Atom2 [i][j][k].z=Atom2 [i][j][k].x*0+Atom2 [i][j][k].y*sin(angleX)+Atom2 [i][j][k].z*cos(angleX);
 
                Atom3 [i][j][k].x=Atom3 [i][j][k].x*1+Atom3 [i][j][k].y*0+Atom3 [i][j][k].z*0;
                Atom3 [i][j][k].y=Atom3 [i][j][k].x*0+Atom3 [i][j][k].y*cos(angleX)+Atom3 [i][j][k].z*(-sin(angleX));
                Atom3 [i][j][k].z=Atom3 [i][j][k].x*0+Atom3 [i][j][k].y*sin(angleX)+Atom3 [i][j][k].z*cos(angleX);
 
                Atom4 [i][j][k].x=Atom4 [i][j][k].x*1+Atom4 [i][j][k].y*0+Atom4 [i][j][k].z*0;
                Atom4 [i][j][k].y=Atom4 [i][j][k].x*0+Atom4 [i][j][k].y*cos(angleX)+Atom4 [i][j][k].z*(-sin(angleX));
                Atom4 [i][j][k].z=Atom4 [i][j][k].x*0+Atom4 [i][j][k].y*sin(angleX)+Atom4 [i][j][k].z*cos(angleX);
            }
        }
    }
    // Do rotation about Y axis
    for (i=0; i<10; i++)
    {
        for (j=0; j<10; j++)
        {
            for (k=0; k<10; k++)
            {
                Atom1 [i][j][k].x=Atom1 [i][j][k].x*cos(angleY)+Atom1 [i][j][k].y*0+Atom1 [i][j][k].z*sin(angleY);
                Atom1 [i][j][k].y=Atom1 [i][j][k].x*0+Atom1 [i][j][k].y*1+Atom1 [i][j][k].z*0;
                Atom1 [i][j][k].z=Atom1 [i][j][k].x*(-sin(angleY))+Atom1 [i][j][k].y*0+Atom1 [i][j][k].z*cos(angleY);
 
                Atom2 [i][j][k].x=Atom2 [i][j][k].x*cos(angleY)+Atom2 [i][j][k].y*0+Atom2 [i][j][k].z*sin(angleY);
                Atom2 [i][j][k].y=Atom2 [i][j][k].x*0+Atom2 [i][j][k].y*1+Atom2 [i][j][k].z*0;
                Atom2 [i][j][k].z=Atom2 [i][j][k].x*(-sin(angleY))+Atom2 [i][j][k].y*0+Atom2 [i][j][k].z*cos(angleY);
 
                Atom3 [i][j][k].x=Atom3 [i][j][k].x*cos(angleY)+Atom3 [i][j][k].y*0+Atom3 [i][j][k].z*sin(angleY);
                Atom3 [i][j][k].y=Atom3 [i][j][k].x*0+Atom3 [i][j][k].y*1+Atom3 [i][j][k].z*0;
                Atom3 [i][j][k].z=Atom3 [i][j][k].x*(-sin(angleY))+Atom3 [i][j][k].y*0+Atom3 [i][j][k].z*cos(angleY);
 
                Atom4 [i][j][k].x=Atom4 [i][j][k].x*cos(angleY)+Atom4 [i][j][k].y*0+Atom4 [i][j][k].z*sin(angleY);
                Atom4 [i][j][k].y=Atom4 [i][j][k].x*0+Atom4 [i][j][k].y*1+Atom4 [i][j][k].z*0;
                Atom4 [i][j][k].z=Atom4 [i][j][k].x*(-sin(angleY))+Atom4 [i][j][k].y*0+Atom4 [i][j][k].z*cos(angleY);
            }
        }
    }
    // Do rotation about Z axis
    for (i=0; i<10; i++)
    {
        for (j=0; j<10; j++)
        {
            for (k=0; k<10; k++)
            {
                Atom1 [i][j][k].x=Atom1 [i][j][k].x*cos(angleZ)+Atom1 [i][j][k].y*(-sin(angleZ))+Atom1 [i][j][k].z*0;
                Atom1 [i][j][k].y=Atom1 [i][j][k].x*sin(angleZ)+Atom1 [i][j][k].y*cos(angleZ)+Atom1 [i][j][k].z*0;
                Atom1 [i][j][k].z=Atom1 [i][j][k].x*0+Atom1 [i][j][k].y*0+Atom1 [i][j][k].z*1;
 
                Atom2 [i][j][k].x=Atom2 [i][j][k].x*cos(angleZ)+Atom2 [i][j][k].y*(-sin(angleZ))+Atom2 [i][j][k].z*0;
                Atom2 [i][j][k].y=Atom2 [i][j][k].x*sin(angleZ)+Atom2 [i][j][k].y*cos(angleZ)+Atom2 [i][j][k].z*0;
                Atom2 [i][j][k].z=Atom2 [i][j][k].x*0+Atom2 [i][j][k].y*0+Atom2 [i][j][k].z*1;
 
                Atom3 [i][j][k].x=Atom3 [i][j][k].x*cos(angleZ)+Atom3 [i][j][k].y*(-sin(angleZ))+Atom3 [i][j][k].z*0;
                Atom3 [i][j][k].y=Atom3 [i][j][k].x*sin(angleZ)+Atom3 [i][j][k].y*cos(angleZ)+Atom3 [i][j][k].z*0;
                Atom3 [i][j][k].z=Atom3 [i][j][k].x*0+Atom3 [i][j][k].y*0+Atom3 [i][j][k].z*1;
 
                Atom4 [i][j][k].x=Atom4 [i][j][k].x*cos(angleZ)+Atom4 [i][j][k].y*(-sin(angleZ))+Atom4 [i][j][k].z*0;
                Atom4 [i][j][k].y=Atom4 [i][j][k].x*sin(angleZ)+Atom4 [i][j][k].y*cos(angleZ)+Atom4 [i][j][k].z*0;
                Atom4 [i][j][k].z=Atom4 [i][j][k].x*0+Atom4 [i][j][k].y*0+Atom4 [i][j][k].z*1;
 
                cout << Atom1 [i][j][k].x << " " << Atom1 [i][j][k].y << " " << Atom1 [i][j][k].z << "          ";
                cout << Atom2 [i][j][k].x << " " << Atom2 [i][j][k].y << " " << Atom2 [i][j][k].z << "          ";
                cout << Atom3 [i][j][k].x << " " << Atom3 [i][j][k].y << " " << Atom3 [i][j][k].z << "          ";
                cout << Atom4 [i][j][k].x << " " << Atom4 [i][j][k].y << " " << Atom4 [i][j][k].z << "          " << endl;
            }
        }
    }
    projection (); // function projection evaluates whether atoms belong to the projection plane
 
    return 0;
}
 
void projection ()
{
    for (i=0; i<10; i++)
    {
        for (j=0; j<10; j++)
        {
            for (k=0; k<10; k++)
            {
                // Condition for Atom1
                if (Atom1 [i][j][k].x*a + Atom1 [i][j][k].y*b + Atom1 [i][j][k].z*c==1)
                 // Intercept equation of the projection plane is x/m+y/n+z/p=1, but m=1/a; n=1/b; p=1/c;
                {
                    Atom11 [i][j][k].x=Atom1 [i][j][k].x;
                    Atom11 [i][j][k].y=Atom1 [i][j][k].y;
                    Atom11 [i][j][k].z=Atom1 [i][j][k].z;
                }
                else break;
                // Condition for Atom2
                if (Atom2 [i][j][k].x*a + Atom2 [i][j][k].y*b + Atom2 [i][j][k].z*c==1)
                {
                    Atom22 [i][j][k].x=Atom2 [i][j][k].x;
                    Atom22 [i][j][k].y=Atom2 [i][j][k].y;
                    Atom22 [i][j][k].z=Atom2 [i][j][k].z;
                }
                else break;
                // Condition for Atom3
                if (Atom3 [i][j][k].x*a + Atom3 [i][j][k].y*b + Atom3 [i][j][k].z*c==1)
                {
                    Atom33 [i][j][k].x=Atom3 [i][j][k].x;
                    Atom33 [i][j][k].y=Atom3 [i][j][k].y;
                    Atom33 [i][j][k].z=Atom3 [i][j][k].z;
                }
                else break;
                // Condition for Atom4
                if (Atom4 [i][j][k].x*a + Atom4 [i][j][k].y*b + Atom4 [i][j][k].z*c==1)
                {
                    Atom44 [i][j][k].x=Atom4 [i][j][k].x;
                    Atom44 [i][j][k].y=Atom4 [i][j][k].y;
                    Atom44 [i][j][k].z=Atom4 [i][j][k].z;
                }
                else break;
            }
        }
    }
}
 

Я смотрел видео на Ютюбе, читал документацию Qt, но ничего конкретного для решения моей проблемы не нашел. Основной дилеммой является визуализация атомов в плоскости (Аtom11 - Atom44).

Подскажите, пожалуйста, какие-нибудь источники или посоветуйте что-нибудь для решения моей проблемы.

Заранее благодарен!


Название: Re: От С++ к Qt C++
Отправлено: Igors от Март 17, 2013, 12:45
Приведенный код называется "не ленивый программист" (ужасно). Ладно, об этом Вы не спрашивали, чисто по алгоритму:

Зачем Вы связались с поворотами? Что Вы от них хотели? Вам надо найти точки принадлежащие данной плоскости - ну и находите. Задайте плоскость вектором  (a, b, c)  + расстоянием до начала координат (d) и спокойно находите расстояние до нее
Код
C++ (Qt)
bool OnPlane( const Atom & atom, float a, float b, float c, float d, float epsilon )
{
float dist = atom.x * a + atom.y * b + atom.z * c + d;
return fabs(dist) < epsilon;
}
 
Вот и вся любовь


Название: Re: От С++ к Qt C++
Отправлено: Dancing_on_water от Март 17, 2013, 12:51
Э-кхм, начну с того, что неплохо подучить C++ как таковой.

В вашем коде стек уже забит дай боже как, еще что-либо в подобном роде и программа начнет вылетать с криками: "Stack Overflow".

Теперь к самому вопросу:

Если вам нужен 3d с кучей объектов, то тут openGL без вариантов.
Если 2d , то пойдет QGraphicsScene

Все прочее не подходит, т.к. у вас в одной плоскости уже 1000 объектов.



Название: Re: От С++ к Qt C++
Отправлено: Skrypnyk от Март 17, 2013, 13:46
Приведенный код называется "не ленивый программист" (ужасно). Ладно, об этом Вы не спрашивали, чисто по алгоритму:

Зачем Вы связались с поворотами? Что Вы от них хотели? Вам надо найти точки принадлежащие данной плоскости - ну и находите. Задайте плоскость вектором  (a, b, c)  + расстоянием до начала координат (d) и спокойно находите расстояние до нее
Код
C++ (Qt)
bool OnPlane( const Atom & atom, float a, float b, float c, float d, float epsilon )
{
float dist = atom.x * a + atom.y * b + atom.z * c + d;
return fabs(dist) < epsilon;
}
 
Вот и вся любовь

Повороты нужны для отображения плоскости проекции. Таким образом мы будем смотреть по направлению нормали к плоскости и получим реальные расстояния между атомами на экране.


Название: Re: От С++ к Qt C++
Отправлено: Skrypnyk от Март 17, 2013, 13:50
Э-кхм, начну с того, что неплохо подучить C++ как таковой.

В вашем коде стек уже забит дай боже как, еще что-либо в подобном роде и программа начнет вылетать с криками: "Stack Overflow".

Теперь к самому вопросу:

Если вам нужен 3d с кучей объектов, то тут openGL без вариантов.
Если 2d , то пойдет QGraphicsScene

Все прочее не подходит, т.к. у вас в одной плоскости уже 1000 объектов.



Я недавно учу С++, причем программирование -  не основное направление моей учебы. Но мне интересно. Жаль, что времени мало. Спасибо за ответ. Буду читать о QGraphicsScene.


Название: Re: От С++ к Qt C++
Отправлено: Igors от Март 17, 2013, 14:31
Лучше не злоупотреблять цитированием если и так ясно о чем речь
Повороты нужны для отображения плоскости проекции. Таким образом мы будем смотреть по направлению нормали к плоскости и получим реальные расстояния между атомами на экране.
Экран всего лишь отображает, поэтому расстояния на экране реальными быть не могут :) Если же Вы хотите отобразить на экране секущую плоскость (с найденными точками), то Вам совершенно не нужно изучать какие-то мудреные классы и/или OpenGL. Надо просто перевести найденные точки в экранные координаты построив матрицу поворота. Сначала выведите исходные точки в плоскости XY
Код
C++ (Qt)
QPointF Atom2Screen( const Atom & atom,
                    int w, int h,   // ширина и высота экрана (области вывода)
                    float sizeX, float sizeY )  // размер решетки атомов
{
float scale = qMin(w / sizeX, h / sizeY);
float x = (atom.x - sizeX / 2) * scale + w / 2;
float y = h / 2 - (atom.y - sizeY / 2) * scale;
return QPointF(x, y);
}
 
Чтобы нарисовать найденные точки - все то же самое, только сначала надо помножить точку на матрицу. Чтобы воздух не гонять - нарисуйте исходные, а матрицу я Вам покажу


Название: Re: От С++ к Qt C++
Отправлено: Skrypnyk от Март 17, 2013, 21:08
Igors, я получил двухмерные координаты точек секущей. Теперь хотелось бы их визуализировать. Как это сделать, если всем точкам отвечают элементы массива с координатами x, y (Atom11 [j][k].x, Atom11 [j][k].y, и то же для атомов типа 22, 33, 44)?

В Вашей функции Atom2Screen первый аргумент
Цитировать
const Atom & atom
требует ввода указателя, если я не ошибаюсь. Мне нужно создать указатель?


Название: Re: От С++ к Qt C++
Отправлено: Igors от Март 18, 2013, 12:17
В Вашей функции Atom2Screen первый аргумент
Цитировать
const Atom & atom
требует ввода указателя, если я не ошибаюсь. Мне нужно создать указатель?
Это "ссылка", в данном случае константная. Просто подавайте в ф-цию элемент массива, указатель создавать не нужно. Подробнее о ссылках - см любую книгу по С++

я получил двухмерные координаты точек секущей. Теперь хотелось бы их визуализировать. Как это сделать, если всем точкам отвечают элементы массива с координатами x, y (Atom11 [j][k].x, Atom11 [j][k].y, и то же для атомов типа 22, 33, 44)?
Визуализация (перевод в экранные координаты) в любом случае выполняется ф-цией которую я привел в предыдущем посте. Если 2 или более точек совпадают в данной проекции - ну увидите их все вместе как одну, это нормально.

То что Вы реализовали называется "углы Эйлера"  (последовательность поворотов). Это длинно и мутно, "зато" в данном случае совершенно неуместно и неправильно. Нужно получить уравнения секущих плоскостей из отрезков Миллера. Это можно сделать напр так
Код
C++ (Qt)
// на основании Вашего текста
QVector3D axisX(10, 0, 0);
QVector3D axisY(0, 10, 0);
QVector3D axisZ(0, 0, 10);
QVector3D cntr(-4, -4, -4);
 
void Miller2Plane( int a, int b, int с, QVector <QVector4D> & plane )
{
for (int i = 0; i < qMax(a, 1); ++i) {
 for (int j = 0; j < qMax(b, 1); ++j) {
  for (int k = 0; k < qMax(c, 1); ++k) {
 
// находим 3 точки плоскости
   QVector <QVector3D> vec;  
   if (a) vec.push_back(cntr + axisX / (i + 1));
   if (b) vec.push_back(cntr + axisY / (j + 1));
   if (c) vec.push_back(cntr + axisZ / (k + 1));
   assert(vec.size() > 0);
   if (!a) vec.push_back(vec.back() + axisX);
   if (!b) vec.push_back(vec.back() + axisY);
   if (!c) vec.push_back(vec.back() + axisZ);
 
// записываем уравнение плоскости (QVector4D)
   QVector3D nor = QVector3D::normal(vec[0], vec[1], vec[2]).normalize();
   plane.push_back(QVector4D(nor, -QVector3D::dotProduct(nor, vec[0])));
  }
 }
}
}
Если a, b, c нули или единицы - одна плоскость, иначе "семейство".


Название: Re: От С++ к Qt C++
Отправлено: Skrypnyk от Март 18, 2013, 15:12
Igors, спасибо за Ваш ответ. Очень ценная для меня информация. Я использовал углы Эйлера, потому что это был единственный доступный для меня инструмент поворота. У меня есть несколько вопросов по части приведенного Вами кода:

1. QVector <QVector4D> & plane - что нужно вводить как аргумент при вызове функции Miller2Plane (1,1,1, ?)? И зачем нужен QVector4D? Чему отвечает 4-я координата?
2. push_back() - эквивалентно append (), как я понял из документации Кьют.  Т.е. добавляет в конец вектора новое значение?
3. assert(vec.size() > 0) - зачем оценивать количество элементов вектора именно на этом этапе (оценки равны или нет переменные a, b, c нулю)?
4. back()? - зачем возвращать ссылку на последний вектор?
5. В Вашей записи vec
  • , vec [1], vec [2] - обозначаются первые 3 элемента массива vec, которые отвечают индексам Миллера?
6. В
Код:
plane.push_back(QVector4D(nor, -QVector3D::dotProduct(nor, vec[0])));
функция QVector4D - это QVector4D::QVector4D(const QVector3D & vector, float wpos)?
Зачем нужно скалярное произведение нормали к плоскости с, как я понимаю, первым отрезком Миллера? Да еще и со знаком минус?


Название: Re: От С++ к Qt C++
Отправлено: Igors от Март 18, 2013, 18:32
Простейший случай: индекс = (1, 1, 1). Одна секущая плоскость по диагонали. cntr + axisX(Y, Z) есть 3 точки лежащие в этой плоскости. Уравнение плоскости

ax + by + cz + d = 0;

a, b, c  - нормаль к плоскости, d - расстояние до начала координат. Если подставить точку (x. y. z) в это уравнение, результат будет (знаковое) расстояние от точки до плоскости. Если точка лежит на плоскости, то уравнение даст ноль. Находим нормаль и d и записываем это в Vector4D

Если все 3 индекса == 0, это случай недопустимый, вываливаемся по assert. А вот 1 или 2 индекса могут быть нулевыми - ось(и) параллельны плоскости. Тогда cntr+axis не проходит, но мы можем добавить отрезок оси к уже имеющейся на плоскости точки - и получить новую.

Да, все это "аналитическая геометрия", курс первого семестра который традиционно считается легким (в теории).  По поводу остальных Ваших вопросов по векторам и др - общий ответ "да" и учите плюсы, по-другому не получится


Название: Re: От С++ к Qt C++
Отправлено: Skrypnyk от Март 18, 2013, 18:42
Получается вместо QVector <QVector4D> & plane при вызове функции Miller2Plane должно быть записано расстояние от начала координат до плоскости?


Название: Re: От С++ к Qt C++
Отправлено: Igors от Март 18, 2013, 18:57
Получается вместо QVector <QVector4D> & plane при вызове функции Miller2Plane должно быть записано расстояние от начала координат до плоскости?
Что-то совсем мрачно  :'( Как Вы знаете, 3 индекса Миллера могут задавать любое число секущих плоскостей, поэтому ф-ция заполняет контейнер (вектор) каждый элемент которого QVector4D описывающий секущую плоскость: x, y, z есть нормаль к плоскости и w - расстояние


Название: Re: От С++ к Qt C++
Отправлено: m_ax от Март 18, 2013, 20:07
Получается вместо QVector <QVector4D> & plane при вызове функции Miller2Plane должно быть записано расстояние от начала координат до плоскости?
Что-то совсем мрачно  :'( Как Вы знаете, 3 индекса Миллера могут задавать любое число секущих плоскостей, поэтому ф-ция заполняет контейнер (вектор) каждый элемент которого QVector4D описывающий секущую плоскость: x, y, z есть нормаль к плоскости и w - расстояние

А если вектора кристаллической решётки не ортогональны?  ;)


Название: Re: От С++ к Qt C++
Отправлено: Igors от Март 18, 2013, 21:07
А если вектора кристаллической решётки не ортогональны?  ;)
На здоровье - задавайте неортогональные axisX(Y, Z)


Название: Re: От С++ к Qt C++
Отправлено: Skrypnyk от Март 18, 2013, 23:22
Igors, тогда еще вопрос: -QVector3D::dotProduct(nor, vec[0]) - тоже получается расстояние в функции QVector4D(nor, -QVector3D::dotProduct(nor, vec[0]))?
И еще хочу поинтересоваться: в чем смысл трех вложенных циклов for? Я задаю столько вопросов, потому что не силен в программировании, а мне нужно знать какие процессы описываются приведенным Вами кодом. Я не сомневаюсь, что он дает результат. Но хочется узнать что он делает, чтобы получить конечный результат. Еще раз спасибо.


Название: Re: От С++ к Qt C++
Отправлено: Igors от Март 19, 2013, 11:53
-QVector3D::dotProduct(nor, vec[0]) - тоже получается расстояние в функции QVector4D(nor, -QVector3D::dotProduct(nor, vec[0]))?
Уравнение плоскости ax + by + cz + d = 0;
Отсюда d = -(ax + by + cz);
В правой части скалярное произведение нормали к плоскости (a, b, c) на точку лежащую на ней (x, y, z)

И еще хочу поинтересоваться: в чем смысл трех вложенных циклов for?
В том что (судя по картинкам в Вике) отрезки Миллера могут задавать множество (семейство) секущих плоскостей, напр (1, 1, 2) уже 2 плоскости


Название: Re: От С++ к Qt C++
Отправлено: Skrypnyk от Март 19, 2013, 21:14
Ага, спасибо, Ваша правда)).

А по поводу индексов Миллера, то это величины, обратные к отрезкам, отсекаемым плоскостью на координатных осях. Например, если мы запишем плоскость (2, 2, 2) используя индексы Миллера в круглых скобках, то мы обозначим единственную плоскость, которая пересекает оси в точках (1/2; 0; 0), (0; 1/2; 0) и (0; 0; 1/2). Если же записать {2, 2, 2} в фигурных скобках, тогда речь идет о семействе плоскостей (они являются семейством в силу симметрии): (-2, -2, -2), (-2, 2, -2), (-2, -2, 2)... (2, 2, 2).

Поэтому 3 вложенных цикла, я полагаю, можно убрать.

Да, еще хотелось бы заметить, что нормаль к плоскости (2, 2, 2) - это вектор [2, 2, 2]. В последнем случае 3 числа в квадратных скобках обозначают вектор с началом в точке (0; 0; 0) и концом в точке (2; 2; 2).


Название: Re: От С++ к Qt C++
Отправлено: Igors от Март 20, 2013, 12:45
А по поводу индексов Миллера, то это величины, обратные к отрезкам, отсекаемым плоскостью на координатных осях. Например, если мы запишем плоскость (2, 2, 2) используя индексы Миллера в круглых скобках, то мы обозначим единственную плоскость, которая пересекает оси в точках (1/2; 0; 0), (0; 1/2; 0) и (0; 0; 1/2). Если же записать {2, 2, 2} в фигурных скобках, тогда речь идет о семействе плоскостей (они являются семейством в силу симметрии): (-2, -2, -2), (-2, 2, -2), (-2, -2, 2)... (2, 2, 2).
А я чего-то, бегло глянув Вику, подумал не так - ну Вам виднее  :)

Да, еще хотелось бы заметить, что нормаль к плоскости (2, 2, 2) - это вектор [2, 2, 2]. В последнем случае 3 числа в квадратных скобках обозначают вектор с началом в точке (0; 0; 0) и концом в точке (2; 2; 2).
Тогда еще проще получается - сразу готовая нормаль и точка (напр cntr + (1/2, 0, 0)).  Займитесь визуализацией исходных точек и тех что лежат на секущих плоскостях. Считайте все в реальных/исходных координатах (в тех что задавали точки) и получайте в пикселях только перед выводом. A когда дело дойдет до разворота плоскости - я Вам матрицу нарисую.

Edit: нормаль готова "прямо из отрезков" только если оси ортогональны, иначе придется все равно находить 3 точки как выше