본문 바로가기

programming/OpenCascade

OpenCascade - User Guides - 1. Foundation Classes - 2. Basics

Basics

Library organization

Modules and toolkits

OCCT는 여러 module들로 구성됨.

첫 module - foundation classes.

한 module은 여러 toolkit (실행, 리소스)으로 구성됨.

한 toolkit은 하나의 .so 혹은 .dll

 

Packages

class들과 의미론적 연결.

e.g. geometry package - Point, Line, Circle classes.

class명 앞에 접두어로 package명 붙임. (e.g. Geom_Circle)

  • Enumerations
  • Object classes
  • Exceptions
  • Pointers 

Contents of a package

 

 

Classes

 

Inheritance

 

 

Data Types

  • Data types manipulated by handle (or reference)
  • Data types manipulated by value - primitive

Manipulation of data types

 

Primitive Types

  • Standard_Boolean - Standard_True, Standard_False.
  • Standard_Character - ASCII character.
  • Standard_ExtCharacter - extended character.
  • Standard_Integer
  • Standard_Real
  • Standard_ShortReal
  • Standard_CString - literal constants
  • Standard_ExtString - extended string.
  • Standard_Address - a byte address of undetermined size.

Standard package.

C++ Types OCCT Types 비고
int Standard_Integer  
double Standard_Real  
float Standard_ShortReal  
bool Standard_Boolean  
char Standard_Character UTF-8
char16_t Standard_Utf16Char UTF-16
char*  Standard_CString UTF-8
void* Standard_Address  
char16_t* Standard_ExtString UTF-16

 

Types manipulated by value

  • Primitive types
  • Enumerated types
  • Types defined by classes not inheriting from Standard_Transient.

Manipulation of a data type by value

 

Types manipulated by reference (handle)

  • classes inheriting from the Standard_Transient.

Manipulation of a data type by reference

 

When is it necessary to use a handle?

 

Programming with Handles

Handle Definition

smart pointer.

 

Organization of Classes

 

reference counter를 제공하는 Standard_Transient에서 상속.

핸들을 정의하는 템플릿 클래스 : opencascade::handle<>

전처리기 매크로 : Handle()

Handle(Geom_Line) aLine; // "Handle(Geom_Line)" is expanded to "opencascade::handle<Geom_Line>"

 

접두어 Handle_ 이 붙은 typedef도 제공됨.

Handle_Geom_Line aLine; // "Handle_Geom_Line" is typedef to "opencascade::handle<Geom_Line>"

 

 

Using a Handle

 

handle 초기값은 null.

IsNull( ), Nullify( )

 

Type Management

 

RTTI 사용

Standard_Type.hxx 가 제공하는 2가지 매크로

 

  • inline variant (간편하지만 binary가 커질 수 있음.)
#include <Geom_Surface.hxx>
class Appli_ExtSurface : public Geom_Surface
{
. . .
public:
  DEFINE_STANDARD_RTTIEXT(Appli_ExtSurface,Geom_Surface)
};

 

 

  • Out-of line variant

In Appli_ExtSurface.hxx file:

#include <Geom_Surface.hxx>
class Appli_ExtSurface : public Geom_Surface
{
. . .
public:
  DEFINE_STANDARD_RTTIEXT(Appli_ExtSurface,Geom_Surface)
};

 

In Appli_ExtSurface.cxx file:

#include <Appli_ExtSurface.hxx>
IMPLEMENT_STANDARD_RTTIEXT(Appli_ExtSurface,Geom_Surface)

 

사용 예

if (aCurve->IsKind(STANDARD_TYPE(Geom_Line))) // equivalent to "if (dynamic_cast<Geom_Line>(aCurve.get()) != 0)"
{
...
}

 

Type Conformity

up cast

 

Explicit Type Conversion

down case (safe cast)

Handle(Geom_Point) aPnt1;
Handle(Geom_CartesianPoint) aPnt2, aPnt3;
aPnt2 = new Geom_CartesianPoint();
aPnt1 = aPnt2; // OK, standard assignment
aPnt3 = Handle(Geom_CartesianPoint)::DownCast (aPnt1);
// OK, the actual type of aPnt1 is Geom_CartesianPoint, although the static type of the handle is Geom_Point

 

 

e.g. Standard_Transient에서 상속받은 A, B,

Handle(A) a;
Handle(B) b;
Handle(Standard_Transient) t;
TColStd_SequenceOfTransient aSeq;
a = new A();
aSeq.Append (a);
b = new B();
aSeq.Append (b);
t = aSeq.Value (1);
// here, you cannot write:
// a = t; // ERROR !
// so you downcast:
a = Handle (A)::Downcast (t)
if (!a.IsNull())
{
  // types are compatible, you can use a
}
else
{
  // the types are incompatible
}

 

 

Using Handles to Create Objects

생성할 때는 new 사용.

delete는 쓰지 말 것. (참조 없으면 자동 소멸됨.)

 

 

Invoking Methods

arrow(->) : 메소드 호출

dot : 핸들 상태 확인, 수정.

Handle(Geom_CartesianPoint) aCentre;
Standard_Real x, y, z;
if (aCentre.IsNull())
{
  aCentre = new PGeom_CartesianPoint (0, 0, 0);
}
aCentre->Coord (x, y, z);

 

Handle(Standard_Transient) aPnt = new Geom_CartesianPoint (0., 0., 0.);
if (aPnt->DynamicType() == STANDARD_TYPE(Geom_CartesianPoint))
{
  std::cout << "Type check OK\n";
}
else
{
  std::cout << "Type check FAILED\n";
}

 

Null 핸들 접근 시 Standard_NullObject 예외 발생.

 

Invoking Class Methods

Standard_Integer aDegree = Geom_BezierCurve::MaxDegree();

 

 

Handle deallocation

reference counter 설명.

 

Cycles

순환 참조 시 자동 소멸 안됨.

회피 방법:

  • 양방향 링크인 경우, 한 방향은 그냥 C++ pointer를 써라
  • 소멸해야 하면 handle 하나를 nullify 해라.

Memory Management

작은 메모리 배열은 클러스터로 그룹핑, 재활용하는 방식 사용됨.

 

Usage of Memory Manager

 

C 함수 Standard::Allocate(), Standard::Free(), Standard::Reallocate() 가 제공됨.

C++ new( ), delete( )가 위 함수로 재정의됨.

Standard_DefineAlloc.hxx 가 제공하는 매크로 DEFINE_STANDARD_ALLOC가 모든 OCCT class에 사용되었음.

OCCT class에서 상속된 클래스에도 적용됨.

 

How to configure the Memory Manager

환경변수로 설정

  • MMGT_OPT:
    • 0 (default) : C heap 직접 사용 (malloc(), free()). MMGT_CLEAR 제외 다른 옵션은 모두 무시됨.
    • 1 : 아래 설명대로 최적화됨.
    • 2, Intel ® TBB optimized memory manager
  • MMGT_CLEAR:
    • 1 (default) : 모든 block 0으로 클리어.
    • 0 : 그대로 반환.
  • MMGT_CELLSIZE: large pools of memory 에 할당된 최대 블럭들 크기. Default 200.
  • MMGT_NBPAGES: small blocks in pages (operating-system dependent)를 위해 할당된 메모리 chunk 크기. Default  1000.
  • MMGT_THRESHOLD: heap에 반환되지 않고 내부적으로 재활용되는 블럭들의 최대 크기. Default 40000.
  • MMGT_MMAP: large memory blocks 할당 방식
    • 1 (default) : OS memory mapping functions 로 할당.
    • 0 : malloc()로 C heap 할당.

 

Optimization Techniques

 

MMGT_OPT==1이면,

block 종류 크기 특성
small-sized ~ MMGT_CELLSIZE 단독 할당되지 않고, large-pool의 일부로 할당됨.
mid-sized MMGT_CELLSIZE ~ MMGT_THRESHOLD Standard::Free() 재활용됨. Standard::Purge() 로 heap에 반환 가능.
large-sized MMGT_THRESHOLD ~ memory-pool 포함.
MMGT_MMAP 설정의 방식으로 할당.

 

 

Benefits and drawbacks

장점 : 유사 크기의 많은 블록을 계속 할당/해제하는 애플리케이션의 경우 50%까지 성능 향상.

단점 : 프로그램 수행 중 재활용 메모리 해제 안됨. 상당한 메모리 소모 및 메모리 누수로 오인.

 

메모리를 많이 쓰는 동작 후, Standard::Purge( ) 호출 필요.

 

Exceptions

Introduction

계층구조

root class : Standard_Failure (Standard package)

 

Raising an Exception

 

"C++ like" Syntax

throw Standard_DomainError ("Cannot cope with this condition");

메시지는 optional.

try
{
  OCC_CATCH_SIGNALS
  // try block
}
catch (const Standard_DomainError& )
{
  // handle Standard_DomainError exceptions here
}

 

Regular usage

 

<ErrorTypeName>_Raise_if(condition, "Error message");

condition 만족시에만 raise

 

#define No_Exception // remove all raises

 

 

Handling an Exception

try { } 열고 OCC_CATCH_SIGNALS 삽입하면, 시스템 signal들을 예외로 다룸.

void f(1)
{
  try
  {
    OCC_CATCH_SIGNALS
    // try block
  }
  catch (const Standard_Overflow& ) // first handler
  {
    // ...
  }
  catch (const Standard_NumericError& ) // second handler
  {
    // ...
  }
}

 

root인 Standard_Failure의 catch를 메인 블럭에 배치하는 것을 권장.

#include <Standard_ErrorHandler.hxx>
#include <Standard_Failure.hxx>
#include <iostream>
int main (int argc, char* argv[])
{
  try
  {
    OCC_CATCH_SIGNALS
    // main block
    return 0;
  }
  catch (const Standard_Failure& theFailure)
  {
    std::cerr << "Error " + theFailure.DynamicType()->Name() << " [" << theFailure.GetMessageString() << "]\n";
  }
  return 1;
}

 

Catching signals

main() 함수 시작 부분에 OSD::SetSignal() 메소드로 핸들러 설치하고 try { } 에 OCC_CATCH_SIGNALS 삽입 필요.

 

 

Implementation on various platforms

 

OCC_CONVERT_SIGNALS

1. Windows : 정의되지 않음. normal C++ 예외가 모든 경우에 사용됨.

2. Linux : 정의됨. signal 발생 시, 가장 가까운 OCC_CATCH_SIGNALS 삽입 위치로 long jump 해서 C++ 예외 throw.

 

Plug-In Management

Distribution by Plug-Ins

global universal identifier (GUID)로 인식됨.

 

C++ Plug-In Implementation

Factory 메소드 포함.

 

package Plugin.

Load( )함수

 

1) 다음 리소스 파일을 읽어 가용한 plug-in들과 위치 정보를 얻음.

$CSF_PluginDefaults/Plugin

 

2) library 로드.

Linux : LD_LIBRARY_PATH

Windows : PATH

 

3) PLUGINFACTORY 함수 호출로 객체를 리턴.

 

 

C++ Client Plug-In Implementation

Handle(FADriver_PartStorer)::DownCast(PlugIn::Load (yourStandardGUID));

 

#include <Standard_Macro.hxx>
#include <Standard_GUID.hxx>
#include <Standard_Transient.hxx>
class FAFactory
{
public:
  Standard_EXPORT static Handle(Standard_Transient) Factory (const Standard_GUID& theGUID);
};

 

#include <FAFactory.hxx>
#include <FADriver_PartRetriever.hxx>
#include <FADriver_PartStorer.hxx>
#include <FirstAppSchema.hxx>
#include <Standard_Failure.hxx>
#include <FACDM_Application.hxx>
#include <Plugin_Macro.hxx>
static Standard_GUID StorageDriver  ("45b3c690-22f3-11d2-b09e-0000f8791463");
static Standard_GUID RetrievalDriver("45b3c69c-22f3-11d2-b09e-0000f8791463");
static Standard_GUID Schema         ("45b3c6a2-22f3-11d2-b09e-0000f8791463");
//======================================================
// function : Factory
// purpose :
//======================================================
Handle(Standard_Transient) FAFactory::Factory (const Standard_GUID& theGUID)
{
  if (theGUID == StorageDriver)
  {
    std::cout << "FAFactory : Create store driver\n";
    static Handle(FADriver_PartStorer) sd = new FADriver_PartStorer();
    return sd;
  }
  if (theGUID == RetrievalDriver)
  {
    std::cout << "FAFactory : Create retrieve driver\n";
    static Handle(FADriver_PartRetriever) rd = new FADriver_PartRetriever();
    return rd;
  }
  if (theGUID == Schema)
  {
    std::cout << "FAFactory : Create schema\n";
    static Handle(FirstAppSchema) s = new FirstAppSchema();
    return s;
  }
  throw Standard_Failure ("FAFactory: unknown GUID");
  return Handle(Standard_Transient)();
}
// export plugin function "PLUGINFACTORY"
PLUGIN(FAFactory)