///////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
// All rights reserved.
//
// This software and its documentation and related materials are owned by
// the Alliance. The software may only be incorporated into application
// programs owned by members of the Alliance, subject to a signed
// Membership Agreement and Supplemental Software License Agreement with the
// Alliance. The structure and organization of this software are the valuable
// trade secrets of the Alliance and its suppliers. The software is also
// protected by copyright law and international treaty provisions. Application
// programs incorporating this software must include the following statement
// with their copyright notices:
//
// This application incorporates Open Design Alliance software pursuant to a license
// agreement with Open Design Alliance.
// Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
// All rights reserved.
//
// By use of this software, its documentation or related materials, you
// acknowledge and accept the above terms.
///////////////////////////////////////////////////////////////////////////////
#ifndef __ODGIINTERSECTIONSCALCULATOR__
#define __ODGIINTERSECTIONSCALCULATOR__
#include "TD_PackPush.h"
#include "Ge/GeExtents3d.h"
#include "Gi/GiExtentsSpaceTree.h"
/** \details
.
Library: Source code provided.
*/
class OdGiTriangleForIntersectTest
{
friend class OdGiIntersectionsCalculator;
friend class OdGiCollisionDetector;
friend class OdGiCollisionDetectorIntersectionsOnly;
// unique ID of the object
//IMPORTANT: the user is responsible for the uniqueness of the ID
OdUInt32 ID;
// extents of the triangle
OdGeExtents3d m_extents;
// parameters of the triangle's plane
OdGeVector3d planeNorm;
double planeD;
bool m_bIsPlaneCalculated;
public:
//three vertices
OdGePoint3d ABC[3];
// default constructor
OdGiTriangleForIntersectTest();
//constructor
OdGiTriangleForIntersectTest(const OdGePoint3d *points, OdUInt32 uniqueID);
/** \details
Specifies triangle data.
\param points [in] Array of 3 points.
\param bCalcExtents [in] If true, extents will be calculated using const OdGePoint3d* points.
*/
void setData( const OdGePoint3d* points, bool bCalcExtents = true );
/** \details
Overrides triangle extents.
\param extents [in] New triangle extents.
*/
void rewriteExtents( const OdGeExtents3d& extents );
// retrieve the plane's normal
inline const OdGeVector3d* getTrianglePlaneNorm();
//retrieve the D
inline double getPlaneD();
//**********************************************************************//
//********************METHODS FOR USING IN SPACE TREE*******************//
//**********************************************************************//
//set/get ID
OdUInt32 getID() {return ID;}
void setID(OdUInt32 uniqueID){ID = uniqueID;}
// check that the triangle is in extents
inline bool isInExtents(OdGeExtents3d& extents) const;
// not need for this class
bool isInExtents(OdGeExtents2d&) const { return false; }
// check that objects are equal
bool isEqual(OdGiTriangleForIntersectTest*, const OdGeTol& = OdGeContext::gTol) const
{
return false;
}
private:
// calculate the parameters of the plane
inline void calculatePlaneParameters();
};
/** \details
The data type that represents a vector of the objects.
*/
typedef OdVector > OdGiIntersectTrianglesVector;
typedef OdGiExtentsSpaceTree<3, 5, 20, OdGeExtents3d, OdGePoint3d, OdGiTriangleForIntersectTest> OdGiExtents3dSpaceTree_Gi;
typedef OdGiExtentsSpaceNode OdGiExtents3dSpaceNode_Gi;
/** \details
.
Library: Source code provided.
*/
class OdGiEdgeForIntersectTest : public OdGiExtents3dSpaceEdge
{
public:
//means that this edge is an edge of touching of two triangles
bool m_bIsTouchingEdge;
OdGiEdgeForIntersectTest(OdGiExtents3dSpacePoint& pt1, OdGiExtents3dSpacePoint& pt2, OdUInt32 uniqueID) : OdGiExtents3dSpaceEdge(pt1, pt2, uniqueID)
{
m_bIsTouchingEdge = false;
}
};
/** \details
This class implements triangles-based intersection calculation.
Usage:
1) call initializeCalculations()
2) add triangles:
2.1) call appendTriangleContainer to obtain containerID
2.2) call addTriangleToContainer with obtained ID
3) specify containers that should be tested by calling addContainerToBeTested and call processPathCalculation for them
4) call computeIntersections to calculate intersections between specified container and all "should be tested" containers
5) use processPathCalculation() to obtain results
Library: Source code provided.
\sa
*/
class OdGiIntersectionsCalculator : public OdGiExtentsSpaceTreeCallback
{
protected:
// tolerance for the intersection calculation
OdGeTol m_tol;
// cach data for the controlling already intersected triangles with the given triangle
OdVector> m_vectTestedTriangles;
OdUInt32Vector m_vectTestTriangles_objBoundary;
// data for controlling the objects with which will be intersected the given object
OdUInt32Vector m_vectToBeTestedObjects;
// following parameter need for the callback method' notifyObjectPlacedAtNode'
bool m_bSecondObjectProcessedInTree;
// cach data for storing the triangles from all objects
OdVector m_containerTriangles;
// extents trees for the triangles and vertices
OdGiExtents3dSpaceTree_Gi m_spaceTriangTree;
OdGiExtents3dSpaceTree m_spaceVertexTree;
// arrays for storing the intersecting vertices and edges (this arrays will have the same size as 'm_vectToBeTestedObjects')
OdArray* m_intersectVertices;
OdArray* m_intersectEdges;
// list for the storing final pathes for polyout
OdList m_finalIntersectPathes;
bool m_b3dFacesActive;
// method for the callback from the tree
virtual bool notifyObjectPlacedAtNode(OdGiTriangleForIntersectTest* pTriang, int objectType, OdGiExtents3dSpaceNode_Gi* pNode);
// calculate intersections of the triangles
void intersectTriangles(OdUInt32 idObjA, OdUInt32 trIdA, OdUInt32 idObjB, OdUInt32 trIdB, OdUInt32 idObjTested, const OdGeTol& tol);
//Public API
public:
/** \details
Default constructor for the OdGiIntersectionsCalculator class.
*/
OdGiIntersectionsCalculator();
/** \details
Destructor for the OdGiIntersectionsCalculator class.
*/
virtual ~OdGiIntersectionsCalculator(){}
/** Appends specified triangle container to the containers list and returns it ID
*/
OdInt32 appendTriangleContainer( OdGiIntersectTrianglesVector* pContainer );
/** Adds triangle to the specified triangle container
*/
OdInt32 addTriangleToContainer( OdInt32 containerID, const OdGePoint3d *pTriangle );
/** Adds specified triangle container to the "containers to be tested" list
*/
OdInt32 addContainerToBeTested( OdInt32 containerID );
/** Computes intersections between specified triangle container and "containers to be tested" list
*/
void computeIntersections( OdInt32 containerID, OdGeExtents3d &extents );
// initialize calculations
virtual void initializeCalculations(OdGeExtents3d& ext, OdInt32 nObjects);
// finalize calculations
virtual void finalizeCalculations();
// intermediate finalize calculations
void intermediatefinalizeCalculations();
//process triangles into tree
void processTrianglesIntoSpaceTree(OdUInt32 objID, bool bOtherObjectsProcessed);
//process path calculation
void processPathCalculation(OdUInt32 idObjTested);
/** \details
Retrives intersection tolerance
\returns Returns intersection tolerance
*/
const OdGeTol& tolerance() const { return m_tol; }
/** \details
Specifies intersection tolerance
\param tol [in] Intersection tolerance
*/
void setTolerance( const OdGeTol& tol ) { m_tol = tol; }
public:
//Data accessors
bool& facesActive() { return m_b3dFacesActive; }
bool getSpaceTreeRootExtents( OdGeExtents3d& ext );
OdUInt32 triangleContainerSize() const { return m_containerTriangles.size(); }
OdUInt32 containerToBeTestedSize() const { return m_vectToBeTestedObjects.size(); }
void removeEdgeInfo( OdInt32 objID );
OdList& finalIntersectionPathes() { return m_finalIntersectPathes; }
OdArray* intersectionVertices() { return m_intersectVertices; }
OdArray* intersectionEdges(){ return m_intersectEdges; }
};
/** \details
This class is a detector for collision of triangular representations of entities.
\sa
*/
class OdGiCollisionDetector : public OdGiIntersectionsCalculator
{
public:
/** \details
Default constructor for the OdGiCollisionDetector class.
*/
OdGiCollisionDetector();
/** \details
Destructor for the OdGiCollisionDetector class.
*/
virtual ~OdGiCollisionDetector() {};
protected:
// method for the callback from the tree
virtual bool notifyObjectPlacedAtNode(OdGiTriangleForIntersectTest* pTriang, int objectType, OdGiExtents3dSpaceNode_Gi* pNode);
protected: //Hide OdGiIntersectionsCalculator methods
void computeIntersections( OdInt32 containerID, OdGeExtents3d &extents ) { OdGiIntersectionsCalculator::computeIntersections( containerID, extents ); }
void processPathCalculation(OdUInt32 idObjTested) { OdGiIntersectionsCalculator::processPathCalculation( idObjTested ); }
void removeEdgeInfo( OdInt32 objID ) { OdGiIntersectionsCalculator::removeEdgeInfo( objID ); }
OdList& finalIntersectionPathes() { return m_finalIntersectPathes; }
OdArray* intersectionVertices() { return m_intersectVertices; }
OdArray* intersectionEdges(){ return m_intersectEdges; }
public:
/** \details
Detects collisions between a specified triangle container and all triangle containers that are marked as "container to be tested".
\param containerID [in] Triangle container.
\param extents [in] Not used.
*/
void detectCollisions( OdInt32 containerID, const OdGeExtents3d &extents );
/** \details
Gets a list of all detected collisions.
\param result [out] Recieves results of collision detection.
*/
void getCollisions( OdList& result );
/** \details
Retrieves a collision distance at the specified index.
\param collisionIndex [in] Index of a collision for which to get the distance.
\param result [out] Receives collision distance.
\returns
true if collision distance is sucessfully received. This method returns false if index exceeds
the size of vector with collisions or if collision at the specified index is not detected.
*/
bool getCollisionDistance( OdUInt32 collisionIndex, double& result ) const;
/** \details
Finalizes calculations, i.e. resets the triangles tree, removes triangles info and releases all data related to collision detection.
*/
virtual void finalizeCalculations();
/** \details
Clears all triangle containers that were marked for collision detection calculations.
*/
void clearContainersToBeTested();
/** \details
Specifies whether to detect collisions only when collided objects intersect.
\param b [in] Flag that specifies whether to detect only intersecting objects. If true, touches are not detected.
*/
void setIntersectionsOnly( bool b ) { SETBIT( m_options, kOption_IntersectionOnly, b ); }
/** \details
Checks whether only intersected objects are detected as collisions.
\returns
true if only intersected objects are detected as collisions, false otherwise.
*/
bool isIntersectionsOnly() const { return GETBIT( m_options, kOption_IntersectionOnly ); }
/** \details
Specifies a distance for the clearance mode when objects that are "too close" are detected as intersections.
\param cl [in] Clearance distance. Object which have less distance than this value are considered collided in the clearance mode.
*/
void setClearance( double cl )
{
SETBIT( m_options, kOption_Clearance, cl > 0. );
m_dClearance = cl;
}
/** \details
Checks whether clearance mode for detecting collisions is enabled. This method detects collisions between intersectiong, touching and objects that are "too close".
\returns
true if clearance mode is enabled, false otherwise.
*/
bool isClearance() const { return GETBIT( m_options, kOption_Clearance ); }
/** \details
Retrieves a distance for the clearance mode when objects that are "too close" are detected as intersections.
*/
double getClearance() const { return m_dClearance; }
/** \details
Specifies whether collision detection should calculate collision distance.
\param b [in] The flag that indicates that collision detection should calculate collision distance.
*/
void setCalcDistance( bool b ) { SETBIT( m_options, kOption_CalcDistance, b ); }
/** \details
Checks whether collision detection calculates collision distance.
\returns
true if collision detection calculates collision distance, false otherwise.
*/
bool getCalcDistance() const { return GETBIT( m_options, kOption_CalcDistance ); }
/** \details
Specifies whether collision detection should check all faces instead of detecting the first collision.
\param b [in] If true, collision detection checks all faces instead of detecting the first collision.
*/
void setCheckAll( bool b ) { SETBIT( m_options, kOption_CheckAll, b ); }
/** \details
Checks whether collision detection checks all faces instead of detecting the first collision.
\returns
true if collision detection checks all faces, false otherwise.
*/
bool getCheckAll() const { return GETBIT( m_options, kOption_CheckAll ); }
protected:
//DOM-IGNORE-BEGIN
struct DetectedCollision
{
bool bDetected;
double dDistance;
DetectedCollision() : bDetected( false ), dDistance( 0.0 ) {}
operator bool() const { return bDetected; }
DetectedCollision& operator=( bool b ) { bDetected = b; return *this; }
};
OdVector > m_vectCollidedContainers;
//Performance
DetectedCollision* m_vectCollidedContainersAsPtr;
OdGePoint3d m_ptA;
OdGePoint3d m_ptB;
bool collideTriangles( OdUInt32 idObjA, OdUInt32 trIdA, OdUInt32 idObjB, OdUInt32 trIdB, OdUInt32 idObjTested, const OdGeTol& tol );
//check that points of one triangle are placed on opposite siedes of the second triangle plane
OdUInt32 checkPointsPlacement( const OdGeVector3d* pPlaneNormalA, double D_A, const OdGePoint3d* pPointsTriangleB, const OdGeTol& tol );
enum CollisionOption
{
kOption_IntersectionOnly = 1,
kOption_Clearance = 2,
kOption_CalcDistance = 4,
kOption_CheckAll = 8
};
OdUInt8 m_options;
double m_dClearance;
OdUInt32 m_nProcessingID = 0;
//DOM-IGNORE-END
};
//Collision detector that detect only intersections (no touching)
//It is separate class because additional checks in OdGiCollisionDetector::collideTriangles will slow down it
/*class OdGiCollisionDetectorIntersectionsOnly : public OdGiCollisionDetector
{
public:
OdGiCollisionDetectorIntersectionsOnly() : OdGiCollisionDetector()
{};
virtual ~OdGiCollisionDetectorIntersectionsOnly()
{};
protected:
// method for the callback from the tree
virtual bool notifyObjectPlacedAtNode(OdGiTriangleForIntersectTest* pTriang, int objectType, OdGiExtents3dSpaceNode_Gi* pNode);
bool collideTriangles(OdUInt64 idObjA, OdUInt64 trIdA, OdUInt64 idObjB, OdUInt64 trIdB, OdUInt64 idObjTested, const OdGeTol& tol);
//check that points of one triangle are placed on opposite siedes of the second triangle plane
OdUInt32 checkPointsPlacement(const OdGeVector3d* pPlaneNormalA, double D_A, const OdGePoint3d* pPointsTriangleB, const OdGeTol& tol);
};*/
#include "TD_PackPop.h"
#endif //#ifndef __ODGIINTERSECTIONSCALCULATOR__