ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvPlane.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 "ecvPlane.h"
9 
10 // ECV_CORE_LIB
11 #include "ecvMaterialSet.h"
12 #include "ecvPointCloud.h"
13 
14 // CV_CORE_LIB
16 
18  PointCoordinateType yWidth,
19  const ccGLMatrix* transMat /*=0*/,
20  QString name /*=QString("Plane")*/)
21  : ccGenericPrimitive(name, transMat),
22  ccPlanarEntityInterface(getUniqueID()),
23  m_xWidth(xWidth),
24  m_yWidth(yWidth) {
26 }
27 
28 ccPlane::ccPlane(QString name /*=QString("Plane")*/)
29  : ccGenericPrimitive(name), m_xWidth(0), m_yWidth(0) {}
30 
32  // invalid dimensions?
35  return false;
36  }
37 
38  if (!init(4, false, 2, 1)) {
39  CVLog::Error("[ccPlane::buildUp] Not enough memory");
40  return false;
41  }
42 
43  ccPointCloud* verts = vertices();
44  assert(verts);
45  assert(m_triNormals);
46 
47  // B ------ C
48  // | |
49  // A ------ D
50  verts->addPoint(CCVector3(-m_xWidth / 2, -m_yWidth / 2, 0));
51  verts->addPoint(CCVector3(-m_xWidth / 2, m_yWidth / 2, 0));
52  verts->addPoint(CCVector3(m_xWidth / 2, m_yWidth / 2, 0));
53  verts->addPoint(CCVector3(m_xWidth / 2, -m_yWidth / 2, 0));
54 
56 
57  addTriangle(0, 2, 1); // A C B
58  addTriangleNormalIndexes(0, 0, 0);
59  addTriangle(0, 3, 2); // A D C
60  addTriangleNormalIndexes(0, 0, 0);
61 
62  return true;
63 }
64 
66  return finishCloneJob(
68 }
69 
71  // call parent method
73 
74  // show normal vector
75  if (MACRO_Draw3D(context)) {
76  PointCoordinateType scale =
77  sqrt(m_xWidth * m_yWidth) / 2; // DGM: highly empirical ;)
79  }
80 }
81 
83  N = CCVector3(0, 0, 1);
85 
87 }
88 
90  CCVector3 N = getNormal();
91  m_PlaneEquation[0] = N.x;
92  m_PlaneEquation[1] = N.y;
93  m_PlaneEquation[2] = N.z;
94  m_PlaneEquation[3] =
95  getCenter().dot(N); // a point on the plane dot the plane normal
96  return m_PlaneEquation;
97 }
98 
99 void ccPlane::flip() {
100  ccGLMatrix reverseMat;
101  reverseMat.initFromParameters(static_cast<PointCoordinateType>(M_PI),
102  CCVector3(1, 0, 0), CCVector3(0, 0, 0));
103 
104  m_transformation = m_transformation * reverseMat;
106 }
107 
109  double* rms /*=0*/) {
110  // number of points
111  unsigned count = cloud->size();
112  if (count < 3) {
114  "[ccPlane::Fit] Not enough points in input cloud to fit a "
115  "plane!");
116  return nullptr;
117  }
118 
119  cloudViewer::Neighbourhood Yk(cloud);
120 
121  // plane equation
122  const PointCoordinateType* theLSPlane = Yk.getLSPlane();
123  if (!theLSPlane) {
124  CVLog::Warning("[ccPlane::Fit] Not enough points to fit a plane!");
125  return nullptr;
126  }
127 
128  // get the centroid
129  const CCVector3* G = Yk.getGravityCenter();
130  assert(G);
131 
132  // and a local base
133  CCVector3 N(theLSPlane);
134  const CCVector3* X = Yk.getLSPlaneX(); // main direction
135  assert(X);
136  CCVector3 Y = N * (*X);
137 
138  // compute bounding box in 2D plane
139  CCVector2 minXY(0, 0), maxXY(0, 0);
140  cloud->placeIteratorAtBeginning();
141  for (unsigned k = 0; k < count; ++k) {
142  // projection into local 2D plane ref.
143  CCVector3 P = *(cloud->getNextPoint()) - *G;
144 
145  CCVector2 P2D(P.dot(*X), P.dot(Y));
146 
147  if (k != 0) {
148  if (minXY.x > P2D.x)
149  minXY.x = P2D.x;
150  else if (maxXY.x < P2D.x)
151  maxXY.x = P2D.x;
152  if (minXY.y > P2D.y)
153  minXY.y = P2D.y;
154  else if (maxXY.y < P2D.y)
155  maxXY.y = P2D.y;
156  } else {
157  minXY = maxXY = P2D;
158  }
159  }
160 
161  // we recenter the plane
162  PointCoordinateType dX = maxXY.x - minXY.x;
163  PointCoordinateType dY = maxXY.y - minXY.y;
164  CCVector3 Gt = *G + *X * (minXY.x + dX / 2) + Y * (minXY.y + dY / 2);
165  ccGLMatrix glMat(*X, Y, N, Gt);
166 
167  ccPlane* plane = new ccPlane(dX, dY, &glMat);
168 
169  // compute least-square fitting RMS if requested
170  if (rms) {
172  computeCloud2PlaneDistanceRMS(cloud, theLSPlane);
173  plane->setMetaData(QString("RMS"), QVariant(*rms));
174  }
175 
176  return plane;
177 }
178 
179 bool ccPlane::toFile_MeOnly(QFile& out, short dataVersion) const {
180  assert(out.isOpen() && (out.openMode() & QIODevice::WriteOnly));
181  if (dataVersion < 21) {
182  assert(false);
183  return false;
184  }
185 
186  if (!ccGenericPrimitive::toFile_MeOnly(out, dataVersion)) return false;
187 
188  // parameters (dataVersion >= 21)
189  QDataStream outStream(&out);
190  outStream << m_xWidth;
191  outStream << m_yWidth;
192 
193  return true;
194 }
195 
197  return std::max(static_cast<short>(21),
199 }
200 
202  short dataVersion,
203  int flags,
204  LoadedIDMap& oldToNewIDMap) {
205  if (!ccGenericPrimitive::fromFile_MeOnly(in, dataVersion, flags,
206  oldToNewIDMap))
207  return false;
208 
209  // parameters (dataVersion>=21)
210  QDataStream inStream(&in);
213 
214  return true;
215 }
216 
218  trans = m_transformation;
219  return ccBBox(CCVector3(-m_xWidth / 2, -m_yWidth / 2, 0),
220  CCVector3(m_xWidth / 2, m_yWidth / 2, 0));
221 }
222 
223 bool ccPlane::setAsTexture(QImage image, QString imageFilename /*=QString()*/) {
224  return SetQuadTexture(this, image, imageFilename);
225 }
226 
228  QImage image,
229  QString imageFilename /*=QString()*/) {
230  if (!quadMesh || quadMesh->size() > 2 // they may not be reserved yet?
231  || !quadMesh->getAssociatedCloud() ||
232  quadMesh->getAssociatedCloud()->size() >
233  4) // they may not be reserved yet?
234  {
235  CVLog::Warning("[ccPlane::SetQuadTexture] Invalid input quad");
236  }
237  if (image.isNull()) {
238  CVLog::Warning("[ccPlane::SetQuadTexture] Invalid texture image!");
239  return false;
240  }
241 
242  // texture coordinates
243  TextureCoordsContainer* texCoords = quadMesh->getTexCoordinatesTable();
244  if (!texCoords) {
245  texCoords = new TextureCoordsContainer();
246  if (!texCoords->reserveSafe(4)) {
247  // not enough memory
248  CVLog::Warning("[ccPlane::setAsTexture] Not enough memory!");
249  delete texCoords;
250  return false;
251  }
252 
253  // create default texture coordinates
254  TexCoords2D TA(0.0f, 0.0f);
255  TexCoords2D TB(0.0f, 1.0f);
256  TexCoords2D TC(1.0f, 1.0f);
257  TexCoords2D TD(1.0f, 0.0f);
258  texCoords->emplace_back(TA);
259  texCoords->emplace_back(TB);
260  texCoords->emplace_back(TC);
261  texCoords->emplace_back(TD);
262 
263  quadMesh->setTexCoordinatesTable(texCoords);
264  }
265 
266  if (!quadMesh->hasPerTriangleTexCoordIndexes()) {
267  if (!quadMesh->reservePerTriangleTexCoordIndexes()) {
268  // not enough memory
269  CVLog::Warning("[ccPlane::setAsTexture] Not enough memory!");
270  quadMesh->setTexCoordinatesTable(0);
271  quadMesh->removePerTriangleMtlIndexes();
272  return false;
273  }
274 
275  // set default texture indexes
276  quadMesh->addTriangleTexCoordIndexes(0, 2, 1);
277  quadMesh->addTriangleTexCoordIndexes(0, 3, 2);
278  }
279 
280  if (!quadMesh->hasPerTriangleMtlIndexes()) {
281  if (!quadMesh->reservePerTriangleMtlIndexes()) {
282  // not enough memory
283  CVLog::Warning("[ccPlane::setAsTexture] Not enough memory!");
284  quadMesh->setTexCoordinatesTable(0);
286  return false;
287  }
288 
289  // set default material indexes
290  quadMesh->addTriangleMtlIndex(0);
291  quadMesh->addTriangleMtlIndex(0);
292  }
293 
295  if (!quadMesh->getMaterialSet()) {
296  quadMesh->setMaterialSet(new ccMaterialSet());
297  }
298  ccMaterialSet* materialSet =
299  const_cast<ccMaterialSet*>(quadMesh->getMaterialSet());
300  assert(materialSet);
301  // remove old materials (if any)
302  materialSet->clear();
303  // add new material
304  {
305  ccMaterial::Shared material(new ccMaterial("texture"));
306  material->setTexture(image, imageFilename, false);
307  materialSet->addMaterial(material);
308  }
309 
310  quadMesh->showMaterials(true);
311 
312  return true;
313 }
constexpr double M_PI
Pi.
Definition: CVConst.h:19
Vector3Tpl< PointCoordinateType > CCVector3
Default 3D Vector.
Definition: CVGeom.h:798
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
std::shared_ptr< core::Tensor > image
std::string name
int count
void * X
Definition: SmallVector.cpp:45
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Definition: CVLog.cpp:143
Array of 2D texture coordinates.
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:36
Type y
Definition: CVGeom.h:36
Type dot(const Vector3Tpl &v) const
Dot product.
Definition: CVGeom.h:408
bool reserveSafe(size_t count)
Reserves memory (no exception thrown)
Definition: ecvArray.h:56
void addElement(const Type &value)
Definition: ecvArray.h:105
Bounding box structure.
Definition: ecvBBox.h:25
Vector3Tpl< T > getTranslationAsVec3D() const
Returns a copy of the translation as a CCVector3.
void applyRotation(Vector3Tpl< float > &vec) const
Applies rotation only to a 3D vector (in place) - float version.
void initFromParameters(T alpha_rad, const Vector3Tpl< T > &axis3D, const Vector3Tpl< T > &t3D)
Inits transformation from a rotation axis, an angle and a translation.
Float version of ccGLMatrixTpl.
Definition: ecvGLMatrix.h:19
virtual void showMaterials(bool state)
Sets whether textures should be displayed or not.
Generic primitive interface.
bool init(unsigned vertCount, bool vertNormals, unsigned faceCount, unsigned faceNormCount)
Inits internal structures.
virtual bool updateRepresentation()
Updates internal representation (as a mesh)
ccGenericPrimitive * finishCloneJob(ccGenericPrimitive *primitive) const
Finished 'clone' job (vertices color, etc.)
ccPointCloud * vertices()
Returns vertices.
bool toFile_MeOnly(QFile &out, short dataVersion) const override
Save own object data.
bool fromFile_MeOnly(QFile &in, short dataVersion, int flags, LoadedIDMap &oldToNewIDMap) override
Loads own object data.
ccGLMatrix m_transformation
Associated transformation (applied to vertices)
short minimumFileVersion_MeOnly() const override
Mesh (triangle) material.
int addMaterial(ccMaterial::CShared mat, bool allowDuplicateNames=false)
Adds a material.
Mesh (triangle) material.
Definition: ecvMaterial.h:28
QSharedPointer< ccMaterial > Shared
Shared type.
Definition: ecvMaterial.h:33
Triangular mesh.
Definition: ecvMesh.h:35
const ccMaterialSet * getMaterialSet() const override
Definition: ecvMesh.h:412
TextureCoordsContainer * getTexCoordinatesTable() const override
Returns per-triangle texture coordinates array.
Definition: ecvMesh.h:476
void drawMeOnly(CC_DRAW_CONTEXT &context) override
Enables (OpenGL) stipple mask.
Definition: ecvMesh.cpp:2635
bool reservePerTriangleMtlIndexes()
Reserves memory to store per-triangle material index.
Definition: ecvMesh.cpp:3734
virtual unsigned size() const override
Returns the number of triangles.
Definition: ecvMesh.cpp:2143
void addTriangleMtlIndex(int mtlIndex)
Adds triangle material index for next triangle.
Definition: ecvMesh.cpp:3751
void setMaterialSet(ccMaterialSet *materialSet, bool autoReleaseOldMaterialSet=true)
Sets associated material set (may be shared)
Definition: ecvMesh.cpp:492
ccGenericPointCloud * getAssociatedCloud() const override
Returns the vertices cloud.
Definition: ecvMesh.h:143
void addTriangleTexCoordIndexes(int i1, int i2, int i3)
Adds a triplet of tex coords indexes for next triangle.
Definition: ecvMesh.cpp:3678
NormsIndexesTableType * m_triNormals
Per-triangle normals.
Definition: ecvMesh.h:1493
void addTriangle(unsigned i1, unsigned i2, unsigned i3)
Adds a triangle to the mesh.
Definition: ecvMesh.cpp:2428
void removePerTriangleTexCoordIndexes()
Remove per-triangle tex coords indexes.
Definition: ecvMesh.cpp:3671
bool hasPerTriangleTexCoordIndexes() const override
Returns whether this mesh as per-triangle triplets of tex coords indexes.
Definition: ecvMesh.h:484
void setTexCoordinatesTable(TextureCoordsContainer *texCoordsTable, bool autoReleaseOldTable=true)
Sets per-triangle texture coordinates array (may be shared)
Definition: ecvMesh.cpp:3598
void addTriangleNormalIndexes(int i1, int i2, int i3)
Adds a triplet of normal indexes for next triangle.
Definition: ecvMesh.cpp:3340
bool reservePerTriangleTexCoordIndexes()
Reserves memory to store per-triangle triplets of tex coords indexes.
Definition: ecvMesh.cpp:3659
void removePerTriangleMtlIndexes()
Removes any per-triangle material indexes.
Definition: ecvMesh.cpp:3746
bool hasPerTriangleMtlIndexes() const
Returns whether this mesh as per-triangle material index.
Definition: ecvMesh.h:421
static CompressedNormType GetNormIndex(const PointCoordinateType N[])
Returns the compressed index corresponding to a normal vector.
virtual QString getName() const
Returns object name.
Definition: ecvObject.h:72
void setMetaData(const QString &key, const QVariant &data)
Sets a meta-data element.
Definition: ecvObject.cpp:216
Interface for a planar entity.
void glDrawNormal(CC_DRAW_CONTEXT &context, const CCVector3 &pos, float scale, const ecvColor::Rgb *color=0)
Draws a normal vector (OpenGL)
Plane (primitive)
Definition: ecvPlane.h:18
PointCoordinateType m_PlaneEquation[4]
Definition: ecvPlane.h:131
virtual void drawMeOnly(CC_DRAW_CONTEXT &context) override
Enables (OpenGL) stipple mask.
Definition: ecvPlane.cpp:70
bool fromFile_MeOnly(QFile &in, short dataVersion, int flags, LoadedIDMap &oldToNewIDMap) override
Loads own object data.
Definition: ecvPlane.cpp:201
PointCoordinateType m_yWidth
Width along 'Y' dimension.
Definition: ecvPlane.h:128
CCVector3 getCenter() const
Returns the center.
Definition: ecvPlane.h:56
CCVector3 getNormal() const override
Returns the entity normal.
Definition: ecvPlane.h:73
virtual bool buildUp() override
Builds primitive.
Definition: ecvPlane.cpp:31
virtual ccGenericPrimitive * clone() const override
Clones primitive.
Definition: ecvPlane.cpp:65
const PointCoordinateType * getEquation()
Returns the equation of the plane.
Definition: ecvPlane.cpp:89
ccPlane(PointCoordinateType xWidth, PointCoordinateType yWidth, const ccGLMatrix *transMat=nullptr, QString name=QString("Plane"))
Default constructor.
Definition: ecvPlane.cpp:17
void flip()
Flips the plane.
Definition: ecvPlane.cpp:99
static ccPlane * Fit(cloudViewer::GenericIndexedCloudPersist *cloud, double *rms=0)
Fits a plane primitive on a cloud.
Definition: ecvPlane.cpp:108
bool setAsTexture(QImage image, QString imageFilename=QString())
Sets an image as texture.
Definition: ecvPlane.cpp:223
static bool SetQuadTexture(ccMesh *quadMesh, QImage image, QString imageFilename=QString())
Sets an image as texture for a quad mesh.
Definition: ecvPlane.cpp:227
PointCoordinateType m_xWidth
Width along 'X' dimension.
Definition: ecvPlane.h:125
bool toFile_MeOnly(QFile &out, short dataVersion) const override
Save own object data.
Definition: ecvPlane.cpp:179
short minimumFileVersion_MeOnly() const override
Definition: ecvPlane.cpp:196
virtual ccBBox getOwnFitBB(ccGLMatrix &trans) override
Returns best-fit bounding-box (if available)
Definition: ecvPlane.cpp:217
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
QMultiMap< unsigned, unsigned > LoadedIDMap
Map of loaded unique IDs (old ID --> new ID)
static void CoordsFromDataStream(QDataStream &stream, int flags, PointCoordinateType *out, unsigned count=1)
static ScalarType computeCloud2PlaneDistanceRMS(GenericCloud *cloud, const PointCoordinateType *planeEquation)
Computes the Root Mean Square (RMS) distance between a cloud and a plane.
virtual void placeIteratorAtBeginning()=0
Sets the cloud iterator at the beginning.
virtual const CCVector3 * getNextPoint()=0
Returns the next point (relatively to the global iterator position)
virtual unsigned size() const =0
Returns the number of points.
A generic 3D point cloud with index-based and presistent access to points.
const PointCoordinateType * getLSPlane()
Returns best interpolating plane equation (Least-square)
const CCVector3 * getGravityCenter()
Returns gravity center.
const CCVector3 * getLSPlaneX()
Returns best interpolating plane (Least-square) 'X' base vector.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
#define MACRO_Draw3D(context)
ImGuiContext * context
Definition: Window.cpp:76
bool LessThanEpsilon(float x)
Test a floating point number against our epsilon (a very small number).
Definition: CVMath.h:23
static const double TD
2D texture coordinates
Display context.