///////////////////////////////////////////////////////////////////////////////
// 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 __ODGIPOINTCLOUD_H__
#define __ODGIPOINTCLOUD_H__
#include "Gi/GiViewport.h"
#include "Ge/GePoint3dArray.h"
#include "Ge/GeVector3dArray.h"
#include "Ge/GeMatrix3d.h"
#include "Ge/GeBoundBlock3d.h"
#include "UInt8Array.h"
#include "TD_PackPush.h"
#include "Gi/GiExport.h"
// Forward declarations
class OdGiPointCloudFilter;
/** \details
The data type that represents a smart pointer to the object.
*/
typedef OdSmartPtr OdGiPointCloudFilterPtr;
class OdGiPointCloudReceiver;
/** \details
The data type that represents a smart pointer to the object.
*/
typedef OdSmartPtr OdGiPointCloudReceiverPtr;
class OdGiPointCloudScheduler;
class OdPerfTimerBase;
/** \details
Basic point cloud interface object.
*/
class ODGI_EXPORT OdGiPointCloud : public OdRxObject
{
public:
enum Component
{
kVertexComponent = 0, // Vertexes data component
kColorComponent, // Colors data component
kNormalComponent, // Normals data component
//
kNumComponents // Number of data components
};
enum ExtraComponent
{ // Extra components (available in Components structure, but not in Flags)
kTransparencyComponent = kNumComponents,
kNumExtraComponents
};
enum ComponentMask
{ kNoComponents = 0, // No data components
kColors = (1 << 0), // Colors data component
kTransparencies = (1 << 1), // Transparencies data component
kNormals = (1 << 2) // Normals data component
};
enum DataSize
{
kDataSizeByte = 0,
kDataSizeWord,
kDataSizeFloat,
kDataSizeDouble
};
enum Flags
{
kLastComponentFlag = (1 << (kNumComponents << 1)), // Flags offset
// Flags
kAsyncCall = (kLastComponentFlag << 0), // Support asynchronic calls.
kPartialData = (kLastComponentFlag << 1), // Support partial data updates.
//
kLastFlag = kPartialData // Last flag
};
/** \details
Helper function to set data type size into flags.
*/
static OdUInt32 addDataSizeFlags(OdUInt32 *pFlags, Component component, DataSize ds)
{ const OdUInt32 addSet = (OdUInt32)ds << (component << 1);
if (!pFlags) return addSet;
return *pFlags = (*pFlags & ~(3 << (component << 1))) | addSet;
}
/** \details
Helper function extracts data type size from flags.
*/
static DataSize getDataSizeFlags(OdUInt32 flags, Component component)
{
return DataSize((flags >> (component << 1)) & 3);
}
/** \details
Returns default point cloud setting (actual for Gi implementation).
*/
static OdUInt32 getDefaultDataSizeFlags()
{ return OdGiPointCloud::addDataSizeFlags(NULL, OdGiPointCloud::kVertexComponent, OdGiPointCloud::kDataSizeDouble) |
OdGiPointCloud::addDataSizeFlags(NULL, OdGiPointCloud::kColorComponent, OdGiPointCloud::kDataSizeWord) |
OdGiPointCloud::addDataSizeFlags(NULL, OdGiPointCloud::kNormalComponent, OdGiPointCloud::kDataSizeDouble);
}
struct Components
{
OdUInt8Array m_component[kNumExtraComponents];
OdUInt32 m_nPoints;
bool hasComponent(long nComponent) const { return !m_component[nComponent].isEmpty(); }
Components() : m_nPoints(0) {}
};
typedef OdArray ComponentsArray;
struct ComponentsRaw
{
const void *m_pComponent[kNumExtraComponents];
OdRxObjectPtr m_pLockedObject;
OdUInt32 m_nPoints;
bool hasComponent(long nComponent) const { return m_pComponent[nComponent] != NULL; }
ComponentsRaw &fromComponents(Components &comps, OdUInt32 components = 0xFFFFFFFF, const OdRxObject *pLockedObject = nullptr)
{ const bool bNeedComponent[kNumExtraComponents] = /* Vertexes is always true */
{ true, GETBIT(components, kColors), GETBIT(components, kNormals), GETBIT(components, kTransparencies) };
for (long nComponent = 0; nComponent < kNumExtraComponents; nComponent++)
m_pComponent[nComponent] = (bNeedComponent[nComponent] && comps.hasComponent(nComponent)) ?
comps.m_component[nComponent].getPtr() : NULL;
m_nPoints = comps.m_nPoints; m_pLockedObject = pLockedObject;
return *this; }
ComponentsRaw &construct(const void *pPoints, OdUInt32 nPoints, const void *pColors = NULL, const void *pTransparencies = NULL,
const void *pNormals = NULL, const OdRxObject *pLockedObject = nullptr)
{ m_pComponent[kVertexComponent] = pPoints; m_pComponent[kColorComponent] = pColors;
m_pComponent[kTransparencyComponent] = pTransparencies; m_pComponent[kNormalComponent] = pNormals;
m_nPoints = nPoints; m_pLockedObject = pLockedObject;
return *this; }
};
typedef OdArray ComponentsRawArray;
public:
ODRX_DECLARE_MEMBERS(OdGiPointCloud);
/** \details
Returns total number of points, contained by point cloud entity.
*/
virtual OdUInt32 totalPointsCount() const = 0;
/** \details
Returns set of data components available for point cloud entity (see ComponentsMask enum).
*/
virtual OdUInt32 componentsMask() const { return kNoComponents; }
/** \details
Returns format support flags.
If set to any component except kNumComponents returns bit flags represent support data type sizes:
1 - byte, 2 - short, 4 - float, 8 - double. For color 2 means OdCmEntityColor+OdCmTransparency combination.
If set to kNumComponents return flags (see Flags enum).
By default: Vertex as doubles, Colors as OdCmEntityColor, Normals as doubles and No Flags.
*/
virtual OdUInt32 supportFlags(Component component = kNumComponents) const
{ return (component == kNumComponents) ? 0 : ((component == kColorComponent) ? 2 : 8); }
/** \details
Returns global transformation, which should be applied by underlying renderer to render point could data.
*/
virtual const OdGeMatrix3d &globalTransform() const { return OdGeMatrix3d::kIdentity; }
/** \details
Returns default point size.
*/
virtual OdInt32 defaultPointSize() const { return 0; }
/** \details
Return extents of point cloud entity.
*/
virtual bool getExtents(OdGeBoundBlock3d & /*bb*/) const { return false; }
/** \details
Return extents of point cloud entity.
*/
virtual bool calculateExtents(OdGeExtents3d &extents, const OdGiPointCloudFilter *pFilter = NULL) const;
/** \details
Check that point data compatible for specified viewports.
*/
virtual bool isDataCompatible(const OdGiViewport &pVp1, const OdGiViewport &pVp2) const = 0;
/** \details
Compute point cloud data.
*/
virtual bool updatePointsData(OdGiPointCloudReceiver *pReceiver, OdUInt32 components = kNoComponents,
OdUInt32 flags = 0, const OdGiViewport *pVp = NULL, const OdGiViewport *pVpFrom = NULL,
OdUInt32 pointSize = 0, OdGiPointCloudScheduler *pExternalScheduler = NULL) const = 0;
};
/** \details
The data type that represents a smart pointer to the object.
*/
typedef OdSmartPtr OdGiPointCloudPtr;
/** \details
Point cloud filter.
*/
class ODGI_EXPORT OdGiPointCloudFilter : public OdRxObject
{
protected:
OdGiPointCloudFilterPtr m_pPrevFilter;
public:
ODRX_DECLARE_MEMBERS(OdGiPointCloudFilter);
void attachFilter(const OdGiPointCloudFilter *pFilter)
{ m_pPrevFilter = pFilter; }
OdGiPointCloudFilterPtr detachFilter()
{ OdGiPointCloudFilterPtr pFilter = m_pPrevFilter; m_pPrevFilter.release(); return pFilter; }
protected:
virtual bool filterPointsImpl(OdGiPointCloud::ComponentsRaw *&pArrays, OdUInt32 &nArrays, OdUInt32 &compFlags, const OdGeBoundBlock3d *&pExtents) const = 0;
virtual bool filterBoundingBoxImpl(OdGeBoundBlock3d &bb) const = 0;
virtual void extractTransformImpl(OdGeMatrix3d & /*xForm*/) const { }
public:
bool filterPoints(OdGiPointCloud::ComponentsRaw *&pArrays, OdUInt32 &nArrays, OdUInt32 &compFlags, const OdGeBoundBlock3d *&pExtents) const
{ if (m_pPrevFilter.isNull() || m_pPrevFilter->filterPoints(pArrays, nArrays, compFlags, pExtents))
return filterPointsImpl(pArrays, nArrays, compFlags, pExtents);
return false;
}
bool filterBoundingBox(OdGeBoundBlock3d &bb) const
{ if (m_pPrevFilter.isNull() || m_pPrevFilter->filterBoundingBox(bb))
return filterBoundingBoxImpl(bb);
return false;
}
OdGeMatrix3d extractTransform() const
{ if (!m_pPrevFilter.isNull())
{ OdGeMatrix3d xForm = m_pPrevFilter->extractTransform();
extractTransformImpl(xForm);
return xForm;
} else {
OdGeMatrix3d xForm; extractTransformImpl(xForm); return xForm;
}
}
const OdGiPointCloudFilter *previousFilter() const
{
return m_pPrevFilter;
}
};
/** \details
Default implementation of point cloud data transformation filter.
*/
class ODGI_EXPORT OdGiPointCloudXformFilter : public OdGiPointCloudFilter
{
protected:
mutable OdGiPointCloud::ComponentsArray m_comps;
mutable OdGeBoundBlock3d *m_pBB;
OdGeMatrix3d m_xForm;
public:
ODRX_DECLARE_MEMBERS(OdGiPointCloudXformFilter);
/** \details
Default constructor for the OdGiPointCloudXformFilter class.
*/
OdGiPointCloudXformFilter() : m_pBB(NULL) {}
/** \details
Destructor for the OdGiPointCloudXformFilter class.
*/
~OdGiPointCloudXformFilter() { if (m_pBB) delete m_pBB; }
protected:
virtual bool filterPointsImpl(OdGiPointCloud::ComponentsRaw *&pPoints, OdUInt32 &nArrays, OdUInt32 &compFlags, const OdGeBoundBlock3d *&pExtents) const;
virtual bool filterBoundingBoxImpl(OdGeBoundBlock3d &bb) const
{
bb.transformBy(m_xForm);
return true;
}
virtual void extractTransformImpl(OdGeMatrix3d &xForm) const
{ xForm.preMultBy(m_xForm); }
public:
/** \details
Sets transformation matrix for this object.
\param xForm [in] Tranform matrix to set.
*/
void setXform(const OdGeMatrix3d &xForm) { m_xForm = xForm; }
/** \details
Adds transformation matrix for this object.
\param xForm [in] Transform matrix that is multiplied with current transform matrix.
*/
void addXform(const OdGeMatrix3d &xForm) { m_xForm.preMultBy(xForm); }
/** \details
Returns transformation matrix for this object.
\returns
Reference to OdGeMatrix3d instance representing current transformation matrix.
*/
const OdGeMatrix3d &getXform() const { return m_xForm; }
/** \details
Resets current transformation matrix to identity matrix.
*/
void resetXform() { m_xForm.setToIdentity(); }
/** \details
Checks whether transformation matrix of this object is a non-identity transformation matrix.
\returns
True if this object has non-identity transformation matrix, false otherwise.
*/
bool hasXform() const { return m_xForm != OdGeMatrix3d::kIdentity; }
/** \details
Returns transformation matrix for this object.
\returns
Reference to OdGeMatrix3d instance representing current transformation matrix.
*/
OdGeMatrix3d &accessXform() { return m_xForm; }
/** \details
Creates an OdGiPointCloudXformFilter object and returns a smart pointer to it.
\param xForm [in] Transform matrix to set.
\param pPrevFilter [in] Previous filter.
\returns
Smart pointer to the created object.
*/
static OdGiPointCloudFilterPtr createObject(const OdGeMatrix3d &xForm, const OdGiPointCloudFilter *pPrevFilter = NULL);
};
/** \details
Default implementation of point cloud data transformation filter.
*/
class ODGI_EXPORT OdGiPointCloudComponentsFilter : public OdGiPointCloudFilter
{
protected:
mutable OdGiPointCloud::ComponentsArray m_comps;
OdUInt32 m_requestComps = 0;
public:
ODRX_DECLARE_MEMBERS(OdGiPointCloudComponentsFilter);
protected:
virtual bool filterPointsImpl(OdGiPointCloud::ComponentsRaw *&pPoints, OdUInt32 &nArrays, OdUInt32 &compFlags, const OdGeBoundBlock3d *&pExtents) const;
virtual bool filterBoundingBoxImpl(OdGeBoundBlock3d &) const { return true; }
public:
void setComponentsRequest(OdUInt32 compFlags) { m_requestComps = compFlags; }
OdUInt32 componentsRequest() const { return m_requestComps; }
OdGiPointCloud::ComponentsArray &components() const { return m_comps; }
static OdGiPointCloudFilterPtr createObject(OdUInt32 compFlags, const OdGiPointCloudFilter *pPrevFilter = NULL);
};
/** \details
Point cloud filter placeholder.
*/
class ODGI_EXPORT OdGiPointCloudPlaceholdFilter : public OdGiPointCloudFilter
{
public:
// ODRX_DECLARE_MEMBERS(OdGiPointCloudComponentsFilter); // No need own RTTI
protected:
virtual bool filterPointsImpl(OdGiPointCloud::ComponentsRaw *& /*pPoints*/, OdUInt32 & /*nArrays*/, OdUInt32 & /*compFlags*/,
const OdGeBoundBlock3d *& /*pExtents*/) const { return true; }
virtual bool filterBoundingBoxImpl(OdGeBoundBlock3d & /*bb*/) const { return true; }
public:
static OdGiPointCloudFilterPtr createObject(const OdGiPointCloudFilter *pPrevFilter = NULL, bool bForce = false);
};
typedef OdUInt64 OdGiPointCloudCellId;
const OdGiPointCloudCellId kGiPointCloudNegativeCellId = OdGiPointCloudCellId(-1);
/** \details
Point cloud data receiver.
*/
class FIRSTDLL_EXPORT OdGiPointCloudReceiver : public OdRxObject
{
protected:
OdGiPointCloudFilterPtr m_pFilter;
OdGiPointCloud::ComponentsRawArray m_comps;
public:
ODRX_DECLARE_MEMBERS(OdGiPointCloudReceiver);
protected:
void attachFilter(const OdGiPointCloudFilter *pFilter)
{ m_pFilter = pFilter; }
OdGiPointCloudFilterPtr detachFilter()
{ OdGiPointCloudFilterPtr pFilter = m_pFilter; m_pFilter.release(); return pFilter; }
OdUInt32 numPointsTotal(const OdGiPointCloud::ComponentsRaw *pArrays, OdUInt32 nArrays) const
{ OdUInt32 nPoints = 0;
for (OdUInt32 nArray = 0; nArray < nArrays; nArray++)
nPoints += pArrays[nArray].m_nPoints;
return nPoints;
}
void copyComponents(OdGiPointCloud::ComponentsRaw *pCopies, const OdGiPointCloud::ComponentsRaw *pArrays, OdUInt32 nArrays) const
{
for (OdUInt32 nComponent = 0; nComponent < nArrays; nComponent++)
pCopies[nComponent] = pArrays[nComponent];
}
virtual bool addPointsImpl(const OdGiPointCloud::ComponentsRaw *pArrays, OdUInt32 nArrays, OdUInt32 compFlags,
OdGiPointCloudCellId nCellId, const OdGeBoundBlock3d *pExtents) = 0;
virtual bool removePointsImpl(OdUInt32 /*nPoints*/, OdGiPointCloudCellId /*nCellId*/) { return false; }
private:
bool addPointsFiltered(const OdGiPointCloud::ComponentsRaw *pArrays, OdUInt32 nArrays, OdUInt32 compFlags,
OdGiPointCloudCellId nCellId, const OdGeBoundBlock3d *pExtents)
{ OdGiPointCloud::ComponentsRaw pointsCopy;
OdGiPointCloud::ComponentsRaw *pCopy = NULL;
if (nArrays == 1) pointsCopy = *pArrays, pCopy = &pointsCopy;
else if (nArrays > 1) m_comps.resize(nArrays),
copyComponents(m_comps.asArrayPtr(), pArrays, nArrays), pCopy = m_comps.asArrayPtr();
if (m_pFilter->filterPoints(pCopy, nArrays, compFlags, pExtents))
return addPointsImpl(pCopy, nArrays, compFlags, nCellId, pExtents);
return true;
}
public:
bool addPoints(const OdGiPointCloud::ComponentsRaw *pArrays, OdUInt32 nArrays, OdUInt32 compFlags,
OdGiPointCloudCellId nCellId = kGiPointCloudNegativeCellId, const OdGeBoundBlock3d *pExtents = NULL)
{
if (!m_pFilter.isNull())
return addPointsFiltered(pArrays, nArrays, compFlags, nCellId, pExtents);
else
return addPointsImpl(pArrays, nArrays, compFlags, nCellId, pExtents);
}
bool removePoints(OdUInt32 nPoints, OdGiPointCloudCellId nCellId = kGiPointCloudNegativeCellId)
{
return removePointsImpl(nPoints, nCellId);
}
};
/** \details
Default implementation of point cloud data receiver for extents computation.
*/
class ODGI_EXPORT OdGiPointCloudExtentsReceiver : public OdGiPointCloudReceiver
{
protected:
OdGeExtents3d m_extents;
public:
ODRX_DECLARE_MEMBERS(OdGiPointCloudExtentsReceiver);
protected:
virtual bool addPointsImpl(const OdGiPointCloud::ComponentsRaw *pArrays, OdUInt32 nArrays, OdUInt32 compFlags,
OdGiPointCloudCellId /*nCellId*/, const OdGeBoundBlock3d *pExtents);
public:
static OdGiPointCloudReceiverPtr createObject(const OdGiPointCloudFilter *pFilter)
{ OdSmartPtr pObj = createObject();
pObj->attachFilter(pFilter);
return pObj;
}
const OdGeExtents3d &getExtents() const { return m_extents; }
void resetExtents() { m_extents = OdGeExtents3d::kInvalid; }
};
/** \details
External point cloud updating scheduler.
*/
class ODGI_EXPORT OdGiPointCloudScheduler
{
public:
enum SchedulerState
{
kDisabled = 0, // Scheduler disabled
kProcessing, // Scheduler enabled, data processing in progress.
kStopped // Scheduler requests abort of data processing.
};
protected:
OdRefCounter m_numTasks;
public:
/** \details
Default constructor for the OdGiPointCloudScheduler class.
*/
OdGiPointCloudScheduler() : m_numTasks(0) {}
/** \details
Desctructor for the OdGiPointCloudScheduler class.
*/
virtual ~OdGiPointCloudScheduler() {}
/** \details
Called by vectorizer when point cloud processing started.
*/
virtual void startScheduling() = 0;
/** \details
Called by vectorizer when point cloud processing completed.
*/
virtual void stopScheduling() = 0;
/** \details
Check current scheduler state.
*/
virtual SchedulerState checkSchedulerState(bool bFinal = false) = 0;
/** \details
Register task. Returns true if this is first registered task.
*/
bool onTaskAdded() { return (++m_numTasks) == 1; }
/** \details
Unregister task. Returns true if this is last registered task.
*/
bool onTaskCompleted() { return !(--m_numTasks); }
/** \details
Checks number of registered tasks.
*/
int numTasks() const { return m_numTasks; }
};
/** \details
Default timer-based scheduler implementation.
*/
class ODGI_EXPORT OdGiPointCloudTimerBasedScheduler : public OdGiPointCloudScheduler
{
protected:
OdPerfTimerBase *m_pTimer;
OdUInt32 m_msec;
SchedulerState m_eState;
public:
/** \details
Default constructor for the OdGiPointCloudTimerBasedScheduler class.
*/
OdGiPointCloudTimerBasedScheduler() : m_pTimer(NULL), m_msec(1000), m_eState(kDisabled) {}
/** \details
Destructor for the OdGiPointCloudTimerBasedScheduler class.
*/
~OdGiPointCloudTimerBasedScheduler();
/** \details
Called by vectorizer when point cloud processing started.
*/
void startScheduling();
/** \details
Called by vectorizer when point cloud processing completed.
*/
void stopScheduling();
/** \details
Setup timer period in milliseconds.
*/
void setTimerPeriod(OdUInt32 msec) { m_msec = msec; }
/** \details
Return timer period in milliseconds.
*/
OdUInt32 timerPeriod() const { return m_msec; }
/** \details
Check current scheduler state.
*/
SchedulerState checkSchedulerState(bool bFinal = false);
};
#include "TD_PackPop.h"
#endif // __ODGIPOINTCLOUD_H__