ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ccPointCloud.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "../casters.h"
9 #include <ecvAdvancedTypes.h>
10 #include <ecvColorTypes.h>
11 
12 #include <climits>
13 #include <cstdint>
14 #include <ecvPointCloud.h>
15 #include <ecvPolyline.h>
16 #include <ecvProgressDialog.h>
17 #include <ecvScalarField.h>
18 #include <pybind11/pytypes.h>
19 #include <type_traits>
20 #include <vector>
21 
22 #undef slots
23 #include <pybind11/functional.h>
24 #include <pybind11/numpy.h>
25 #include <pybind11/pybind11.h>
26 #include <pybind11/stl.h>
27 #include <pybind11/stl_bind.h>
28 
29 #include "wrappers.h"
30 
31 static_assert(std::is_same<PointCoordinateType, float>::value,
32  "PointCoordinateType is neither double or float");
33 static_assert(sizeof(CCVector3) == sizeof(PointCoordinateType) * 3,
34  "Unexpected layout for CCVector3");
35 
36 void define_ccPointCloud(py::module &m)
37 {
38  DEFINE_POINTCLOUDTPL(ccGenericPointCloud, m, "__ccGenericPointCloudTpl");
39  py::class_<ccPointCloud, cloudViewer::PointCloudTpl<ccGenericPointCloud>>(m,
40  "ccPointCloud",
41  R"doc(
42  The main class to represent point clouds in ACloudViewer.
43 
44 
45 
46  Two constructor are available:
47 
48  Parameters
49  ----------
50  name: str,
51  The name of the point cloud
52  uniqueID: int
53  Unique ID, you practically never need to give a value as it is
54  one is already selected by default.
55 
56  Example
57  -------
58 
59  .. code:: Python
60 
61  import pycc
62  pc = pycc.ccPointCloud("Yoshi's Island")
63 
64 
65 
66  Parameters
67  ----------
68  x: numpy.array
69  y: numpy.array
70  z: numpy.array
71 
72  Example
73  -------
74 
75  .. code:: Python
76 
77  import numpy as np
78  import pycc
79 
80  x = np.array([1, 2, 3])
81  y = np.array([1, 2, 3])
82  z = np.array([1, 2, 3])
83  pc = pycc.ccPointCloud(x, y, z)
84 
85 )doc")
86  .def(py::init<QString>(), "name"_a = QString())
87  .def(py::init(
88  [](py::array_t<PointCoordinateType> &xs,
89  py::array_t<PointCoordinateType> &ys,
90  py::array_t<PointCoordinateType> &zs)
91  {
92  auto pointCloud = new ccPointCloud;
93  try
94  {
95  PyCC::addPointsFromArrays(*pointCloud, xs, ys, zs);
96  }
97  catch (const std::exception &)
98  {
99  delete pointCloud;
100  throw;
101  }
102 
103  return pointCloud;
104  }))
105  // features deletion/clearing
106  .def(
107  "partialClone",
108  [](const ccPointCloud &self, const cloudViewer::ReferenceCloud *refCloud)
109  { return self.partialClone(refCloud); },
110  "reference"_a)
111  // features allocation/resize
112  .def("reserveThePointsTable", &ccPointCloud::reserveThePointsTable, "_numberOfPoints"_a)
113  .def("reserveTheRGBTable", &ccPointCloud::reserveThePointsTable)
114  .def("reserveTheRGBTable", &ccPointCloud::reserveThePointsTable, "fillWithWhite"_a = false)
115  .def("reserveTheNormsTable", &ccPointCloud::reserveTheNormsTable)
116  .def("resizeTheNormsTable", &ccPointCloud::resizeTheNormsTable)
117  .def("shrinkToFit", &ccPointCloud::shrinkToFit)
118  // ScalarField management
119  .def("getCurrentDisplayedScalarField", &ccPointCloud::getCurrentDisplayedScalarField)
120  .def("getCurrentDisplayedScalarFieldIndex",
122  .def("setCurrentDisplayedScalarField",
124  "index"_a)
125  .def("setPointSize", &ccPointCloud::setPointSize, "size"_a)
126  .def("sfColorScaleShown", &ccPointCloud::sfColorScaleShown)
127  .def("showSFColorsScale", &ccPointCloud::showSFColorsScale, "state"_a)
128  // normals computation/orientation
129  .def("computeNormalsWithGrids",
131  "minTriangleAngle_deg"_a = 1.0,
132  "pDlg"_a = nullptr)
133  .def("orientNormalsTowardViewPoint",
135  "VP"_a,
136  "pDlg"_a = nullptr)
137  .def("computeNormalsWithOctree",
139  "model"_a,
140  "preferredOrientation"_a,
141  "defaultRadius"_a,
142  "pDlg"_a = nullptr)
143  .def("orientNormalsWithMST",
145  "kNN"_a,
146  "pDlg"_a = nullptr)
147  .def("orientNormalsWithFM",
149  "level"_a,
150  "pDlg"_a = nullptr)
151  // Special functions added by pycc
152  .def("addPoints", &PyCC::addPointsFromArrays<ccPointCloud>)
153  .def("setColor",
154  [](ccPointCloud &self,
155  ColorCompType r,
156  ColorCompType g,
157  ColorCompType b,
158  ColorCompType a = 255) { self.setRGBColor(r, g, b); })
159  .def("setPointNormal", &ccPointCloud::setPointNormal, "index"_a, "normal"_a)
160  .def("addNorm", &ccPointCloud::addNorm, "normal"_a)
161  .def("addNormals",
162  [](ccPointCloud &self,
163  const py::array_t<PointCoordinateType> &nx,
164  const py::array_t<PointCoordinateType> &ny,
165  const py::array_t<PointCoordinateType> &nz)
166  {
167  if (nx.size() != ny.size() || nx.size() != nz.size())
168  {
169  throw py::value_error("nx, ny, nz must have the same size");
170  }
171 
172  const py::ssize_t numToReserve = self.size() + nx.size();
173  if (numToReserve > std::numeric_limits<unsigned int>::max())
174  {
175  throw std::out_of_range(std::to_string(numToReserve) +
176  " cannot be casted to unsigned int");
177  }
178  self.reserve(static_cast<unsigned int>(numToReserve));
179 
180  auto xs_it = nx.begin();
181  auto ys_it = ny.begin();
182  auto zs_it = nz.begin();
183 
184  while (xs_it != nx.end())
185  {
186  self.addNorm({xs_it->cast<PointCoordinateType>(),
187  ys_it->cast<PointCoordinateType>(),
188  zs_it->cast<PointCoordinateType>()});
189  ++xs_it;
190  ++ys_it;
191  ++zs_it;
192  }
193  })
194  .def("colorize", &ccPointCloud::colorize)
195  .def("crop2D", &ccPointCloud::crop2D, "poly"_a, "orthodDim"_a, "inside"_a = true)
196  .def("colors",
197  [](ccPointCloud &self) -> py::object
198  {
199  ColorsTableType *colorsTable = self.rgbColors();
200  if (colorsTable == nullptr)
201  {
202  return py::none();
203  }
204 
205  ecvColor::Rgb *colors = colorsTable->data();
206  if (colors == nullptr)
207  {
208  return py::none();
209  }
210 
211  static_assert(CHAR_BIT == 8, "A char must have 8 bits");
212  static_assert(sizeof(ColorCompType) == 1, "ColorCompType must have 8 bit");
213  static_assert(sizeof(ecvColor::Rgb) == 3 * sizeof(ColorCompType), "");
214  static_assert(alignof(uint8_t) == alignof(ecvColor::Rgba), "Not same alignment");
215 
216  auto *ptr = reinterpret_cast<uint8_t *>(colors);
217 
218  auto capsule = py::capsule(ptr, [](void *) {});
219  py::array a(py::dtype("3u1"), colorsTable->size(), ptr, capsule);
220 
221  return a;
222  })
223  .def("points",
224  [](ccPointCloud &self)
225  {
226  if (self.size() > 0)
227  {
228  // FIXME, ideally, ccPointCloud would have a .points() method returning a ref
229  // to the std::vector of points, and we would avoid the const cast
230  auto *ptr = const_cast<CCVector3 *>(self.getPoint(0));
231  auto capsule = py::capsule(ptr, [](void *) {});
232  py::array a(py::dtype("3f"), self.size(), ptr, capsule);
233  // Make the array non-writeable to make up for the const cast
234  a.attr("flags").attr("writeable") = false;
235  return a;
236  }
237  else
238  {
239  return py::array(py::dtype("3f"), 0);
240  }
241  })
242  .def("__repr__",
243  [](const ccPointCloud &self)
244  {
245  return std::string("<ccPointCloud(") + "'" + self.getName().toStdString() + "', " +
246  std::to_string(self.size()) + " points)>";
247  });
248 }
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
int size
void define_ccPointCloud(py::module &m)
Array of RGB colors for each point.
A 3D cloud interface with associated features (color, normals, octree, etc.)
void setPointSize(unsigned size=0)
Sets point size.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void setCurrentDisplayedScalarField(int index)
Sets the currently displayed scalar field.
bool sfColorScaleShown() const
Returns whether color scale should be displayed or not.
bool resizeTheNormsTable()
Resizes the compressed normals array.
bool orientNormalsTowardViewPoint(CCVector3 &VP, ecvProgressDialog *pDlg=nullptr)
Normals are forced to point to O.
void addNorm(const CCVector3 &N)
Pushes a normal vector on stack (shortcut)
bool computeNormalsWithGrids(double minTriangleAngle_deg=1.0, ecvProgressDialog *pDlg=nullptr)
Compute the normals with the associated grid structure(s)
void showSFColorsScale(bool state)
Sets whether color scale should be displayed or not.
bool computeNormalsWithOctree(CV_LOCAL_MODEL_TYPES model, ccNormalVectors::Orientation preferredOrientation, PointCoordinateType defaultRadius, ecvProgressDialog *pDlg=nullptr)
Compute the normals by approximating the local surface around each point.
bool orientNormalsWithFM(unsigned char level, ecvProgressDialog *pDlg=nullptr)
Orient normals with Fast Marching.
bool orientNormalsWithMST(unsigned kNN=6, ecvProgressDialog *pDlg=nullptr)
Orient the normals with a Minimum Spanning Tree.
bool colorize(float r, float g, float b)
Multiplies all color components of all points by coefficients.
bool reserveTheNormsTable()
Reserves memory to store the compressed normals.
int getCurrentDisplayedScalarFieldIndex() const
Returns the currently displayed scalar field index (or -1 if none)
void setPointNormal(size_t pointIndex, const CCVector3 &N)
Sets a particular point normal (shortcut)
cloudViewer::ReferenceCloud * crop2D(const ccPolyline *poly, unsigned char orthoDim, bool inside=true)
Crops the cloud inside (or outside) a 2D polyline.
ccScalarField * getCurrentDisplayedScalarField() const
Returns the currently displayed scalar (or 0 if none)
void shrinkToFit()
Removes unused capacity.
bool reserveThePointsTable(unsigned _numberOfPoints)
Reserves memory to store the points coordinates.
A very simple point cloud (no point duplication)
RGB color structure.
Definition: ecvColorTypes.h:49
RGBA color structure.
double colors[3]
int max(int a, int b)
Definition: cutil_math.h:48
unsigned char ColorCompType
Default color components type (R,G and B)
Definition: ecvColorTypes.h:29
void addPointsFromArrays(PointCloudType &self, py::array_t< PointCoordinateType > &xs, py::array_t< PointCoordinateType > &ys, py::array_t< PointCoordinateType > &zs)
Definition: wrappers.h:94
std::string to_string(const T &n)
Definition: Common.h:20
#define DEFINE_POINTCLOUDTPL(T, module, name)
Definition: wrappers.h:155