Геометрические примитивы
Создание класса, производного от Geom_Curve
Если мы хотим создать собственный класс кривой, наследующий свойства класса Geom_Curve, мы должны реализовать его чисто виртуальные функции. Перечислим их.
Во-первых, есть две чисто виртуальные функции, которые наследуются от класса Geom_Geometry. Это
- Выполнение преобразование кривой как геометрического объекта, т.е. смещение, поворот, масштабирование, отражение или комбинация этих преобразований:
// Выполнение преобразования кривой
void Transform (const gp_Trsf &T)
- Создание копии кривой как геометрического объекта:
// Создание копии кривой
Handle_Geom_Geometry Copy () const
У самого класса Geom_Curve имеются следующие чисто виртуальные функции, которые должны быть реализованы в производном классе
- Минимальное значение параметра на кривой. Если кривая бесконечна, это может быть значение, возвращаемое процедурой RealFirst() — минимальное вещественное число. Например, для прямой минимальное значение равно -Precision::Infinite().
// Процедура возвращает минимальное значение параметра на кривой.
Standard_Real FirstParameter() const
- Максимальное значение параметра на кривой. Если кривая бесконечна, это может быть значение, возвращаемое процедурой RealLast() — максимальное вещественное число. Для прямой это значение равно Precision::Infinite().
// Процедура возвращает максимальное значение параметра на кривой.
Standard_Real LastParameter() const
- Признак замкнутости кривой. Некоторые кривые (например, окружность) всегда замкнуты, другие — всегда незамкнуты. Кривая может считаться замкнутой, если расстояние между ее крайними точками меньше gp::Resolution()
// Возвращает значение true для замкнутой кривой
Standard_Boolean IsClosed() const
- Признак периодичности кривой. Периодическая кривая должна быть замкнутой и расстояние между точками P(u) и P (u + T), где T — период, должно быть меньше значения gp::Resolution(). Величина периода должна вычисляться функцией Standard_Real Period () const. По умолчанию она возвращает разность между максимальным и минимальным значениями параметра.
// Возвращает значение true для периодической кривой
Standard_Boolean IsPeriodic() const
- Гладкость кривой. Она характеризуется значением перечисляемого типа:
enum GeomAbs_Shape {
GeomAbs_C0, GeomAbs_G1, GeomAbs_C1, GeomAbs_G2, GeomAbs_C2, GeomAbs_C3, GeomAbs_CN
}
имеющими следующий смысл:
— C0 : кривая непрерывна;
— G1 : кривая имеет непрерывно изменяющуюся касательную;
— C1 : кривая имеет непрерывную первую производную;
— G2 : кривизна кривой изменяется непрерывно:
— C2 : кривая имеет непрерывную вторую производную;
— C3 : кривая имеет непрерывную третью производную;
— CN : кривая бесконечно дифференцируема.
(Не совсем понятно, в чем состоит разница между G1 и C1, а также G2 и C2.)
// Функция возвращает значение гладкости кривой
GeomAbs_Shape Continuity() const
// Возвращает true если степень гладкости кривой не менее N
Standard_Boolean IsCN(const Standard_Integer N) const
- Следующий набор процедур вычисляет значение точки кривой и производных для данного значения параметра.
// Процедура вычисляет значение точки P на кривой для значения параметра U
void D0(const Standard_Real U,gp_Pnt& P) const
// Процедура вычисляет значение точки P и вектора первой производной V1
// для значения параметра U
void D1(const Standard_Real U,gp_Pnt& P,gp_Vec& V1) const
// Процедура вычисляет значение точки P, первой V1 и второй V2 производных
// для значения параметра U
void D2(const Standard_Real U,gp_Pnt& P,gp_Vec& V1,gp_Vec& V2)
// Процедура вычисляет значение точки P, первой V1, второй V2 и
// третьей V3 производных для значения параметра U
void D3(const Standard_Real U,gp_Pnt& P,gp_Vec& V1,gp_Vec& V2,gp_Vec& V3) const = 0;
// Процедура вычисляет значение N-ой производной для значения параметра U
gp_Vec DN(const Standard_Real U,const Standard_Integer N)
- Следующие две процедуры связаны с обращением параметризации. Первая меняет параметризацию на обратную, т.е. если первоначально значению параметра FirstParameter отвечала точка StartPoint, а параметру LastParameter точка EndPoint, то после обращения параметру FirstParameter отвечает точка EndPoint, а параметру LastParameter точка StartPoint. Вторая возвращает значение параметра на обращенной кривой по первоначальному параметру, так что точки me->Value(U) и me->Reversed()->Value(me->ReversedParameter(U)) совпадают.
// Изменениие направления параметризации
void Reverse()
// Значение параметра на обращенной кривой
Standard_Real ReversedParameter(const Standard_Real U) const
В качестве примера создадим класс, описывающий винтовую линию. Винтовая линия определяется:
— радиусом $R$;
— шагом $h$;
— ориентацией (левый, правый винт) $\alpha=\pm 1$
— локальной системой координат gp_Ax2 ax2, в которой уравнение кривой имеет вид:
Соответственно, должно храниться преобразование перехода от локальных $(x_l, y_l, z_l, O_l)$ к мировым $(x_w, y_w, z_w, O_w)$ координатам: если локальная система координат имеет оси
$\mathbf{e}_x=(e_{xx},e_{xy},e_{xz})$ (gp_Dir xDir = ax2.XDirection()),
$\mathbf{e}_y=(e_{yx},e_{yy},e_{yz})$ (gp_Dir yDir = ax2.YDirection()),
$\mathbf{e}_z=(e_{zx},e_{zy},e_{zz})$ (gp_Dir zDir = ax2.Direction())
и начало координат в точке
$O=(O_x, O_y, O_z)$ (gp_Pnt origin = ax2.Axis().Location()),
то мировые координаты точки связаны с локальными преобразованием:
Первая производная равна
(3)Четная (вторая и выше) производная ($k$ — четное) равна
(4)а нечетная (третья и выше) производная ($k$ — нечетное)
(5)Описание класса винтовой линии (заголовочный файл) может иметь вид:
class vkScrewLine : public Geom_Curve
{
public:
// Конструктор / деструктор
vkScrewLine();
virtual ~vkScrewLine();
//
// --- Реализация абстрактных методов базового класса
// Признак замкнутости кривой
Standard_Boolean IsClosed() const { return Standard_False; }
// Признак периодичности кривой
Standard_Boolean IsPeriodic() const { return Standard_False; }
// Гладкость кривой
GeomAbs_Shape Continuity() const { return GeomAbs_CN; }
Standard_Boolean IsCN(const Standard_Integer N) const { return Standard_True; };
// Минимальное / максимальное значения параметра на кривой.
Standard_Real FirstParameter() const;
Standard_Real LastParameter() const;
// Уравнение кривой
void D0(const Standard_Real U,gp_Pnt& P) const;
void D1(const Standard_Real U,gp_Pnt& P,gp_Vec& V1) const;
void D2(const Standard_Real U,gp_Pnt& P,gp_Vec& V1,gp_Vec& V2) const;
void D3(const Standard_Real U,gp_Pnt& P,gp_Vec& V1,gp_Vec& V2,gp_Vec& V3) const;
gp_Vec DN(const Standard_Real U,const Standard_Integer N) const;
// Обращение параметра
void Reverse();
Standard_Real ReversedParameter(const Standard_Real U) const;
// Преобразование кривой как геометрического объекта
void Transform (const gp_Trsf& T);
// Копирование кривой как геометрического объекта
Handle(Geom_Geometry) Copy() const;
//
// --- Задание / опрос данных класса
// Радиус
void SetRadius(Standard_Real radius);
Standard_Real Radius( )
{ return myRadius; }
// Шаг винта
void SetLead(Standard_Real lead);
Standard_Real Lead( void)
{ return myLead; }
// Ориентация (правый/левый) винта
void SetIsRight( Standard_Boolean isRight);
Standard_Boolean IsRight( void )
{ return myIsRight; }
// Положение локальной системы координат
void SetAxes( gp_Ax2 axes);
gp_Ax2 Axes( void )
{ return myAxes; }
//
DEFINE_STANDARD_RTTI(vkScrewLine)
//
private:
Standard_Real myRadius; // Радиус винта
Standard_Real myLead; // Шаг винтовой линии
Standard_Boolean myIsRight; // Признак: правый, левый винт
gp_Ax2 myAxes; // Оси, определяющие локальную систему координат
gp_Trsf myL2WTrsf; // Преобразование от локальной к мировой системе координат
//
// Процедуры перехода к мировой системе координат
void CalcL2WTransform( void );
void L2WTransform( gp_Pnt& P ) const;
void L2WTransform( gp_Vec& V ) const;
};
DEFINE_STANDARD_HANDLE(vkScrewLine,Geom_Curve)
Приведем теперь реализацию методов. В конструкторе устанавливаются значения по умолчаню.
IMPLEMENT_STANDARD_HANDLE(vkScrewLine,Geom_Curve)
IMPLEMENT_STANDARD_RTTIEXT(vkScrewLine,Geom_Curve)
vkScrewLine::vkScrewLine()
{
// Радиус
myRadius = 1.;
// Шаг
myLead = 1.;
// Направление
myIsRight = Standard_True;
// Локальная система координат
myAxes = gp::XOY();
}
vkScrewLine::~vkScrewLine()
{
}
Минимальное и максимальное значение параметра — два витка винта:
//
// Минимальное / максимальное значения параметра на кривой.
Standard_Real vkScrewLine::FirstParameter() const
{
Standard_Real value = 0.;
return value;
}
Standard_Real vkScrewLine::LastParameter() const
{
Standard_Real value = 4.*M_PI;
return value;
}
Вычисление значений точки кривой и производных для данного значения параметра.
//
void vkScrewLine::D0(const Standard_Real phi,gp_Pnt& P) const
{
double alpha = myIsRight ? +1 : -1;
double x = myRadius*cos(alpha*phi);
double y = myRadius*sin(alpha*phi);
double z = myLead*phi/(2.*M_PI);
//
P.SetCoord(x,y,z);
// Переход к мировой системе координат
L2WTransform( P );
}
//
void vkScrewLine::D1(const Standard_Real phi,gp_Pnt& P,gp_Vec& V1) const
{
double alpha = myIsRight ? +1 : -1;
double x = myRadius*cos(alpha*phi);
double y = myRadius*sin(alpha*phi);
double z = myLead*phi/(2.*M_PI);
//
P.SetCoord(x,y,z);
// Переход к мировой системе координат
L2WTransform( P );
//
double x1 = -alpha*y;
double y1 = alpha*x;
double z1 = myLead/(2.*M_PI);
V1.SetCoord(x1,y1,z1);
// Переход к мировой системе координат
L2WTransform( V1 );
}
//
void vkScrewLine::D2(const Standard_Real phi,gp_Pnt& P,gp_Vec& V1,gp_Vec& V2) const
{
double alpha = myIsRight ? +1 : -1;
double x = myRadius*cos(alpha*phi);
double y = myRadius*sin(alpha*phi);
double z = myLead*phi/(2.*M_PI);
//
P.SetCoord(x,y,z);
// Переход к мировой системе координат
L2WTransform( P );
//
double x1 = -alpha*y;
double y1 = alpha*x;
double z1 = myLead/(2.*M_PI);
V1.SetCoord(x1,y1,z1);
// Переход к мировой системе координат
L2WTransform( V1 );
//
double x2 = -alpha*alpha*x;
double y2 = -alpha*alpha*y;
V2.SetCoord(x2,y2,0.);
// Переход к мировой системе координат
L2WTransform( V2 );
}
//
void vkScrewLine::D3(const Standard_Real phi,gp_Pnt& P,gp_Vec& V1,gp_Vec& V2,gp_Vec& V3) const
{
double alpha = myIsRight ? +1 : -1;
double x = myRadius*cos(alpha*phi);
double y = myRadius*sin(alpha*phi);
double z = myLead*phi/(2.*M_PI);
//
P.SetCoord(x,y,z);
// Переход к мировой системе координат
L2WTransform( P );
//
double x1 = -alpha*y;
double y1 = alpha*x;
double z1 = myLead/(2.*M_PI);
V1.SetCoord(x1,y1,z1);
// Переход к мировой системе координат
L2WTransform( V1 );
//
double alpha2 = alpha*alpha;
double x2 = -alpha2*x;
double y2 = -alpha2*y;
V2.SetCoord(x2,y2,0.);
// Переход к мировой системе координат
L2WTransform( V2 );
//
double alpha3 = pow(alpha,3);
double x3 = alpha3*y;
double y3 = -alpha3*x;
V3.SetCoord(x3,y3,0.);
// Переход к мировой системе координат
L2WTransform( V3 );
}
//
gp_Vec vkScrewLine::DN(const Standard_Real phi,const Standard_Integer N) const
{
// OutOfRange_Raise_if( N<1,"vkScrewLine::DN : N<1");
//
gp_Vec VN;
double alpha = myIsRight ? +1 : -1;
double x = myRadius*cos(alpha*phi);
double y = myRadius*sin(alpha*phi);
if( N==1 ) {
double x1 = -alpha*y;
double y1 = alpha*x;
double z1 = myLead/(2.*M_PI);
VN.SetCoord(x1,y1,z1);
} else if( N%2==0 ) {
// N -- четное
double alphaN = pow(alpha,N);
int sign = N%4==0 ? +1 : -1;
double xN = sign*alphaN*x;
double yN = sign*alphaN*y;
VN.SetCoord(xN,yN,0.);
} else {
// N -- нечетное
double alphaN = pow(alpha,N);
int signX = (N+1)%4==0 ? +1 : -1;
int signY = (N-1)%4==0 ? +1 : -1;
double xN = signX*alphaN*y;
double yN = signY*alphaN*x;
VN.SetCoord(xN,yN,0.);
}
// Переход к мировой системе координат
L2WTransform( VN );
return VN;
}
Процедуры обращения параметризации
//
void vkScrewLine::Reverse()
{
gp_Dir zDir = myAxes.Direction();
// Опрос координат направления
Standard_Real x, y, z;
zDir.Coord(x, y, z);
zDir.SetCoord(-x, -y, -z);
myAxes.SetDirection(zDir);
Standard_Real dPhi = FirstParameter() + LastParameter();
myAxes.Rotate(myAxes.Axis(),dPhi);
Standard_Real dZ = dPhi/(2.*M_PI);
gp_Vec zTrans(x*dZ,y*dZ,z*dZ);
myAxes.Translate (zTrans);
// Преобразование к мировой системе координат
CalcL2WTransform( );
}
//
Standard_Real vkScrewLine::ReversedParameter(const Standard_Real U) const
{
Standard_Real value;
value = FirstParameter()+LastParameter() - U;
return value;
}
Реализация абстрактных методов класса Geom_Geometry.
Handle(Geom_Geometry) vkScrewLine::Copy() const
{
Handle(vkScrewLine) L;
L = new vkScrewLine();
//
L->SetRadius(myRadius);
L->SetLead(myLead);
L->SetAxes(myAxes);
L->SetIsRight(myIsRight);
//
return L;
}
//
void vkScrewLine::Transform (const gp_Trsf& T)
{
myAxes.Transform (T);
CalcL2WTransform( );
}
Внутренние методы винтовой линии
void vkScrewLine::CalcL2WTransform( void )
{
gp_Dir xDir = myAxes.XDirection();
gp_Dir yDir = myAxes.YDirection();
gp_Dir zDir = myAxes.Direction();
gp_Pnt origin = myAxes.Axis().Location();
myL2WTrsf.SetValues(xDir.X(),yDir.X(),zDir.X(),origin.X(),
xDir.Y(),yDir.Y(),zDir.Y(),origin.Y(),
xDir.Z(),yDir.Z(),zDir.Z(),origin.Z(),1.e-10,1.e-10);
}
//
void vkScrewLine::L2WTransform( gp_Pnt& P ) const
{
P.Transform(myL2WTrsf);
}
//
void vkScrewLine::L2WTransform( gp_Vec& V ) const
{
V.Transform(myL2WTrsf);
}
//
void vkScrewLine::SetRadius(Standard_Real radius)
{
myRadius = radius;
CalcL2WTransform( );
}
//
void vkScrewLine::SetLead(Standard_Real lead)
{
myLead = lead;
CalcL2WTransform( );
}
//
void vkScrewLine::SetIsRight(Standard_Boolean isRight)
{
myIsRight = isRight;
}
//
void vkScrewLine::SetAxes(gp_Ax2 axes)
{
myAxes = axes;
CalcL2WTransform( );
}