9 #ifndef opengl_COctreePointRenderer_H 10 #define opengl_COctreePointRenderer_H 20 namespace global_settings
50 template <
class Derived>
80 return *
static_cast<const Derived*
>(
this);
141 std::numeric_limits<float>::max(),
142 std::numeric_limits<float>::max(),
143 std::numeric_limits<float>::max()),
145 -
std::numeric_limits<float>::max(),
146 -
std::numeric_limits<float>::max(),
147 -
std::numeric_limits<float>::max()),
201 switch (my_child_index)
260 throw std::runtime_error(
"my_child_index!=[0,7]");
296 bool corners_are_all_computed =
true,
297 bool trust_me_youre_visible =
false,
298 float approx_area_sqpixels = 0)
const 302 if (!corners_are_all_computed)
304 for (
int i = 0; i < 8; i++)
308 node.getCornerX(i), node.getCornerY(i), node.getCornerZ(i),
309 cr_px[i].
x, cr_px[i].
y, cr_z[i]);
314 std::numeric_limits<float>::max(),
315 std::numeric_limits<float>::max()),
317 -std::numeric_limits<float>::max(),
318 -std::numeric_limits<float>::max());
319 if (!trust_me_youre_visible)
322 for (
int i = 0; i < 8; i++)
330 const bool any_cr_zs_neg =
331 (cr_z[0] < 0 || cr_z[1] < 0 || cr_z[2] < 0 || cr_z[3] < 0 ||
332 cr_z[4] < 0 || cr_z[5] < 0 || cr_z[6] < 0 || cr_z[7] < 0);
333 const bool any_cr_zs_pos =
334 (cr_z[0] > 0 || cr_z[1] > 0 || cr_z[2] > 0 || cr_z[3] > 0 ||
335 cr_z[4] > 0 || cr_z[5] > 0 || cr_z[6] > 0 || cr_z[7] > 0);
336 const bool box_crosses_image_plane = any_cr_zs_pos && any_cr_zs_neg;
341 if (!box_crosses_image_plane &&
343 px_max.
x < 0 || px_max.
y < 0))
350 if (node.all || !node.pts.empty())
356 float render_area_sqpixels =
357 trust_me_youre_visible ? approx_area_sqpixels
358 : std::abs(px_min.x - px_max.
x) *
359 std::abs(px_min.y - px_max.
y);
360 render_area_sqpixels = std::max(1.0f, render_area_sqpixels);
364 TRenderQueueElement(node_idx, render_area_sqpixels));
373 bool children_are_all_visible_for_sure =
true;
375 if (!trust_me_youre_visible)
377 for (
int i = 0; i < 8; i++)
379 if (!(cr_px[i].
x >= 0 && cr_px[i].
y >= 0 &&
383 children_are_all_visible_for_sure =
false;
390 if (children_are_all_visible_for_sure)
397 const float approx_child_area =
398 trust_me_youre_visible
399 ? approx_area_sqpixels / 8.0f
400 : std::abs(px_min.x - px_max.
x) *
401 std::abs(px_min.y - px_max.
y) / 8.0f;
403 for (
int i = 0; i < 8; i++)
405 node.child_id[i], ri, child_cr_px, child_cr_z,
true,
406 true, approx_child_area);
411 #pragma clang diagnostic push // clang complains about unused vars (becase it 413 #pragma clang diagnostic ignored "-Wunused-variable" 419 node.bb_min.x, node.bb_min.y, node.bb_min.z);
421 node.center.x, node.bb_min.y, node.bb_min.z);
423 node.bb_max.x, node.bb_min.y, node.bb_min.z);
425 node.bb_min.x, node.center.y, node.bb_min.z);
427 node.center.x, node.center.y, node.bb_min.z);
429 node.bb_max.x, node.center.y, node.bb_min.z);
431 node.bb_min.x, node.bb_max.y, node.bb_min.z);
433 node.center.x, node.bb_max.y, node.bb_min.z);
435 node.bb_max.x, node.bb_max.y, node.bb_min.z);
438 node.bb_min.x, node.bb_min.y, node.center.z);
440 node.center.x, node.bb_min.y, node.center.z);
442 node.bb_max.x, node.bb_min.y, node.center.z);
444 node.bb_min.x, node.center.y, node.center.z);
446 node.center.x, node.center.y, node.center.z);
448 node.bb_max.x, node.center.y, node.center.z);
450 node.bb_min.x, node.bb_max.y, node.center.z);
452 node.center.x, node.bb_max.y, node.center.z);
454 node.bb_max.x, node.bb_max.y, node.center.z);
457 node.bb_min.x, node.bb_min.y, node.bb_max.z);
459 node.center.x, node.bb_min.y, node.bb_max.z);
461 node.bb_min.x, node.bb_min.y, node.bb_max.z);
463 node.bb_min.x, node.center.y, node.bb_max.z);
465 node.center.x, node.center.y, node.bb_max.z);
467 node.bb_max.x, node.center.y, node.bb_max.z);
469 node.bb_min.x, node.bb_max.y, node.bb_max.z);
471 node.center.x, node.bb_max.y, node.bb_max.z);
473 node.bb_max.x, node.bb_max.y, node.bb_max.z);
476 #define PROJ_SUB_NODE(POSTFIX) \ 477 mrpt::img::TPixelCoordf px_##POSTFIX; \ 478 float depth_##POSTFIX; \ 479 ri.projectPointPixels( \ 480 p_##POSTFIX.x, p_##POSTFIX.y, p_##POSTFIX.z, px_##POSTFIX.x, \ 481 px_##POSTFIX.y, depth_##POSTFIX); 483 #define PROJ_SUB_NODE_ALREADY_DONE(INDEX, POSTFIX) \ 484 const mrpt::img::TPixelCoordf px_##POSTFIX = cr_px[INDEX]; \ 485 float depth_##POSTFIX = cr_z[INDEX]; 522 #define DO_RECURSE_CHILD( \ 523 INDEX, SEQ0, SEQ1, SEQ2, SEQ3, SEQ4, SEQ5, SEQ6, SEQ7) \ 525 mrpt::img::TPixelCoordf child_cr_px[8] = { \ 526 px_##SEQ0, px_##SEQ1, px_##SEQ2, px_##SEQ3, \ 527 px_##SEQ4, px_##SEQ5, px_##SEQ6, px_##SEQ7}; \ 528 float child_cr_z[8] = {depth_##SEQ0, depth_##SEQ1, depth_##SEQ2, \ 529 depth_##SEQ3, depth_##SEQ4, depth_##SEQ5, \ 530 depth_##SEQ6, depth_##SEQ7}; \ 531 this->octree_recursive_render( \ 532 node.child_id[INDEX], ri, child_cr_px, child_cr_z); \ 538 0, Xm_Ym_Zm, X0_Ym_Zm, Xm_Y0_Zm, X0_Y0_Zm, Xm_Ym_Z0,
539 X0_Ym_Z0, Xm_Y0_Z0, X0_Y0_Z0)
541 1, X0_Ym_Zm, Xp_Ym_Zm, X0_Y0_Zm, Xp_Y0_Zm, X0_Ym_Z0,
542 Xp_Ym_Z0, X0_Y0_Z0, Xp_Y0_Z0)
544 2, Xm_Y0_Zm, X0_Y0_Zm, Xm_Yp_Zm, X0_Yp_Zm, Xm_Y0_Z0,
545 X0_Y0_Z0, Xm_Yp_Z0, X0_Yp_Z0)
547 3, X0_Y0_Zm, Xp_Y0_Zm, X0_Yp_Zm, Xp_Yp_Zm, X0_Y0_Z0,
548 Xp_Y0_Z0, X0_Yp_Z0, Xp_Yp_Z0)
550 4, Xm_Ym_Z0, X0_Ym_Z0, Xm_Y0_Z0, X0_Y0_Z0, Xm_Ym_Zp,
551 X0_Ym_Zp, Xm_Y0_Zp, X0_Y0_Zp)
553 5, X0_Ym_Z0, Xp_Ym_Z0, X0_Y0_Z0, Xp_Y0_Z0, X0_Ym_Zp,
554 Xp_Ym_Zp, X0_Y0_Zp, Xp_Y0_Zp)
556 6, Xm_Y0_Z0, X0_Y0_Z0, Xm_Yp_Z0, X0_Yp_Z0, Xm_Y0_Zp,
557 X0_Y0_Zp, Xm_Yp_Zp, X0_Yp_Zp)
559 7, X0_Y0_Z0, Xp_Y0_Z0, X0_Yp_Z0, Xp_Yp_Z0, X0_Y0_Zp,
560 Xp_Y0_Zp, X0_Yp_Zp, Xp_Yp_Zp)
561 #undef DO_RECURSE_CHILD 563 #undef PROJ_SUB_NODE_ALREADY_DONE 566 #pragma clang diagnostic pop 592 const size_t node_id,
const bool all_pts =
false)
595 const size_t N = all_pts ?
octree_derived().size() : node.pts.size();
606 if (has_to_compute_bb)
609 for (
size_t i = 0; i < N; i++)
612 for (
size_t i = 0; i < N; i++)
622 for (
size_t i = 0; i < N; i++)
626 if (has_to_compute_bb) node.update_bb(
p);
629 for (
size_t i = 0; i < N; i++)
634 if (has_to_compute_bb) node.update_bb(
p);
638 node.is_leaf =
false;
639 node.center =
mean * (1.0f / N);
644 for (
int i = 0; i < 8; i++)
645 node.child_id[i] = children_idx_base + i;
648 for (
int i = 0; i < 8; i++)
655 for (
size_t j = 0; j < N; j++)
657 const size_t i = all_pts ? j : node.pts[j];
705 std::vector<size_t> emptyVec;
706 node.pts.swap(emptyVec);
711 for (
int i = 0; i < 8; i++)
738 const bool draw_solid_boxes =
false)
const 745 if (!node.is_leaf)
continue;
747 mrpt::make_aligned_shared<mrpt::opengl::CBox>();
748 gl_box->setBoxCorners(
751 gl_box->setColor(lines_color);
752 gl_box->setLineWidth(lines_width);
753 gl_box->setWireframe(!draw_solid_boxes);
762 size_t total_elements = 0;
767 o <<
"Node #" << i <<
": ";
778 o << node.pts.size() <<
" elements; ";
779 total_elements += node.pts.size();
784 o <<
"parent, center=(" << node.center.x <<
"," << node.center.y
785 <<
"," << node.center.z <<
"), children: " << node.child_id[0]
786 <<
"," << node.child_id[1] <<
"," << node.child_id[2] <<
"," 787 << node.child_id[3] <<
"," << node.child_id[4] <<
"," 788 << node.child_id[5] <<
"," << node.child_id[6] <<
"," 789 << node.child_id[7] <<
"; ";
791 o <<
" bb: (" << node.bb_min.x <<
"," << node.bb_min.y <<
"," 792 << node.bb_min.z <<
")-(" << node.bb_max.x <<
"," << node.bb_max.y
793 <<
"," << node.bb_max.z <<
")\n";
795 o <<
"Total elements in all nodes: " << total_elements << std::endl;
void clear()
Clear the list of objects in the scene, deleting objects' memory.
The structure for each octree spatial node.
bool is_leaf
true: it's a leaf and pts has valid indices; false: children is valid.
void update_bb(const mrpt::math::TPoint3Df &p)
update bounding box with a new point:
volatile size_t m_visible_octree_nodes_ongoing
bool all
true: All elements in the reference object; false: only those in pts
A set of object, which are referenced to the coordinates framework established in this object...
size_t octree_get_visible_nodes() const
Return the number of visible octree nodes in the last render event.
float getCornerZ(int i) const
size_t OCTREE_RENDER_MAX_POINTS_PER_NODE()
Default value = 1e5.
volatile size_t m_visible_octree_nodes
void octree_get_graphics_boundingboxes(mrpt::opengl::CSetOfObjects &gl_bb, const double lines_width=1, const mrpt::img::TColorf &lines_color=mrpt::img::TColorf(1, 1, 1), const bool draw_solid_boxes=false) const
Returns a graphical representation of all the bounding boxes of the octree (leaf) nodes...
A pair (x,y) of pixel coordinates (subpixel resolution).
void keep_min(T &var, const K test_val)
If the second argument is below the first one, set the first argument to this lower value...
#define MRPT_MAKE_ALIGNED_OPERATOR_NEW
Put this macro inside any class with members that require {16,32,64}-byte memory alignment (e...
const Derived & octree_derived() const
void internal_recursive_split(const size_t node_id, const bool all_pts=false)
Template class that implements the data structure and algorithms for Octree-based efficient rendering...
COctreePointRenderer()
Default ctor.
void keep_max(T &var, const K test_val)
If the second argument is above the first one, set the first argument to this higher value...
TRenderQueueElement(const size_t id, float area_sq)
Lightweight 3D point (float version).
size_t octree_get_node_count() const
Return the number of octree nodes (all of them, including the empty ones)
mrpt::aligned_std_deque< TNode > m_octree_nodes
First one [0] is always the root node.
size_t child_id[8]
[is_leaf=false] The indices in m_octree_nodes of the 8 children.
void OCTREE_RENDER_MAX_DENSITY_POINTS_PER_SQPIXEL(float value)
Default value = 0.01 points/px^2.
std::deque< T, mrpt::aligned_allocator_cpp11< T > > aligned_std_deque
mrpt::math::TPoint3Df center
[is_leaf=false] The center of the node, whose coordinates are used to decide between the 8 children n...
Information about the rendering process being issued.
Derived & octree_derived()
void octree_render(const mrpt::opengl::gl_utils::TRenderInfo &ri) const
Render the entire octree recursively.
mrpt::math::TPoint3Df bb_max
void octree_recursive_render(size_t node_idx, const mrpt::opengl::gl_utils::TRenderInfo &ri, mrpt::img::TPixelCoordf cr_px[8], float cr_z[8], bool corners_are_all_computed=true, bool trust_me_youre_visible=false, float approx_area_sqpixels=0) const
Render a given node.
std::vector< TRenderQueueElement > m_render_queue
The list of elements that really are visible and will be rendered.
COctreePointRenderer(const COctreePointRenderer &)
Copy ctor.
bool m_octree_has_to_rebuild_all
#define PROJ_SUB_NODE(POSTFIX)
void octree_mark_as_outdated()
Called from the derived class (or the user) to indicate we have/want to rebuild the entire node tree ...
void octree_debug_dump_tree(std::ostream &o) const
Used for debug only.
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
std::vector< size_t > pts
Point indices in the derived class that fall into this node.
void internal_octree_assure_uptodate()
A RGB color - floats in the range [0,1].
void octree_getBoundingBox(mrpt::math::TPoint3D &bb_min, mrpt::math::TPoint3D &bb_max) const
#define DO_RECURSE_CHILD( INDEX, SEQ0, SEQ1, SEQ2, SEQ3, SEQ4, SEQ5, SEQ6, SEQ7)
float getCornerY(int i) const
float render_area_sqpixels
The approximate size of the octree on the screen (squared pixels).
GLsizei const GLfloat * value
void projectPointPixels(float x, float y, float z, float &proj_x_px, float &proj_y_px, float &proj_z_depth) const
Exactly like projectPoint but the (x,y) projected coordinates are given in pixels instead of normaliz...
void setBBFromOrderInParent(const TNode &parent, int my_child_index)
size_t node_id
The node ID to render.
void insert(const CRenderizable::Ptr &newObject)
Insert a new object to the list.
void octree_assure_uptodate() const
Must be called at children class' render() previously to octree_render()
EIGEN_STRONG_INLINE double mean() const
Computes the mean of the entire matrix.
#define PROJ_SUB_NODE_ALREADY_DONE(INDEX, POSTFIX)
float getCornerX(int i) const
mrpt::math::TPoint3Df bb_min