15 #include <QElapsedTimer>
26 uint32_t maxCountPerCell)
42 const unsigned char bitDec =
50 #ifdef COMPUTE_REAL_RADIUS
56 codeIndex < cellCodes.size() &&
57 (cellCodes[codeIndex].theCode >> bitDec) ==
58 currentTruncatedCellCode;
63 #ifdef COMPUTE_REAL_RADIUS
71 #ifdef COMPUTE_REAL_RADIUS
74 double maxSquareRadius = 0;
75 for (uint32_t i = 0; i < node.
pointCount; ++i) {
80 if (squareRadius > maxSquareRadius) {
81 maxSquareRadius = squareRadius;
84 node.
radius =
static_cast<float>(sqrt(maxSquareRadius));
105 uint8_t childIndex =
fillNode(childNode);
113 return static_cast<uint8_t
>(currentTruncatedCellCode & 7);
119 m_octree->pointsAndTheirCellCodes();
120 const unsigned char bitDec =
130 codeIndex < cellCodes.size() &&
131 (cellCodes[codeIndex].theCode >> bitDec) ==
132 currentTruncatedCellCode;
143 double maxSquareRadius = 0;
144 for (uint32_t i = 0; i < node.
pointCount; ++i) {
147 double squareRadius =
149 if (squareRadius > maxSquareRadius) {
150 maxSquareRadius = squareRadius;
153 node.
radius =
static_cast<float>(sqrt(maxSquareRadius));
161 return static_cast<uint8_t
>(currentTruncatedCellCode & 7);
171 if (pointCount == 0) {
176 CVLog::Print(QString(
"[LoD] Preparing LoD acceleration structure for "
177 "cloud '%1' [%2 points]...")
190 "cloud '%1' (not enough memory)")
206 CVLog::Warning(QString(
"[LoD] Failed to compute LOD structure on "
207 "cloud '%1' (not enough memory)")
216 [&]() { m_cloud.clearLOD(); });
243 for (uint8_t currentLevel = 0; currentLevel <
m_maxLevel;
246 if (level.
data.empty()) {
266 .arg(level.
data.size()));
274 int32_t childNodeIndex =
298 uint8_t biggestLevel = 0;
321 biggestLevel = std::min<uint8_t>(biggestLevel, 10);
322 for (uint8_t currentLevel = 0; currentLevel < biggestLevel;
325 assert(!level.
data.empty());
327 size_t cellCountBefore =
333 int32_t childNodeIndex =
347 size_t cellCountAfter =
349 CVLog::Print(QString(
"[LoD][pass 2] Level %1: %2 cells (+%3)")
350 .arg(currentLevel + 1)
352 .arg(cellCountAfter - cellCountBefore));
365 QString(
"[LoD] Acceleration structure ready for cloud '%1' "
366 "(max level: %2 / mem. = %3 Mb / duration: %4 s.)")
369 .arg(
m_lod.
memory() /
static_cast<double>(1 << 20), 0,
371 .arg(timer.elapsed() / 1000.0, 0,
'f', 1));
386 m_state(NOT_INITIALIZED) {
395 size_t totalNodeCount = 0;
396 for (
size_t i = 0; i <
m_levels.size(); ++i) {
397 totalNodeCount +=
m_levels[i].data.size();
399 size_t nodeSize =
sizeof(
Node);
400 size_t nodesSize = totalNodeCount * nodeSize;
402 return nodesSize + thisSize;
447 }
catch (
const std::bad_alloc&) {
463 l.
data.emplace_back(level);
465 return static_cast<int32_t
>(l.
data.size()) - 1;
492 for (
size_t i = 1; i <
m_levels.size();
533 for (
size_t l = 0; l <
m_levels.size(); ++l) {
535 n.displayedPointCount = 0;
545 unsigned char maxLevel)
554 }
catch (
const std::bad_alloc&) {
565 for (
int i = 0; i < 8; ++i) {
588 if (dist <= -node.
radius) {
598 uint32_t visibleCount = 0;
610 for (
int i = 0; i < 8; ++i) {
614 visibleCount +=
flag(childNode);
618 if (visibleCount == 0) {
657 *
this, frustum,
static_cast<unsigned char>(
m_levels.size()));
673 uint32_t displayedCount = 0;
676 uint32_t thisNodeRemainingCount =
678 assert(
count <= thisNodeRemainingCount);
679 bool displayAll = (
count >= thisNodeRemainingCount);
681 for (
int i = 0; i < 8; ++i) {
688 uint32_t childNodeRemainingCount =
691 uint32_t childMaxCount = 0;
693 childMaxCount = childNodeRemainingCount;
696 static_cast<double>(childNodeRemainingCount) /
697 thisNodeRemainingCount;
698 childMaxCount =
static_cast<uint32_t
>(
ceil(ratio *
count));
699 if (displayedCount + childMaxCount >
count) {
700 assert(
count >= displayedCount);
701 childMaxCount =
count - displayedCount;
706 uint32_t childDisplayedCount =
710 assert(childDisplayedCount <= childMaxCount);
712 displayedCount += childDisplayedCount;
713 assert(displayedCount <=
count);
726 m_octree->pointsAndTheirCellCodes();
735 return displayedCount;
741 unsigned& remainingPointsAtThisLevel) {
742 remainingPointsAtThisLevel = 0;
765 }
catch (
const std::bad_alloc&) {
771 uint32_t thisPassDisplayCount = 0;
773 bool earlyStop =
false;
774 size_t earlyStopIndex = 0;
782 for (
size_t i = 0; i < l.
data.size(); ++i) {
791 uint32_t nodeMaxCount = 0;
792 uint32_t nodeRemainingCount =
795 nodeMaxCount = nodeRemainingCount;
797 double ratio =
static_cast<double>(nodeRemainingCount) /
799 nodeMaxCount =
static_cast<uint32_t
>(
ceil(ratio * maxCount));
801 if (
m_indexMap.size() + nodeMaxCount >= maxCount) {
804 maxCount -
static_cast<uint32_t
>(
m_indexMap.size());
813 uint32_t nodeDisplayCount =
815 assert(nodeDisplayCount <= nodeMaxCount);
817 thisPassDisplayCount += nodeDisplayCount;
818 assert(thisPassDisplayCount ==
m_indexMap.size());
819 remainingPointsAtThisLevel +=
824 uint32_t totalRemainingCount =
827 assert(totalRemainingCount >= thisPassDisplayCount);
828 totalRemainingCount -= thisPassDisplayCount;
831 if (totalRemainingCount != 0 && thisPassDisplayCount < maxCount) {
833 assert(!earlyStop && remainingPointsAtThisLevel == 0);
835 uint32_t mapFreeSize = maxCount - thisPassDisplayCount;
837 bool displayAll = (mapFreeSize > totalRemainingCount);
840 for (
size_t i = 0; i < l.
data.size(); ++i) {
847 uint32_t nodeMaxCount = 0;
848 uint32_t nodeRemainingCount =
851 nodeMaxCount = nodeRemainingCount;
853 double ratio =
static_cast<double>(nodeRemainingCount) /
855 nodeMaxCount =
static_cast<uint32_t
>(
ceil(ratio * mapFreeSize));
857 if (
m_indexMap.size() + nodeMaxCount >= maxCount) {
860 maxCount -
static_cast<uint32_t
>(
m_indexMap.size());
869 uint32_t nodeDisplayCount =
871 assert(nodeDisplayCount <= nodeMaxCount);
873 thisPassDisplayCount += nodeDisplayCount;
874 assert(thisPassDisplayCount ==
m_indexMap.size());
877 remainingPointsAtThisLevel +=
883 maxCount =
static_cast<unsigned>(
m_indexMap.size());
889 for (
size_t i = earlyStopIndex + 1; i < l.
data.size(); ++i) {
897 uint32_t nodeRemainingCount =
899 remainingPointsAtThisLevel += nodeRemainingCount;
903 if (remainingPointsAtThisLevel) {
915 #include "ecvPointCloudLOD.moc"
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
static bool Print(const char *format,...)
Prints out a formatted message in console.
Intersection sphereInFrustum(const CCVector3f &c, float r) const
ccClipPlaneSet m_clipPlanes
void setClipPlanes(const ccClipPlaneSet &clipPlanes)
uint32_t flag(ccPointCloudLOD::Node &node)
void propagateFlag(ccPointCloudLOD::Node &node, uint8_t flag)
const Frustum & m_frustum
PointCloudLODVisibilityFlagger(ccPointCloudLOD &lod, const Frustum &frustum, unsigned char maxLevel)
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
virtual void setOctree(ccOctree::Shared octree, bool autoAddChild=true)
Sets the associated octree.
virtual ccOctree::Shared getOctree() const
Returns the associated octree (if any)
virtual QString getName() const
Returns object name.
void updated()
Signal sent when the octree organization is modified (cleared, etc.)
QSharedPointer< ccOctree > Shared
Shared pointer.
Thread for background computation.
ccPointCloudLODThread(ccPointCloud &cloud, ccPointCloudLOD &lod, uint32_t maxCountPerCell)
Default constructor.
uint8_t fillNode(ccPointCloudLOD::Node &node) const
Fills a node (and returns its relative position) + recursive.
uint8_t fillNode_flat(ccPointCloudLOD::Node &node) const
Fills a node (and returns its relative position)
virtual ~ccPointCloudLODThread()
Destructor.
ccOctree::Shared m_octree
uint32_t m_maxCountPerCell
L.O.D. (Level of Detail) structure.
QMutex m_mutex
For concurrent access.
void clear()
Clears the structure.
int32_t newCell(unsigned char level)
Reserves a new cell at a given level.
LODIndexSet m_indexMap
Index map.
ccPointCloudLODThread * m_thread
Computing thread.
void shrink_to_fit()
Shrinks the internal data to its minimum size.
virtual ~ccPointCloudLOD()
Destructor.
LODIndexSet m_lastIndexMap
Last index map (pointer on)
LODIndexSet & getIndexMap(unsigned char level, unsigned &maxCount, unsigned &remainingPointsAtThisLevel)
Builds an index map with the remaining visible points.
uint32_t flagVisibility(const Frustum &frustum, ccClipPlaneSet *clipPlanes=0)
Test all cells visibility with a given frustum.
ccPointCloudLOD()
Default constructor.
uint32_t addNPointsToIndexMap(Node &node, uint32_t count)
size_t memory() const
Returns the memory used by the structure (in bytes)
RenderParams m_currentState
Current rendering state.
Node & node(int32_t index, unsigned char level)
bool isBroken()
Returns whether the structure is broken or not.
void setState(State state)
Sets the current state.
void resetVisibility()
Updates the max radius per level FOR ALL CELLS.
bool init(ccPointCloud *cloud)
Initializes the construction process (asynchronous)
std::vector< Level > m_levels
Per-level cells data.
void clearData()
Clears the internal (nodes) data.
static const unsigned char UNDEFINED
Undefined visibility flag.
const ccOctree::Shared & octree() const
Returns the associated octree.
friend ccPointCloudLODThread
ccOctree::Shared m_octree
Associated octree.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
double getDiagNormd() const
Returns diagonal length (double precision)
Vector3Tpl< T > getCenter() const
Returns center.
void add(const Vector3Tpl< T > &P)
'Enlarges' the bounding box with a point
unsigned CellCode
Type of the code of an octree cell.
static const int MAX_OCTREE_LEVEL
Max octree subdivision level.
std::vector< IndexAndCode > cellsContainer
Container of 'IndexAndCode' structures.
static unsigned char GET_BIT_SHIFT(unsigned char level)
Returns the binary shift for a given level of subdivision.
unsigned size() const override
const CCVector3 * getPoint(unsigned index) const override
std::vector< ccClipPlane > ccClipPlaneSet
std::vector< unsigned > LODIndexSet
L.O.D. indexes set.
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
uint32_t displayedPointCount
std::array< int32_t, 8 > childIndexes
Parameters of the current render state.
int unfinishedLevel
Previously unfinished level.
uint32_t visiblePoints
Number of visible points (for the last visibility test)
unsigned unfinishedPoints
Previously unfinished level.
uint32_t displayedPoints
Number of already displayed points.