Отображение графических примитивов (точки, линии)
Мы рассмотрим предоставляемые OpenCascade средства для отображения графических примитивов, непосредственно предоставляемых библиотекой OpenGL, а именно (в скобках указан тип в OpenGL):
- точки (GL_POINTS) — отдельные точки,
- линии (GL_LINES ) — пары точек рассматриваются как концы отрезков,
- ломаная (GL_LINE_STRIP) — последовательность точек рассматривается как вершины ломаной,
- линия-многоугольник (GL_LINE_LOOP) — аналогично предыдущему, но, кроме того, автоматически добавляется отрезок, соединяющий первую и последнюю вершины (замкнутая ломаная),
- треугольники (GL_TRIANGLES ) — каждая тройка точек рассматривается как вершины треугольника,
- соединенные треугольники (GL_TRIANGLE_STRIP) — цепочка соединенных треугольников,
- веер треугольников (GL_TRIANGLE_FAN) — веер соединенных треугольников,
- четырехугольники (GL_QUADS) — каждая четверка точек рассматривается как вершины четырехугольника,
- цепочка четырехугольников (GL_QUAD_STRIP ) — цепочка соединенных четырехугольников,
- область-многоугольник (GL_POLYGON ) — последовательность точек рассматривается как вершины линии-многоугольника, ограничивающей участок поверхности.
Класс управления отображением (Visual3d_ViewManager)
Общая логика построения изображения в упрощенном виде выглядит так. Объект класса V3d_Viewer (см. раздел), ссылается на объект класса построения изображения Visual3d_ViewManager. Если, как и ранее, мы будем придерживаться понятий MFC, класс документа будем называть COCCDoc, то в файлах должно быть записано что-то вроде
// OCCDoc.h
Handle(V3d_Viewer) myViewer;
. . . . .
// OCCDoc.cpp
COCCDoc::COCCDoc()
{
//
Handle(Graphic3d_GraphicDriver) aGraphicDriver =
((CMyTestApp*)AfxGetApp())->GetGraphicDriver();
//
myViewer = new V3d_Viewer(...
. . . . .
}
void COCCDoc::CreateScene( void )
{
Handle(Visual3d_ViewManager) viewManager = myViewer->Viewer();
. . . . .
}
где процедура CreateScene предназначена для построения сцены — описания отображаемых объектов.
Класс Visual3d_ViewManager содержит перечень структур, объектов класса Graphic3d_Structure. Структура состоит из групп, объектов класса Graphic3d_Group. Группа содержит примитивы и их атрибуты (свойства).
Поясним сказанное примером. Пусть мы хотим отобразить массив точек. Для этого
- Получаем указатель на объект класса построения изображения
void COCCDoc::CreateScene( void )
{
Handle(Visual3d_ViewManager) viewManager = myViewer->Viewer();
- Создаем структуру
Handle(Graphic3d_Structure) structure = new Graphic3d_Structure(viewManager);
viewManager->Display(structure); // Структуру нужно отображать
- Создаем массив точек. Пусть это будут вершины куба со срезанным углом
//
// Вершины
gp_Pnt point[10];
Standard_Real l_side = 1.0; // Длина стороны куба
Standard_Real l_cut = 0.75; // Длина срезанной стороны
point[0].SetCoord(0.0,0.0,0.0);
point[1].SetCoord(l_side,0.0,0.0);
point[2].SetCoord(l_side,l_side,0.0);
point[3].SetCoord(0.0,l_side,0.0);
point[4].SetCoord(0.0,0.0,l_side);
point[5].SetCoord(l_side,0.0,l_side);
point[6].SetCoord(l_side,l_cut,l_side);
point[7].SetCoord(l_cut,l_side,l_side);
point[8].SetCoord(0.0,l_side,l_side);
point[9].SetCoord(l_side,l_side,l_cut);
- Мы разделим точки на две подгруппы: точки нижнего онования (их четыре) и остальные. У каждой подгруппы установим свои атрибуты. К атрибутам точки относятся: тип (символ отображения), цвет и размер. Точки первой подгруппы будем отображать в виде кружочка с плюсиком (Aspect_TOM_O_PLUS) красным цветом:
Handle(Graphic3d_Group) group = new Graphic3d_Group(structure); // группа
Handle(Graphic3d_AspectMarker3d) aspectMarker = new
Graphic3d_AspectMarker3d(Aspect_TOM_O_PLUS , Quantity_NOC_RED , 2.); // атрибуты
group->SetPrimitivesAspect(aspectMarker); // Устанавливаем атрибуты
// Образуем массив точек
Handle(Graphic3d_ArrayOfPoints) arrayOfPoints = new Graphic3d_ArrayOfPoints(4);
for( int i=0; i<4; i++ )
arrayOfPoints->AddVertex(point[i]);
group->AddPrimitiveArray (arrayOfPoints); // Добавляем массив в группу
- Точки второй подгруппы будем отображать зеленым кружочком:
aspectMarker->SetType(Aspect_TOM_O);
aspectMarker->SetColor(Quantity_NOC_GREEN);
group->SetPrimitivesAspect(aspectMarker);
arrayOfPoints = new Graphic3d_ArrayOfPoints(6);
for( int i=4; i<10; i++ )
arrayOfPoints->AddVertex(point[i]);
group->AddPrimitiveArray (arrayOfPoints);
На рисунке справа показан результат.
Опишем некоторые методы класса Visual3d_ViewManager, связанные с понятием структуры. Как уже было сказано, структура создается со ссылкой на Visual3d_ViewManager, и для добавления ее в множество отображаемых предназначен метод
void Display(const Handle(Graphic3d_Structure)& AStructure)
Указатель на само множество отображаемых структур можно получить методом
void DisplayedStructures(Graphic3d_MapOfStructure& SG)
Перебор элементов множества выполняется с помощью итератора. Например
// Получаем множество структур
Graphic3d_MapOfStructure mapOfStructure;
ViewManager->DisplayedStructures(mapOfStructure);
//
Graphic3d_MapIteratorOfMapOfStructure mapIterator; // итератор по множеству
Handle(Graphic3d_Structure) curStructure; // текущая структура
// Цикл по множеству структур
for( mapIterator.Initialize(mapOfStructure); mapIterator.More(); mapIterator.Next() ) {
curStructure = mapIterator.Key();
}
Отображаемая структура ( Graphic3d_Structure)
Структура создается со ссылкой на объект управления отображением. Она должна быть включена в его перечень отображаемых структур:
// Создание структуры
Handle(Graphic3d_Structure) structure = new Graphic3d_Structure(viewManager);
viewManager->Display(structure); // Структуру нужно отображать
Структура содержит группы отображаемых объектов. Число групп можно опросить методом
// Число групп в структуре
Standard_Integer NumberOfGroups ()
Перечень групп доступен методом
// Множество групп, содержащихся в структуре
Graphic3d_SequenceOfGroup & Groups ()
Цикл по последовательности групп структуры организуется с помощью номера. Например
// Число групп в структуре
int nbGroup = structure->NumberOfGroups();
// Множество групп, содержащихся в структуре
Graphic3d_SequenceOfGroup sequenceOfGroup;
sequenceOfGroup = structure->Groups();
Handle(Graphic3d_Group) curGroup; // Текущая группа
// Цикл по группам
for( int i=1; i<=nbGroup; i++ ) {
curGroup = sequenceOfGroup(i);
}
Структура, как объединение графических объектов, имеет локальную систему координат, относительно которой задаются положения точек. По умолчанию это мировая система координат. Имеется возможность задать преобразование, которое будет применено ко всем элементам структуры. Для этого служит метод
void SetTransform(const TColStd_Array2OfReal &AMatrix,
const Graphic3d_TypeOfComposition AType)
Здесь параметр AMatrix — матрица преобразования размера $4\times 4$, а AType — одно из значений: Graphic3d_TOC_REPLACE или Graphic3d_TOC_POSTCONCATENATE. В первом случае матрица задает абсолютное преобразование, т.е. переход от мировой системы координат, а во втором преобразование добавляется к текущему.
Напомним, что в результате преобразования точка с координатами $( x_A, y_A, z_A)$ переходит в точку с координатами $(x_B, y_B, z_B)$ согласно
(1)Матрица поворота $a_{ij}$ размера $3\times 3$ должна быть ортогональной, а вектор $(t_x, t_y, t_z)$ задает перенос начала координат. В частности, матрицы поворота вокруг осей $x$, $y$ и $z$ выглядят так:
(2)Рассмотрим пример выполнения поворота на угол $45^\circ$ вокруг оси $z$ (против часовой стрелки, если смотреть с положительного направления оси $z$)
double angle = M_PI / 4.; // угол поворота
TColStd_Array2OfReal matrix(1, 4, 1, 4); // матрица 4 на 4
matrix.Init(0.); // обнуляем элементы матрицы
// Матрица поворота вокруг оси z
double cos_a = cos(angle);
double sin_a = sin(angle);
matrix(1,1) = matrix(2,2) = cos_a;
matrix(1,2) = -sin_a;
matrix(2,1) = sin_a;
matrix(3,3) = matrix(4,4) = 1.;
// Выполняем преобразование
structure->SetTransform(matrix,Graphic3d_TOC_POSTCONCATENATE);
Группа примитивов (Graphic3d_Group)
Группа содержит наборы графических примитивов и их атрибуты. Группа создается в структуре, так что конструктор ее выглядит так:
Graphic3d_Group (const Handle< Graphic3d_Structure > &AStructure)
Добавление в группу массива примитивов выполняется процедурой
void AddPrimitiveArray (const Handle< Graphic3d_ArrayOfPrimitives > &elem)
Класс Graphic3d_ArrayOfPrimitives является базовым для следующих классов (описание классов приведено далее)
- Graphic3d_ArrayOfPoints — массив точек.
- Graphic3d_ArrayOfSegments — массив отрезков.
- Graphic3d_ArrayOfPolylines — одна или несколько ломаных.
- Graphic3d_ArrayOfTriangles — один или несколько отдельных треугольников.
- Graphic3d_ArrayOfTriangleStrips — одна или несколько цепочек треугольников.
- Graphic3d_ArrayOfTriangleFans — один или несколько вееров треугольников.
- Graphic3d_ArrayOfQuadrangles — один или несколько отдельных четырехугольников.
- Graphic3d_ArrayOfQuadrangleStrips — одна или несколько цепочек четырехугольников.
- Graphic3d_ArrayOfPolygons — один или несколько многоугольников.
Кроме того, группу может образовывать текст.
Атрибуты могут относиться к различным типам примитивов
// Свойства отображения точки
void SetPrimitivesAspect(const Handle< Graphic3d_AspectMarker3d > &CTX)
// Свойства отображения линии
void SetPrimitivesAspect(const Handle< Graphic3d_AspectLine3d > &CTX)
// Свойства отображения поверхности
void SetPrimitivesAspect(const Handle< Graphic3d_AspectFillArea3d > &CTX)
// Свойства отображения текста
void SetPrimitivesAspect(const Handle< Graphic3d_AspectText3d > &CTX)
Рассмотрим последовательно перечисленные выше варианты.
Отображение точек
Атрибутами изображения точки являются: тип (символ отображения), цвет и размер. Они задаются переменными класса Graphic3d_AspectMarker3d, конструкторы которого выглядят так:
Graphic3d_AspectMarker3d ()
Graphic3d_AspectMarker3d (const Aspect_TypeOfMarker theType,
const Quantity_Color &theColor, const Standard_Real theScale)
Здесь theType — тип маркера, перечисляемое значение: Aspect_TOM_POINT - точка, Aspect_TOM_PLUS -
плюсик, Aspect_TOM_STAR - звездочка и так далее (по умолчанию крестик); theColor — цвет (по умолчанию желтый), а theScale — размер (по умолчанию единица).
Добавление точек в массив типа Graphic3d_ArrayOfPoints выполняется операциями вида
Standard_Integer AddVertex (const gp_Pnt &aVertice)
Standard_Integer AddVertex (const Standard_Real X, const Standard_Real Y,
const Standard_Real Z)
Возвращаемое значение — номер точки в массиве.
Пример рисования точек приведен выше.
Отображение линий
Атрибутами отображения линий служат: тип (сплошная, штриховая и т.д.), цвет и толщина. Они задаются значениями переменных класса Graphic3d_AspectLine3d конструкторы которого выглядят так:
Graphic3d_AspectLine3d ()
Graphic3d_AspectLine3d (const Quantity_Color &AColor,
const Aspect_TypeOfLine AType, const Standard_Real AWidth)
Здесь AColor — цвет (по умолчанию желтый), AType — тип линии, перечисляемое значение: Aspect_TOL_SOLID - сплошная, Aspect_TOL_DASH - штриховая, Aspect_TOL_DOT - пунктирная (по умолчанию сплошная); а AWidth — толщина (по умолчанию единица).
Для отображения отрезков используется массив типа Graphic3d_ArrayOfSegments, каждая пара точек которого рассматривается как концы отрезков.
В качестве примера построим ребра куба со скошенной вершиной, точки которого заданы в примере выше
Handle(Graphic3d_AspectLine3d) aspectLine = new
Graphic3d_AspectLine3d(Quantity_NOC_GREEN, Aspect_TOL_DASH, 2.);
group->SetGroupPrimitivesAspect(aspectLine);
// У нас 15 ребер, т.е. 30 точек
Handle(Graphic3d_ArrayOfSegments) arrayOfSegments = new Graphic3d_ArrayOfSegments(30);
arrayOfSegments->AddVertex(point[0]);
arrayOfSegments->AddVertex(point[1]);
arrayOfSegments->AddVertex(point[1]);
arrayOfSegments->AddVertex(point[2]);
arrayOfSegments->AddVertex(point[2]);
arrayOfSegments->AddVertex(point[3]);
arrayOfSegments->AddVertex(point[3]);
arrayOfSegments->AddVertex(point[0]);
arrayOfSegments->AddVertex(point[0]);
arrayOfSegments->AddVertex(point[4]);
arrayOfSegments->AddVertex(point[1]);
arrayOfSegments->AddVertex(point[5]);
arrayOfSegments->AddVertex(point[2]);
arrayOfSegments->AddVertex(point[9]);
arrayOfSegments->AddVertex(point[3]);
arrayOfSegments->AddVertex(point[8]);
arrayOfSegments->AddVertex(point[4]);
arrayOfSegments->AddVertex(point[5]);
arrayOfSegments->AddVertex(point[5]);
arrayOfSegments->AddVertex(point[6]);
arrayOfSegments->AddVertex(point[6]);
arrayOfSegments->AddVertex(point[7]);
arrayOfSegments->AddVertex(point[7]);
arrayOfSegments->AddVertex(point[8]);
arrayOfSegments->AddVertex(point[8]);
arrayOfSegments->AddVertex(point[4]);
arrayOfSegments->AddVertex(point[6]);
arrayOfSegments->AddVertex(point[9]);
arrayOfSegments->AddVertex(point[9]);
arrayOfSegments->AddVertex(point[7]);
group->AddPrimitiveArray (arrayOfSegments);
На рисунке справа показан результат.
Для отображения одной или нескольких ломаных линий используется массив типа Graphic3d_ArrayOfPolylines. Ломаная (нескольких ломаных) могут быть заданы различными способами:
- Одна ломаная как набор узлов. Например, нижнее основание кубика предыдущего примера может быть описано как
// В основании 4 ребра, 5 точек
Handle(Graphic3d_ArrayOfPolylines) arrayOfPolylines =
new Graphic3d_ArrayOfPolylines(5);
arrayOfPolylines->AddVertex(point[0]);
arrayOfPolylines->AddVertex(point[1]);
arrayOfPolylines->AddVertex(point[2]);
arrayOfPolylines->AddVertex(point[3]);
arrayOfPolylines->AddVertex(point[0]);
group->AddPrimitiveArray (arrayOfPolylines);
- Несколько ломаных, с указанием числа узлов в каждой из них. Например, нижнее и верхнее основания кубика предыдущего примера моут быть отображены следующим образом:
// В основаниях 2 ломаных, всего 11 точек
Handle(Graphic3d_ArrayOfPolylines) arrayOfPolylines =
new Graphic3d_ArrayOfPolylines(11,2);
arrayOfPolylines->AddBound(5); // ломаная из пяти точек, нижнее основание
arrayOfPolylines->AddVertex(point[0]);
arrayOfPolylines->AddVertex(point[1]);
arrayOfPolylines->AddVertex(point[2]);
arrayOfPolylines->AddVertex(point[3]);
arrayOfPolylines->AddVertex(point[0]);
arrayOfPolylines->AddBound(6); // ломаная из шести точек, верхнее основание
arrayOfPolylines->AddVertex(point[4]);
arrayOfPolylines->AddVertex(point[5]);
arrayOfPolylines->AddVertex(point[6]);
arrayOfPolylines->AddVertex(point[7]);
arrayOfPolylines->AddVertex(point[8]);
arrayOfPolylines->AddVertex(point[4]);
group->AddPrimitiveArray (arrayOfPolylines);
Обращаем внимание на то, что в OpenCascade, по-видимому, нет объекта, соответствующего замкнутой ломаной (GL_LINE_LOOP).