@@ -224,27 +224,84 @@ void NDT::getVisualizationInto(mrpt::opengl::CSetOfObjects& outObj) const
224
224
MRPT_START
225
225
if (!genericMapParams.enableSaveAs3DObject ) return ;
226
226
227
+ // Calculate histograms / stats:
228
+ auto bb = this ->boundingBox ();
229
+
230
+ // handle planar maps (avoids error in histogram below):
231
+ for (int i = 0 ; i < 3 ; i++)
232
+ if (bb.max [i] - bb.min [i] < 0 .1f ) bb.max [i] = bb.min [i] + 0 .1f ;
233
+
234
+ // Use a histogram to discard outliers from the colormap extremes:
235
+ constexpr size_t nBins = 100 ;
236
+ // for x,y,z
237
+ std::array<mrpt::math::CHistogram, 3 > hists = {
238
+ mrpt::math::CHistogram (bb.min .x , bb.max .x , nBins),
239
+ mrpt::math::CHistogram (bb.min .y , bb.max .y , nBins),
240
+ mrpt::math::CHistogram (bb.min .z , bb.max .z , nBins)};
241
+
242
+ size_t nPoints = 0 ;
243
+
244
+ const auto lambdaVisitPointsForHist =
245
+ [&hists, &nPoints](const mrpt::math::TPoint3Df& pt)
246
+ {
247
+ for (int i = 0 ; i < 3 ; i++) hists[i].add (pt[i]);
248
+ nPoints++;
249
+ };
250
+
251
+ this ->visitAllPoints (lambdaVisitPointsForHist);
252
+
253
+ float recolorMin = .0 , recolorMax = 1 .f ;
254
+ if (nPoints)
255
+ {
256
+ // Analyze the histograms and get confidence intervals:
257
+ std::vector<double > coords;
258
+ std::vector<double > hits;
259
+
260
+ const int idx = renderOptions.recolorizeByCoordinateIndex ;
261
+ ASSERT_ (idx >= 0 && idx < 3 );
262
+
263
+ constexpr double confidenceInterval = 0.02 ;
264
+
265
+ hists[idx].getHistogramNormalized (coords, hits);
266
+ mrpt::math::confidenceIntervalsFromHistogram (
267
+ coords, hits, recolorMin, recolorMax, confidenceInterval);
268
+ }
269
+ const float recolorK =
270
+ recolorMax != recolorMin ? 1 .0f / (recolorMax - recolorMin) : 1 .0f ;
271
+
272
+ // points:
227
273
MRPT_TODO (" option to hide points already with NDT" );
228
274
if (renderOptions.points_visible )
229
275
{
230
- auto obj = mrpt::opengl::CPointCloud ::Create ();
276
+ auto obj = mrpt::opengl::CPointCloudColoured ::Create ();
231
277
232
- const auto lambdaVisitPoints = [&obj](const mrpt::math::TPoint3Df& pt)
233
- { obj->insertPoint (pt); };
278
+ const auto lambdaVisitPoints = [&obj](const mrpt::math::TPoint3Df& pt) {
279
+ obj->insertPoint ({pt.x , pt.y , pt.z , 0 , 0 , 0 });
280
+ };
234
281
this ->visitAllPoints (lambdaVisitPoints);
235
282
236
- obj->setColor (renderOptions.points_color );
283
+ if (renderOptions.points_colormap == mrpt::img::cmNONE)
284
+ obj->setColor (renderOptions.points_color );
285
+ else
286
+ {
287
+ if (!obj->empty ())
288
+ obj->recolorizeByCoordinate (
289
+ recolorMin, recolorMax,
290
+ renderOptions.recolorizeByCoordinateIndex ,
291
+ renderOptions.points_colormap );
292
+ }
293
+
237
294
obj->setPointSize (renderOptions.point_size );
238
- obj->enableColorFromZ (false );
239
295
outObj.insert (obj);
240
296
}
241
297
298
+ // planes:
242
299
if (renderOptions.planes_visible )
243
300
{
244
301
auto obj = mrpt::opengl::CSetOfTriangles::Create ();
245
302
246
303
const auto lambdaVisitVoxel =
247
- [&obj, this ](
304
+ [&obj, recolorK, recolorMin, this ](
248
305
[[maybe_unused]] const global_index3d_t & idx,
249
306
const VoxelData& v)
250
307
{
@@ -264,7 +321,18 @@ void NDT::getVisualizationInto(mrpt::opengl::CSetOfObjects& outObj) const
264
321
const auto vy = ndt->eigVectors .at (2 ).cast <float >() * s;
265
322
266
323
mrpt::opengl::TTriangle t;
267
- t.setColor (renderOptions.planes_color );
324
+
325
+ if (renderOptions.planes_colormap == mrpt::img::cmNONE)
326
+ t.setColor (renderOptions.planes_color );
327
+ else
328
+ {
329
+ t.setColor (mrpt::img::colormap (
330
+ renderOptions.planes_colormap ,
331
+ recolorK *
332
+ (center[renderOptions.recolorizeByCoordinateIndex ] -
333
+ recolorMin)));
334
+ }
335
+
268
336
t.vertices [0 ].xyzrgba .pt = center + vx + vy;
269
337
t.vertices [1 ].xyzrgba .pt = center - vx - vy;
270
338
t.vertices [2 ].xyzrgba .pt = center + vx - vy;
@@ -282,6 +350,7 @@ void NDT::getVisualizationInto(mrpt::opengl::CSetOfObjects& outObj) const
282
350
outObj.insert (obj);
283
351
}
284
352
353
+ // normals:
285
354
if (renderOptions.normals_visible )
286
355
{
287
356
auto obj = mrpt::opengl::CSetOfLines::Create ();
@@ -302,7 +371,7 @@ void NDT::getVisualizationInto(mrpt::opengl::CSetOfObjects& outObj) const
302
371
303
372
// eigenVector[0] is the plane normal.
304
373
// [1] and [2] are parallel to the plane surface:
305
- const float s = voxel_size_ * 0 .5f ;
374
+ const float s = voxel_size_ * 0 .2f ;
306
375
const auto vz = ndt->eigVectors .at (0 ).cast <float >() * s;
307
376
308
377
const auto p1 = center;
@@ -777,11 +846,14 @@ void NDT::TLikelihoodOptions::readFromStream(mrpt::serialization::CArchive& in)
777
846
void NDT::TRenderOptions::writeToStream (
778
847
mrpt::serialization::CArchive& out) const
779
848
{
780
- const int8_t version = 0 ;
849
+ const int8_t version = 1 ;
781
850
out << version;
782
851
out << points_visible << point_size << points_color;
783
852
out << planes_visible << planes_color;
784
853
out << normals_visible << normals_color;
854
+ out << static_cast <int8_t >(points_colormap)
855
+ << static_cast <int8_t >(planes_colormap)
856
+ << recolorizeByCoordinateIndex; // v1
785
857
}
786
858
787
859
void NDT::TRenderOptions::readFromStream (mrpt::serialization::CArchive& in)
@@ -791,10 +863,17 @@ void NDT::TRenderOptions::readFromStream(mrpt::serialization::CArchive& in)
791
863
switch (version)
792
864
{
793
865
case 0 :
866
+ case 1 :
794
867
{
795
868
in >> points_visible >> point_size >> points_color;
796
869
in >> planes_visible >> planes_color;
797
870
in >> normals_visible >> normals_color;
871
+ if (version >= 1 )
872
+ {
873
+ in.ReadAsAndCastTo <int8_t >(this ->points_colormap );
874
+ in.ReadAsAndCastTo <int8_t >(this ->planes_colormap );
875
+ in >> recolorizeByCoordinateIndex;
876
+ }
798
877
}
799
878
break ;
800
879
default :
@@ -842,6 +921,10 @@ void NDT::TRenderOptions::dumpToTextStream(std::ostream& out) const
842
921
LOADABLEOPTS_DUMP_VAR (normals_color.R , float );
843
922
LOADABLEOPTS_DUMP_VAR (normals_color.G , float );
844
923
LOADABLEOPTS_DUMP_VAR (normals_color.B , float );
924
+
925
+ LOADABLEOPTS_DUMP_VAR (points_colormap, int );
926
+ LOADABLEOPTS_DUMP_VAR (planes_colormap, int );
927
+ LOADABLEOPTS_DUMP_VAR (recolorizeByCoordinateIndex, int );
845
928
}
846
929
847
930
void NDT::TInsertionOptions::loadFromConfigFile (
@@ -879,6 +962,10 @@ void NDT::TRenderOptions::loadFromConfigFile(
879
962
MRPT_LOAD_CONFIG_VAR (normals_color.R , float , c, s);
880
963
MRPT_LOAD_CONFIG_VAR (normals_color.G , float , c, s);
881
964
MRPT_LOAD_CONFIG_VAR (normals_color.B , float , c, s);
965
+
966
+ points_colormap = c.read_enum (s, " points_colormap" , this ->points_colormap );
967
+ planes_colormap = c.read_enum (s, " planes_colormap" , this ->planes_colormap );
968
+ MRPT_LOAD_CONFIG_VAR (recolorizeByCoordinateIndex, int , c, s);
882
969
}
883
970
884
971
void NDT::internal_insertPointCloud3D (
0 commit comments