Отображение графических объектов
Видовая система координат
Пусть мы наблюдаем некоторую сцену, предметы которой описываются как совокупность точек, а координаты точек задаются в некоторой глобальной системе координат, которую называют мировой (World Coordinates, WC). Отметим, что кроме мировой системы координат часто для отдельных предметов вводят локальные системы. Например, ствол орудия танка может быть описан как цилиндр. Это описание легко выполнить в системе координат, ось которой совпадает с осью ствола. Но положение ствола может меняться относительно башни танка, башня может вращаться, а сам танк двигаться. Поэтому, для описания положения ствола орудия танка на местности (в мировых координатах), нужно от системы координат ствола перейти к системе координат башни, затем к системе координат танка, а уже затем получить его мировые координаты. Далее предполагается, что такого рода преобразования выполнены, и нам заданы мировые координаты точки, которые мы будем обозначать через $(x, y, z)$.
Изображение сцены строится на плоскости (плоскость экрана), которую называют видовой плоскостью (View Plane), как изображено справа. С плоскостью наблюдения связана видовая система координат (View Reference Coordinates, VRC). Координаты точки в видовой системе координат будем обозначать через $(X, Y, Z)$. В OpenCascade предполагается, что начало ее находится в центре прямоугольника области просмотра, ось $Z$ направлена по нормали к плоскости, так что оси $X$ и $Y$ лежат в плоскости вида, ось $Y$ определяет направление "вверх" на экране.
Таким образом, положение видовой системы координат относительно мировой задается тремя векторами:
- Положением начала видовой системы координат (положение центра экрана, точка At, View Reference Point, VRP).
- Направлением нормали к видовой плоскости (View Plane Normal, VPN), направлением оси $Z$.
- Направлением "вверх" для видовой плоскости (View Up Vector, VUP), т.е. направлением оси $Y$ видовой системы координат.

Опросить / задать параметры видовой системы координат можно с помощью процедур объекта класса V3d_View:
// Начало видовой системы координат
void At(Standard_Real& X, Standard_Real& Y, Standard_Real& Z)
void SetAt( const V3d_Coordinate X, const V3d_Coordinate Y, const V3d_Coordinate Z )
// Нормаль к плоскости проекции
void Proj( Quantity_Parameter& Vx, Quantity_Parameter& Vy, Quantity_Parameter& Vz )
void SetProj(const Quantity_Parameter Vx, const Quantity_Parameter Vy, const Quantity_Parameter Vz )
// Направление вектора "вверх"
void Up( Quantity_Parameter& Vx, Quantity_Parameter& Vy, Quantity_Parameter& Vz )
void SetUp( const Quantity_Parameter Vx, const Quantity_Parameter Vy, const Quantity_Parameter Vz )
Построим диметрическую проекцию параллелепипеда. В этой проекции масштабы искажения по осям $x$ и $z$ равны, а нормаль к плоскости изображения имеет направление $(1/3,\sqrt{7}/3, 1/3)$.
// Устанавливаем проекцию (диметрия)
gp_Pnt at;
at.SetCoord(0.0, 0.0, 0.0);
gp_Dir axisX, axisY, axisZ;
axisY.SetCoord(0.0, 0.0, 1.0);
axisZ.SetCoord(1.0, sqrt(7.0), 1.0);
axisX = axisY ^ axisZ;
myView->SetSize(5.); // Размеры области экрана
myView->SetAt (at.X(),at.Y(),at.Z());
myView->SetProj(axisZ.X(), axisZ.Y(), axisZ.Z());
myView->SetUp (axisY.X(), axisY.Y(), axisY.Z());
//
// Рисуем оси координат
Handle(Geom_Axis2Placement) axes;
axes = new Geom_Axis2Placement(gp::XOY());
Handle(AIS_Trihedron) aisTrihedron;
aisTrihedron = new AIS_Trihedron(axes);
aisTrihedron->SetSize(1.0);
myAISContext->Display(aisTrihedron);
//
// Создаем параллелепипед
BRepPrimAPI_MakeBox box(0.80, 0.60, 0.40);
Handle(AIS_Shape) aisBox = new AIS_Shape(box.Shape());
myAISContext->Display(aisBox);
myAISContext->SetColor(aisBox,Quantity_Color(Quantity_NOC_GREEN));

Построим преобразование перехода от мировой системы координат к видовой. В диметрческой проекции конец единичного вектора оси $x$ пректируется в точку $(-\sqrt{7/2}/2, -1/(6\sqrt{2}) )=(-0.9354,-0.1178)$. Проверим это.
// Создадим видовую систему координат
gp_Ax3 frameView(at, axisZ, axisX);
// Преобразоание координат вектора из мировой в видовую систему
gp_Trsf trsfW2V;
trsfW2V.SetTransformation(frameView);
gp_Pnt pntWorld(1.,0.,0.);
gp_Pnt pntView = pntWorld.Transformed(trsfW2V); // x=-0.9354, y=-0.1178, z=0.3333
С видовой системой координат связаны еще два понятия: точка наблюдения (положение глаза, eye) и плоскость отсечения. Точка наблюдения (глаз) всегда располагается на оси $Z$. Расстояние от этой точки до плоскости вида называется глубиной (depth). Опрос/задание положения глаза выполняется процедурами
// Опрос положения глаза (eye) в мировых координатах
void Eye(V3d_Coordinate& X,V3d_Coordinate& Y,V3d_Coordinate& Z)
// Опрос расстояние между точками eye и at
Quantity_Length Depth()
// Задание положения глаза
void SetEye( const V3d_Coordinate X, const V3d_Coordinate Y, const V3d_Coordinate Z )
// Задание расстояния между точками eye и at
void SetDepth(const Quantity_Length Depth)
Установкой нового положения глаза можно изменить ориентацию плоскости наблюдения (направление оси $Z$). Кроме этого, положение глаза влияет на построение проекции, но об этом мы будем говорить в соответствующем разделе.
Плоскости отсечения ограничивают область пространства, точки которого участвуют в отображении. В OpenCascade могут быть заданы передняя и задняя плоскости отсечения (ZClipping), а также набор других плоскостей.
Рассмотрим использование передней и задней плоскостей отсечения. Они описываются в понятиях видовой системы координат, т.е. они параллельны плоскости вида и задаются относительно нее. Возможны четыре режима отсечения, соответствующие значениям перечисляемого типа V3d\_TypeOfZclipping:
- V3d_OFF — плоскости отсечения не используются;
- V3d_BACK — используется только задняя плоскость отсечения;
- V3d_FRONT — используется только передняя плоскость отсечения;
- V3d_SLICE — используется обе плоскости отсечения;
Режим использования передней и задней плоскостей отсечения устанавливается процедурой класса V3d_View:
// задание режима ZClipping
void SetZClippingType(const V3d_TypeOfZclipping Type)
Положение плоскостей отсечения указывается следующим образом. Вводится "средняя" (medium) плоскость отсечения, а передняя и задняя плоскости лежат от нее на на расстоянии $w/2$, где $w$ — расстояние между плоскостями. Напомним, что все три плоскости (средняя, передняя и задняя) параллельны плоскости проектирования, плоскости вида. Таким образом, положение плоскостей отсечения задается процедурами
// Задание положения средней плоскости
// отсечения относительно видовой
void SetZClippingDepth(
const Quantity_Length Depth)
// Задание расстояния между плоскостями
void SetZClippingWidth(
const Quantity_Length Width)
а информация об их положении опрашивается так:
// Получение информации о ZClipping
// <Depth> : расстояние до средней плоскости
// <Width> : расстояние между плоскостями
// <TypeOfZclipping> : режим отсечения
V3d_TypeOfZclipping ZClipping(
Quantity_Length& Depth,Quantity_Length& Width)

Рассмотрим пример. У построенного выше изображения параллелепипеда введем переднюю и заднюю плоскости отсечения. Среднюю плоскость проведем через центр параллелепипеда, а расстояние между плоскостями положим равным расстоянию $d$ от видовой плоскости до центра , так что задняя плоскость будет на $0.5d$, а передняя на расстоянии $1.5d$ от видовой плоскости, и они пересекут параллелепипед. Для наглядности мы постром независмо эти сечения и нарисуем задний многоугольник сечения красным цветом, а передний — синим. Приводимый ниже участок программы является продолжением предыдущих.
// Видовая система координат
gp_Ax3 frameView(at, axisZ, axisX);
// Преобразоание координат вектора из мировой
// в видовую систему
gp_Trsf trsfW2V;
trsfW2V.SetTransformation(frameView);
// Точка: центр параллелепипеда
gp_Pnt center(0.40, 0.30, 0.20);
center.Transform(trsfW2V);
//
// --- Задаем режим обеих плоскостей отсечения
myView->SetZClippingType(V3d_SLICE);
// Положение средней плоскости отсечения:
// через центр
myView->SetZClippingDepth(center.Z());
// Задание расстояния между плоскостями отсечения
Quantity_Length width = center.Z();
myView->SetZClippingWidth(width);
//

//
// --- Нарисуем многоугольники сечения
// Преобразоание координат вектора из видовой в мировую систему
gp_Trsf trsfV2W;
trsfV2W = trsfW2V.Inverted();
// Дальняя плоскость в мировых координатах
gp_Dir nrmPlane = gp_Dir(0.,0.,1.).Transformed(trsfV2W);
gp_Pnt pntPlane(0.,0.,center.Z()/2.+0.001);
pntPlane.Transform(trsfV2W);
gp_Pln farPlane(pntPlane, nrmPlane);
Handle (Geom_Plane) geomPlane = new Geom_Plane(farPlane);
// Пересечение плоскости с параллелепипедом
BRepAlgoAPI_Section farSection(box,geomPlane,Standard_False);
farSection.ComputePCurveOn1(Standard_True);
farSection.Approximation(TopOpeBRepTool_APPROX);
farSection.Build();
// Рисуем пересечение
Handle(AIS_Shape) aisSection = new AIS_Shape(farSection.Shape());
myAISContext->SetDisplayMode(aisSection ,0,Standard_False);
myAISContext->SetColor(aisSection,Quantity_NOC_RED,Standard_False);
myAISContext->Display(aisSection,Standard_False);
// Ближняя плоскость
pntPlane.SetCoord(0.,0.,3.*center.Z()/2.-0.001);
pntPlane.Transform(trsfV2W);
gp_Pln nearPlane(pntPlane, nrmPlane);
geomPlane = new Geom_Plane(nearPlane);
// Пересечение плоскости с параллелепипедом
BRepAlgoAPI_Section nearSection(box,geomPlane,Standard_False);
nearSection.ComputePCurveOn1(Standard_True);
nearSection.Approximation(TopOpeBRepTool_APPROX);
nearSection.Build();
// Рисуем пересечение
aisSection = new AIS_Shape(nearSection.Shape());
myAISContext->SetDisplayMode(aisSection ,0,Standard_False);
myAISContext->SetColor(aisSection,Quantity_NOC_BLUE1,Standard_False);
myAISContext->Display(aisSection,Standard_False);