86f4bb48be
- C3d aggiornamento delle librerie ( 117960).
463 lines
17 KiB
C++
463 lines
17 KiB
C++
//////////////////////////////////////////////////////////////////////////////////////////
|
|
/**
|
|
\file
|
|
\brief \ru Типы данных утилиты обнаружения столкновений.
|
|
\en Data types of collision detection. \~
|
|
*/
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef __CDET_DATA_H
|
|
#define __CDET_DATA_H
|
|
|
|
#include <templ_sptr.h>
|
|
#include <mb_cart_point.h>
|
|
#include <mb_operation_result.h>
|
|
#include <mb_matrix3d.h>
|
|
#include <set>
|
|
#include <map>
|
|
|
|
class MbHRepSolid;
|
|
|
|
/**
|
|
\addtogroup Collision_Detection
|
|
\{
|
|
*/
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
/// \ru Объект из набора контроля столкновений. \en Object from the set of collision detection.
|
|
//---
|
|
typedef const MbHRepSolid * cdet_item;
|
|
typedef MbResultType cdet_result; ///< \ru Код результата контроля столкновений. \en Result code of collision queries.
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
// \ru Код результата контроля столкновений. \en Codes of collision detection.
|
|
//---
|
|
const cdet_result CDET_RESULT_Intersected = rt_Intersect;
|
|
const cdet_result CDET_RESULT_NoIntersection = rt_NoIntersect;
|
|
const cdet_result CDET_RESULT_Ok = rt_Success;
|
|
const cdet_result CDET_RESULT_None = rt_None;
|
|
const cdet_result CDET_RESULT_Error = rt_Error;
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
// \ru Геометрический объект пользователя. \en User geometric item.
|
|
//---
|
|
typedef const void * cdet_app_item;
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
// Constants
|
|
//---
|
|
const cdet_item CDET_NULL = nullptr; ///< \ru Пустой объект набора для контроля столкновений. \en Empty object of the collision query set.
|
|
const cdet_app_item CDET_APP_NULL = nullptr; ///< \ru "Нулевой" объект модели приложения. \en "Null object" of the client app.
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
/** \brief \ru Структура данных и обратных вызовов для запроса на поиск соударений.
|
|
\en Data structure and callbacks for the collision search request.
|
|
\details
|
|
\ru Базовый класс, предназначенный для реализации на стороне приложения структуры
|
|
запроса к алгоритму поиска соударений. С помощью обратных вызовов приложение
|
|
управляет поиском соударений и получает сведения o найденных пересечениях.
|
|
\en The base class intended to implement on the application side the structure of a query
|
|
to the collision search algorithm. The application uses a callback to control the collision
|
|
search and obtain details of detected interferencies.
|
|
|
|
*/
|
|
//---
|
|
struct MATH_CLASS cdet_query
|
|
{
|
|
enum cback_res ///< Result code of the callback function
|
|
{
|
|
CBACK_VOID
|
|
, CBACK_SUFFICIENT ///< This code means that an app stops collision query for given pair of lumps
|
|
, CBACK_SKIP ///< Skip testing a given pair of the lumps
|
|
, CBACK_NEED ///< Enable testing a given pair of the lumps
|
|
, CBACK_BREAK ///< Break search of all collisions of the set
|
|
, CBACK_SEARCH_MORE = CBACK_VOID ///< This code notifies a collision detector to continue working at cases CDET_INTERSECTED, CDET_TOUCHED.
|
|
};
|
|
|
|
enum message ///< Code of notification
|
|
{
|
|
CDET_QUERY_STARTED // The collision query is started for the all solids
|
|
, CDET_STARTED // The collision query is started for the given pair
|
|
, CDET_FINISHED // Collision detector complete searching a collisions for the given pair of lumps.
|
|
, CDET_INTERSECTED // The collided pair of objects founded.
|
|
, CDET_TOUCHED // Touched faces has been founded with no penetration of the solids.
|
|
, CDET_INCLUDED // The included pair of objects founded.
|
|
};
|
|
|
|
struct geom_element ///< Structure representing a collision detection geometry.
|
|
{
|
|
cdet_app_item appItem;
|
|
const MbRefItem * refItem;
|
|
const MbMatrix3D * wMatrix;
|
|
geom_element()
|
|
: appItem( nullptr )
|
|
, refItem( nullptr )
|
|
, wMatrix( &MbMatrix3D::identity ) {}
|
|
};
|
|
|
|
struct cback_data ///< Data structure that notifies an app about collision detection event.
|
|
{
|
|
geom_element first, second; ///< Pair of geometric objects
|
|
cback_data(): first(), second() {}
|
|
};
|
|
|
|
// If message is CDET_INCLUDED, then cback_data::first is in cback_data::second.
|
|
cback_res operator() ( message code, cback_data & cData ) { return func( this, code, cData ); }
|
|
|
|
protected:
|
|
typedef cback_res (*cback_func)( cdet_query *, message, cback_data & );
|
|
|
|
cdet_query( cback_func _func ) : func(_func) {}
|
|
cdet_query( const cdet_query & cQuery ) : func(cQuery.func) {}
|
|
~cdet_query() {}
|
|
|
|
cdet_query & operator = ( const cdet_query & cQuery ) { func = cQuery.func; return *this; }
|
|
|
|
private:
|
|
cback_func func;
|
|
};
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
// Simple collision query data to search for the first detected interference.
|
|
//---
|
|
struct MATH_CLASS cdet_query_result: public cdet_query
|
|
{
|
|
cdet_result result;
|
|
|
|
cdet_query_result()
|
|
: cdet_query( QueryFunc )
|
|
, result( CDET_RESULT_NoIntersection )
|
|
{}
|
|
|
|
cdet_query_result( const cdet_query_result & cQuery )
|
|
: cdet_query( cQuery )
|
|
, result( cQuery.result )
|
|
{}
|
|
|
|
|
|
private:
|
|
static cback_res QueryFunc( cdet_query * query, message code, cback_data & )
|
|
{
|
|
C3D_ASSERT( nullptr != query );
|
|
cdet_query_result * q = static_cast<cdet_query_result*>( query );
|
|
switch( code )
|
|
{
|
|
case CDET_QUERY_STARTED: // The collision query is started for all solids of the scene.
|
|
{
|
|
q->result = CDET_RESULT_NoIntersection;
|
|
return CBACK_VOID;
|
|
}
|
|
case CDET_INTERSECTED: // First intersection is founded.
|
|
{
|
|
q->result = CDET_RESULT_Intersected;
|
|
return CBACK_SUFFICIENT;
|
|
}
|
|
case CDET_FINISHED: // A pair of solids is finished.
|
|
return (q->result == CDET_RESULT_Intersected) ? CBACK_BREAK : CBACK_VOID;
|
|
|
|
default:
|
|
return CBACK_VOID;
|
|
}
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
// The structure queries first founded collision faces.
|
|
//---
|
|
struct MATH_CLASS cdet_first_collided: public cdet_query
|
|
{
|
|
SPtr<const MbRefItem> first, second; // collided faces
|
|
|
|
cdet_first_collided()
|
|
: cdet_query( QueryFunc )
|
|
, first()
|
|
, second()
|
|
{}
|
|
|
|
private:
|
|
static cback_res QueryFunc( cdet_query * query, message code, cback_data & cData )
|
|
{
|
|
if ( cdet_first_collided * q = static_cast<cdet_first_collided*>(query) )
|
|
{
|
|
switch( code )
|
|
{
|
|
case CDET_QUERY_STARTED: // The collision query is started for all solids of the set
|
|
{
|
|
q->first = q->second = nullptr;
|
|
return CBACK_VOID;
|
|
}
|
|
case CDET_FINISHED: // A pair of solids is finished.
|
|
return (q->first && q->second) ? CBACK_BREAK : CBACK_SEARCH_MORE;
|
|
|
|
case CDET_INTERSECTED: // First intersection is founded.
|
|
{
|
|
q->first = cData.first.refItem;
|
|
q->second = cData.second.refItem;
|
|
return (q->first && q->second) ? CBACK_SUFFICIENT : CBACK_SEARCH_MORE;
|
|
}
|
|
default:
|
|
return CBACK_VOID;
|
|
}
|
|
}
|
|
return CBACK_VOID;
|
|
}
|
|
OBVIOUS_PRIVATE_COPY( cdet_first_collided );
|
|
};
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
/** \brief \ru Структура запроса для поиска граней столкновения.
|
|
\en The structure of the query to find collision faces.
|
|
*/
|
|
//---
|
|
struct MATH_CLASS cdet_collided_faces: public cdet_query
|
|
{
|
|
typedef std::pair<cdet_app_item,const MbRefItem*> item_face; // represents a face of app item
|
|
typedef std::set<item_face> collided_faces;
|
|
collided_faces faces;
|
|
std::map<cdet_app_item,cdet_app_item> groups;
|
|
cdet_app_item excluded; // a member of excluded group
|
|
|
|
public:
|
|
cdet_collided_faces()
|
|
: cdet_query( _QueryFunc )
|
|
, faces()
|
|
, groups()
|
|
, excluded( CDET_APP_NULL )
|
|
{}
|
|
|
|
/** \brief \ru Объединить пару геометрических объектов в группу.
|
|
\en Unite a pair of geometric items to the group.
|
|
\details \ru Функция объединяет в группу два отдельных объекта или присоединяет
|
|
первый объект к группе, которой принадлежит второй. Если оба объекта уже
|
|
принадлежат каждый своей группе, то обе группы сливаются в одну общую.
|
|
\en The function unites to group two separate objects or the first object
|
|
attaches to the group, which owns the second. If both objects already
|
|
belong to each of their group, the two groups merged into a single.
|
|
*/
|
|
void Group( cdet_app_item fst, cdet_app_item snd )
|
|
{
|
|
fst = _Parent( fst );
|
|
snd = _Parent( snd );
|
|
if ( fst < snd )
|
|
{
|
|
std::swap( fst, snd );
|
|
}
|
|
groups[fst] = snd;
|
|
}
|
|
|
|
/** \brief \ru Исключить из контроля на столкновения тела группы.
|
|
\en Exclude from the collision control solids of the group.
|
|
\param[in] member - \ru Любой участник группы, элементы которой исключаются.
|
|
\en Any member of the group whose elements are excluded. \~
|
|
*/
|
|
void ExludeGroup( cdet_app_item member )
|
|
{
|
|
if ( excluded == CDET_APP_NULL )
|
|
excluded = _Parent( member );
|
|
else
|
|
Group( excluded, member );
|
|
}
|
|
/** \brief \ru Отменить результаты работы функций Group() и ExludeGroup().
|
|
\en Cancel the results of the functions Group() and ExludeGroup().
|
|
*/
|
|
void Reset()
|
|
{
|
|
faces.clear();
|
|
groups.clear();
|
|
excluded = CDET_APP_NULL;
|
|
}
|
|
|
|
private:
|
|
static cback_res _QueryFunc( cdet_query * query, message code, cback_data & cData )
|
|
{
|
|
if ( cdet_collided_faces * q = static_cast<cdet_collided_faces*>(query) )
|
|
{
|
|
switch( code )
|
|
{
|
|
case CDET_QUERY_STARTED:
|
|
{
|
|
q->faces.clear();
|
|
return CBACK_VOID;
|
|
}
|
|
case CDET_STARTED:
|
|
{
|
|
if ( q->_SameGroups(cData.first.appItem,cData.second.appItem) )
|
|
{
|
|
return CBACK_SKIP;
|
|
}
|
|
return CBACK_VOID;
|
|
}
|
|
|
|
case CDET_FINISHED: // a pair of solids was finished.
|
|
return CBACK_SEARCH_MORE;
|
|
|
|
case CDET_INTERSECTED:
|
|
{
|
|
if ( cData.first.refItem )
|
|
{
|
|
q->faces.insert( item_face(cData.first.appItem,cData.first.refItem) );
|
|
}
|
|
if ( cData.second.refItem )
|
|
{
|
|
q->faces.insert( item_face(cData.second.appItem,cData.second.refItem) );
|
|
}
|
|
return CBACK_SEARCH_MORE;
|
|
}
|
|
default:
|
|
return CBACK_VOID;
|
|
}
|
|
}
|
|
return CBACK_VOID;
|
|
}
|
|
|
|
cdet_app_item _Parent( cdet_app_item appItem ) const
|
|
{
|
|
std::map<cdet_app_item,cdet_app_item>::const_iterator iter = groups.find( appItem );
|
|
if ( iter == groups.end() || (iter->second == iter->first) )
|
|
{
|
|
return appItem;
|
|
}
|
|
C3D_ASSERT( iter->second < iter->first );
|
|
|
|
return _Parent( iter->second );
|
|
}
|
|
|
|
bool _SameGroups( cdet_app_item fst, cdet_app_item snd ) const
|
|
{
|
|
return _Parent( fst ) == _Parent( snd );
|
|
}
|
|
|
|
OBVIOUS_PRIVATE_COPY( cdet_collided_faces );
|
|
};
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
//
|
|
//---
|
|
typedef enum
|
|
{
|
|
CDET_EXAM_EnableComponentsOnly // Test collisions between components only.
|
|
, CDET_EXAM_Enabled // Enable the pair to test collisions.
|
|
, CDET_EXAM_Disabled // Reject the collision test of the pair.
|
|
} CDET_exam_status;
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
//
|
|
//---
|
|
struct MATH_CLASS CDET_item_data
|
|
{
|
|
cdet_item comp; // Descriptor of the component owning the inctance.
|
|
cdet_item inst; // Descriptor of the instance.
|
|
cdet_app_item appItem; // Application pointer for the instance or the component.
|
|
CDET_item_data()
|
|
{
|
|
comp = inst = CDET_NULL;
|
|
appItem = CDET_APP_NULL;
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
//
|
|
//---
|
|
typedef CDET_exam_status (*CDET_exam_func)( cdet_query *, const CDET_item_data &, const CDET_item_data & );
|
|
|
|
/** \} */ // Collision_Detection
|
|
|
|
class TapeBase;
|
|
class MbFace;
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
/* \brief \ru Грань столкновения. \en A face of collision. \~
|
|
*/
|
|
// ---
|
|
class MATH_CLASS MbCollisionFace
|
|
{
|
|
cdet_item item; // The instance to witch the face belongs.
|
|
const MbFace * mathFace; // The topological face identified in the collision detection or proximity query.
|
|
TapeBase * partFace; // The face of the application representation.
|
|
|
|
public:
|
|
MbCollisionFace( const MbFace & f )
|
|
: item( CDET_NULL )
|
|
, mathFace( &f )
|
|
, partFace( nullptr )
|
|
{}
|
|
|
|
const MbFace & Face() const { return *mathFace; }
|
|
cdet_item Item() const { return item; }
|
|
const MbFace & GetMathFace() const { return *mathFace; }
|
|
|
|
// \ru Установка объекта модели. \en Setting an object of model.
|
|
void SetCollisionFaceObject( TapeBase * _partFace ) { partFace = _partFace; }
|
|
|
|
// \ru Выдача объекта модели. \en Getting an object of model.
|
|
TapeBase * GetCollisionFaceObject() const { return partFace; }
|
|
|
|
// \ru Задать грань и компонент-вставку, которой принадлежит. \en Set a face and its component-instance.
|
|
MbCollisionFace & SetFace( const MbFace * f, cdet_item inst )
|
|
{
|
|
mathFace = f;
|
|
item = inst;
|
|
return *this;
|
|
}
|
|
|
|
MbCollisionFace & operator = ( const MbCollisionFace & other )
|
|
{
|
|
item = other.item;
|
|
mathFace = other.mathFace;
|
|
partFace = other.partFace;
|
|
return *this;
|
|
}
|
|
bool operator > ( const MbCollisionFace & other ) const { return mathFace > other.mathFace; }
|
|
bool operator < ( const MbCollisionFace & other ) const { return mathFace < other.mathFace; }
|
|
bool operator == ( const MbCollisionFace & other ) const { return mathFace == other.mathFace; }
|
|
bool operator != ( const MbCollisionFace & other ) const { return !(*this == other); }
|
|
|
|
private:
|
|
MbCollisionFace( const MbCollisionFace & ); // not implemented
|
|
};
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
// \ru Параметры (характеристика) близости двух объектов. \en Parameters (characteristic) of proximity of two objects.
|
|
// ---
|
|
class MATH_CLASS MbProximityParameters
|
|
{
|
|
MbCollisionFace * theFace1;
|
|
MbCollisionFace * theFace2;
|
|
SPtr<const MbFace> plane;
|
|
|
|
public:
|
|
MbCartPoint3D fstPnt, sndPnt; // \ru Пара точек близости, принадлежащие триангуляционным сеткам. \en The points of the proximity belonging to the triangulation grids.
|
|
MbCartPoint thePar1, thePar2; // \ru Пара точек близости, заданная в поверхностных координатах граней. \en The points of the proximity specified in the surface coordinates of the faces.
|
|
double theDistance; // \ru Расстояние. \en Distance.
|
|
double upperDist; // \ru Верхняя оценка для поиска минимальной дистанции. \en The upper bound of the minimal distance estimation.
|
|
|
|
public:
|
|
MbProximityParameters();
|
|
~MbProximityParameters();
|
|
|
|
protected:
|
|
MbProximityParameters( const MbFace & topoFace1
|
|
, const MbFace & topoFace2
|
|
, MbCartPoint & par1
|
|
, MbCartPoint & par2
|
|
, double dist );
|
|
|
|
public:
|
|
const MbCollisionFace & FaceOne() const { return *theFace1; }
|
|
const MbCollisionFace & FaceTwo() const { return *theFace2; }
|
|
|
|
void SetFacePair( const MbFace &, const MbFace & );
|
|
void SetFacePair( const MbFace *, cdet_item, const MbFace *, cdet_item );
|
|
|
|
private:
|
|
MbProximityParameters( const MbProximityParameters & ); // not implemented
|
|
MbProximityParameters & operator = ( const MbProximityParameters & ); // not implemented
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif // __CDET_DATA_H
|
|
|
|
// eof
|