1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
|
//##########################################################################
//# #
//# CLOUDCOMPARE #
//# #
//# This program is free software; you can redistribute it and/or modify #
//# it under the terms of the GNU General Public License as published by #
//# the Free Software Foundation; version 2 or later of the License. #
//# #
//# This program is distributed in the hope that it will be useful, #
//# but WITHOUT ANY WARRANTY; without even the implied warranty of #
//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
//# GNU General Public License for more details. #
//# #
//# COPYRIGHT: EDF R&D / TELECOM ParisTech (ENST-TSI) #
//# #
//##########################################################################
#ifndef CC_MESH_HEADER
#define CC_MESH_HEADER
//CCLib
#include <PointProjectionTools.h>
#include <SimpleTriangle.h>
//Local
#include "ccGenericMesh.h"
class ccProgressDialog;
class ccPolyline;
//! Triangular mesh
class QCC_DB_LIB_API ccMesh : public ccGenericMesh
{
public:
//! Default ccMesh constructor
/** \param vertices the vertices cloud
**/
explicit ccMesh(ccGenericPointCloud* vertices);
//! ccMesh constructor (from a CCLib::GenericIndexedMesh)
/** The GenericIndexedMesh should refer to a known ccGenericPointCloud.
\param giMesh the GenericIndexedMesh
\param giVertices giMesh vertices
**/
explicit ccMesh(CCLib::GenericIndexedMesh* giMesh, ccGenericPointCloud* giVertices);
//! Default destructor
~ccMesh() override;
//! Returns class ID
CC_CLASS_ENUM getClassID() const override { return CC_TYPES::MESH; }
//! Sets the associated vertices cloud (warning)
void setAssociatedCloud(ccGenericPointCloud* cloud);
//! Clones this entity
/** All the main features of the entity are cloned, except from the octree
\param vertices vertices set to use (will be automatically - AND OPTIMALLY - cloned if 0)
\param clonedMaterials for internal use
\param clonedNormsTable for internal use
\param cloneTexCoords for internal use
\return a copy of this entity
**/
ccMesh* cloneMesh( ccGenericPointCloud* vertices = nullptr,
ccMaterialSet* clonedMaterials = nullptr,
NormsIndexesTableType* clonedNormsTable = nullptr,
TextureCoordsContainer* cloneTexCoords = nullptr);
//! Creates a Delaunay 2.5D mesh from a point cloud
/** See CCLib::PointProjectionTools::computeTriangulation.
**/
static ccMesh* Triangulate( ccGenericPointCloud* cloud,
CC_TRIANGULATION_TYPES type,
bool updateNormals = false,
PointCoordinateType maxEdgeLength = 0,
unsigned char dim = 2);
//! Creates a Delaunay 2.5D mesh from two polylines
static ccMesh* TriangulateTwoPolylines(ccPolyline* p1, ccPolyline* p2, CCVector3* projectionDir = nullptr);
//! Merges another mesh into this one
/** \param mesh mesh to be merged in this one
\param createSubMesh whether to create a submesh entity corresponding to the added mesh
\return success
**/
bool merge(const ccMesh* mesh, bool createSubMesh);
//inherited methods (ccHObject)
unsigned getUniqueIDForDisplay() const override;
ccBBox getOwnBB(bool withGLFeatures = false) override;
bool isSerializable() const override { return true; }
const ccGLMatrix& getGLTransformationHistory() const override;
//inherited methods (ccGenericMesh)
inline ccGenericPointCloud* getAssociatedCloud() const override { return m_associatedCloud; }
void refreshBB() override;
bool interpolateNormals(unsigned triIndex, const CCVector3& P, CCVector3& N) override;
bool interpolateColors(unsigned triIndex, const CCVector3& P, ccColor::Rgb& C) override;
void computeInterpolationWeights(unsigned triIndex, const CCVector3& P, CCVector3d& weights) const override;
bool getColorFromMaterial(unsigned triIndex, const CCVector3& P, ccColor::Rgb& C, bool interpolateColorIfNoTexture) override;
bool getVertexColorFromMaterial(unsigned triIndex, unsigned char vertIndex, ccColor::Rgb& C, bool returnColorIfNoTexture) override;
unsigned capacity() const override;
//inherited methods (GenericIndexedMesh)
void forEach(genericTriangleAction action) override;
void placeIteratorAtBeginning() override;
CCLib::GenericTriangle* _getNextTriangle() override; //temporary
CCLib::GenericTriangle* _getTriangle(unsigned triangleIndex) override; //temporary
CCLib::VerticesIndexes* getNextTriangleVertIndexes() override;
CCLib::VerticesIndexes* getTriangleVertIndexes(unsigned triangleIndex) override;
void getTriangleVertices(unsigned triangleIndex, CCVector3& A, CCVector3& B, CCVector3& C) const override;
unsigned size() const override;
void getBoundingBox(CCVector3& bbMin, CCVector3& bbMax) override;
//const version of getTriangleVertIndexes
const virtual CCLib::VerticesIndexes* getTriangleVertIndexes(unsigned triangleIndex) const;
//inherited methods (ccDrawableObject)
bool hasColors() const override;
bool hasNormals() const override;
bool hasScalarFields() const override;
bool hasDisplayedScalarField() const override;
bool normalsShown() const override;
void toggleMaterials() override { showMaterials(!materialsShown()); }
//! Shifts all triangles indexes
/** \param shift index shift (positive)
**/
void shiftTriangleIndexes(unsigned shift);
//! Adds a triangle to the mesh
/** \warning Bounding-box validity is broken after a call to this method.
However, for the sake of performance, no call to notifyGeometryUpdate
is made automatically. Make sure to do so when all modifications are done!
\param i1 first vertex index (relatively to the vertex cloud)
\param i2 second vertex index (relatively to the vertex cloud)
\param i3 third vertex index (relatively to the vertex cloud)
**/
void addTriangle(unsigned i1, unsigned i2, unsigned i3);
//! Reserves the memory to store the vertex indexes (3 per triangle)
/** \param n the number of triangles to reserve
\return true if the method succeeds, false otherwise
**/
bool reserve(size_t n);
//! Resizes the array of vertex indexes (3 per triangle)
/** If the new number of elements is smaller than the actual size,
the overflooding elements will be deleted.
\param n the new number of triangles
\return true if the method succeeds, false otherwise
**/
bool resize(size_t n);
//! Removes unused capacity
inline void shrinkToFit() { if (size() < capacity()) resize(size()); }
/*********************************************************/
/************** PER-TRIANGLE NORMALS ***************/
/*********************************************************/
//inherited from ccGenericMesh
bool hasTriNormals() const override;
void getTriangleNormalIndexes(unsigned triangleIndex, int& i1, int& i2, int& i3) const override;
bool getTriangleNormals(unsigned triangleIndex, CCVector3& Na, CCVector3& Nb, CCVector3& Nc) const override;
NormsIndexesTableType* getTriNormsTable() const override { return m_triNormals; }
//! Sets per-triangle normals array (may be shared)
void setTriNormsTable(NormsIndexesTableType* triNormsTable, bool autoReleaseOldTable = true);
//! Removes per-triangle normals
void clearTriNormals() { setTriNormsTable(nullptr); }
//! Returns whether per triangle normals are enabled
/** To enable per triangle normals, you should:
- first, reserve memory for triangles (this is always the first thing to do)
- associate this mesh to a triangle normals array (see ccMesh::setTriNormsTable)
- reserve memory to store per-triangle normal indexes with ccMesh::reservePerTriangleNormalIndexes
- add for each triangle a triplet of indexes (referring to stored normals)
**/
bool arePerTriangleNormalsEnabled() const;
//! Reserves memory to store per-triangle triplets of normal indexes
/** Before adding per-triangle normal indexes triplets to
the mesh (with ccMesh::addTriangleNormalsIndexes()) be
sure to reserve the necessary amount of memory with
this method. This method reserves memory for as many
normals indexes triplets as the number of triangles
in the mesh (effictively stored or reserved - a call to
ccMesh::reserve prior to this one is mandatory).
\return true if ok, false if there's not enough memory
**/
bool reservePerTriangleNormalIndexes();
//! Adds a triplet of normal indexes for next triangle
/** Make sure per-triangle normal indexes array is allocated
(see reservePerTriangleNormalIndexes)
\param i1 first vertex normal index
\param i2 second vertex normal index
\param i3 third vertex normal index
**/
void addTriangleNormalIndexes(int i1, int i2, int i3);
//! Sets a triplet of normal indexes for a given triangle
/** \param triangleIndex triangle index
\param i1 first vertex normal index
\param i2 second vertex normal index
\param i3 third vertex normal index
**/
void setTriangleNormalIndexes(unsigned triangleIndex, int i1, int i2, int i3);
//! Removes any per-triangle triplets of normal indexes
void removePerTriangleNormalIndexes();
/********************************************************/
/************ PER-TRIANGLE MATERIAL ***************/
/********************************************************/
//inherited from ccGenericMesh
bool hasMaterials() const override;
const ccMaterialSet* getMaterialSet() const override { return m_materials; }
int getTriangleMtlIndex(unsigned triangleIndex) const override;
//! Converts materials to vertex colors
/** Warning: this method will overwrite colors (if any)
**/
bool convertMaterialsToVertexColors();
//! Returns whether this mesh as per-triangle material index
bool hasPerTriangleMtlIndexes() const { return m_triMtlIndexes && m_triMtlIndexes->isAllocated(); }
//! Reserves memory to store per-triangle material index
/** Before adding per-triangle material index to
the mesh (with ccMesh::addTriangleMtlIndex()) be sure
to reserve the necessary amount of memory with this
method. This method reserves memory for as many
material descriptors as the number of triangles in
the mesh (effictively stored or reserved - a call to
ccMesh::reserve prior to this one is mandatory).
\return true if ok, false if there's not enough memory
**/
bool reservePerTriangleMtlIndexes();
//! Removes any per-triangle material indexes
void removePerTriangleMtlIndexes();
//! Adds triangle material index for next triangle
/** Cf. ccMesh::reservePerTriangleMtlIndexes.
\param mtlIndex triangle material index
**/
void addTriangleMtlIndex(int mtlIndex);
//! Container of per-triangle material descriptors
using triangleMaterialIndexesSet = ccArray<int, 1, int>;
//! Sets per-triangle material indexes array
void setTriangleMtlIndexesTable(triangleMaterialIndexesSet* matIndexesTable, bool autoReleaseOldTable = true);
//! Returns the per-triangle material indexes array
inline const triangleMaterialIndexesSet* getTriangleMtlIndexesTable() const { return m_triMtlIndexes; }
//! Sets triangle material indexes
/** Cf. ccMesh::reservePerTriangleMtlIndexes.
\param triangleIndex triangle index
\param mtlIndex triangle material index
**/
void setTriangleMtlIndex(unsigned triangleIndex, int mtlIndex);
//! Sets associated material set (may be shared)
void setMaterialSet(ccMaterialSet* materialSet, bool autoReleaseOldMaterialSet = true);
/******************************************************************/
/************ PER-TRIANGLE TEXTURE COORDINATE ***************/
/******************************************************************/
//inherited from ccGenericMesh
bool hasTextures() const override;
TextureCoordsContainer* getTexCoordinatesTable() const override { return m_texCoords; }
void getTriangleTexCoordinates(unsigned triIndex, TexCoords2D* &tx1, TexCoords2D* &tx2, TexCoords2D* &tx3) const override;
bool hasPerTriangleTexCoordIndexes() const override { return m_texCoordIndexes && m_texCoordIndexes->isAllocated(); }
void getTriangleTexCoordinatesIndexes(unsigned triangleIndex, int& i1, int& i2, int& i3) const override;
//! Sets per-triangle texture coordinates array (may be shared)
void setTexCoordinatesTable(TextureCoordsContainer* texCoordsTable, bool autoReleaseOldTable = true);
//! Reserves memory to store per-triangle triplets of tex coords indexes
/** Before adding per-triangle tex coords indexes triplets to
the mesh (with ccMesh::addTriangleTexCoordIndexes()) be
sure to reserve the necessary amount of memory with
this method. This method reserves memory for as many
tex coords indexes triplets as the number of triangles
in the mesh (effictively stored or reserved - a call to
ccMesh::reserve prior to this one is mandatory).
\return true if ok, false if there's not enough memory
**/
bool reservePerTriangleTexCoordIndexes();
//! Remove per-triangle tex coords indexes
void removePerTriangleTexCoordIndexes();
//! Adds a triplet of tex coords indexes for next triangle
/** Make sure per-triangle tex coords indexes array is allocated
(see reservePerTriangleTexCoordIndexes)
\param i1 first vertex tex coords index
\param i2 second vertex tex coords index
\param i3 third vertex tex coords index
**/
void addTriangleTexCoordIndexes(int i1, int i2, int i3);
//! Sets a triplet of tex coords indexes for a given triangle
/** \param triangleIndex triangle index
\param i1 first vertex tex coords index
\param i2 second vertex tex coords index
\param i3 third vertex tex coords index
**/
void setTriangleTexCoordIndexes(unsigned triangleIndex, int i1, int i2, int i3);
//! Computes normals
/** \param perVertex whether normals should be computed per-vertex or per-triangle
\return success
**/
bool computeNormals(bool perVertex);
//! Computes per-vertex normals
bool computePerVertexNormals();
//! Computes per-triangle normals
bool computePerTriangleNormals();
//! Laplacian smoothing
/** \param nbIteration smoothing iterations
\param factor smoothing 'force'
\param progressCb progress dialog callback
**/
bool laplacianSmooth( unsigned nbIteration = 100,
PointCoordinateType factor = static_cast<PointCoordinateType>(0.01),
ccProgressDialog* progressCb = nullptr);
//! Mesh scalar field processes
enum MESH_SCALAR_FIELD_PROCESS { SMOOTH_MESH_SF, /**< Smooth **/
ENHANCE_MESH_SF, /**< Enhance **/
};
//! Applies process to the mesh scalar field (the one associated to its vertices in fact)
/** A very simple smoothing/enhancement algorithm based on
each vertex direct neighbours. Prior to calling this method,
one should check first that the vertices are associated to a
scalar field.
Warning: the processed scalar field must be enabled for both
INPUT & OUTPUT! (see ccGenericCloud::setCurrentScalarField)
\param process either 'smooth' or 'enhance'
**/
bool processScalarField(MESH_SCALAR_FIELD_PROCESS process);
//! Subdivides mesh (so as to ensure that all triangles are falls below 'maxArea')
/** \return subdivided mesh (if successful)
**/
ccMesh* subdivide(PointCoordinateType maxArea) const;
//! Creates a new mesh with the selected vertices only
/** This method is called after a graphical segmentation.
It creates a new mesh structure with the vertices that are
tagged as "visible" (see ccGenericPointCloud::visibilityArray).
This method will also update this mesh if removeSelectedFaces is true.
In this case, all "selected" triangles will be removed from this mesh's instance.
\param removeSelectedFaces specifies if the faces composed only of 'selected' vertices should be removed or not
**/
ccMesh* createNewMeshFromSelection(bool removeSelectedFaces);
//! Swaps two triangles
/** Automatically updates internal structures (i.e. lookup tables for
material, normals, etc.).
**/
void swapTriangles(unsigned index1, unsigned index2);
//! Transforms the mesh per-triangle normals
void transformTriNormals(const ccGLMatrix& trans);
protected:
//inherited from ccHObject
void drawMeOnly(CC_DRAW_CONTEXT& context) override;
bool toFile_MeOnly(QFile& out) const override;
bool fromFile_MeOnly(QFile& in, short dataVersion, int flags) override;
void applyGLTransformation(const ccGLMatrix& trans) override;
void onUpdateOf(ccHObject* obj) override;
void onDeletionOf(const ccHObject* obj) override;
//! Same as other 'computeInterpolationWeights' method with a set of 3 vertices indexes
void computeInterpolationWeights(const CCLib::VerticesIndexes& vertIndexes, const CCVector3& P, CCVector3d& weights) const;
//! Same as other 'interpolateNormals' method with a set of 3 vertices indexes
bool interpolateNormals(const CCLib::VerticesIndexes& vertIndexes, const CCVector3& P, CCVector3& N, const Tuple3i* triNormIndexes = nullptr);
//! Same as other 'interpolateColors' method with a set of 3 vertices indexes
bool interpolateColors(const CCLib::VerticesIndexes& vertIndexes, const CCVector3& P, ccColor::Rgb& C);
//! Used internally by 'subdivide'
bool pushSubdivide(/*PointCoordinateType maxArea, */unsigned indexA, unsigned indexB, unsigned indexC);
/*** EXTENDED CALL SCRIPTS (FOR CC_SUB_MESHES) ***/
//0 parameter
#define ccMesh_extended_call0(baseName,recursiveName) \
inline virtual void recursiveName() \
{ \
baseName(); \
for (Container::iterator it = m_children.begin(); it != m_children.end(); ++it) \
if ((*it)->isA(CC_TYPES::SUB_MESH)) \
static_cast<ccGenericMesh*>(*it)->baseName(); \
} \
//1 parameter
#define ccMesh_extended_call1(baseName,param1Type,recursiveName) \
inline virtual void recursiveName(param1Type p) \
{ \
baseName(p); \
for (Container::iterator it = m_children.begin(); it != m_children.end(); ++it) \
if ((*it)->isA(CC_TYPES::SUB_MESH)) \
static_cast<ccGenericMesh*>(*it)->baseName(p); \
} \
//recursive equivalents of some of ccGenericMesh methods (applied to sub-meshes as well)
ccMesh_extended_call1(showNormals, bool, showNormals_extended)
//! associated cloud (vertices)
ccGenericPointCloud* m_associatedCloud;
//! Per-triangle normals
NormsIndexesTableType* m_triNormals;
//! Texture coordinates
TextureCoordsContainer* m_texCoords;
//! Materials
ccMaterialSet* m_materials;
//! Container of per-triangle vertices indexes (3)
using triangleIndexesContainer = ccArray<CCLib::VerticesIndexes, 3, unsigned>;
//! Triangles' vertices indexes (3 per triangle)
triangleIndexesContainer* m_triVertIndexes;
//! Iterator on the list of triangles
unsigned m_globalIterator;
//! Dump triangle structure to transmit temporary data
CCLib::SimpleRefTriangle m_currentTriangle;
//! Bounding-box
ccBBox m_bBox;
//! Per-triangle material indexes
triangleMaterialIndexesSet* m_triMtlIndexes;
//! Set of triplets of indexes referring to mesh texture coordinates
using triangleTexCoordIndexesSet = ccArray<Tuple3i, 3, int>;
//! Mesh tex coords indexes (per-triangle)
triangleTexCoordIndexesSet* m_texCoordIndexes;
//! Set of triplets of indexes referring to mesh normals
using triangleNormalsIndexesSet = ccArray<Tuple3i, 3, int>;
//! Mesh normals indexes (per-triangle)
triangleNormalsIndexesSet* m_triNormalIndexes;
};
#endif //CC_MESH_HEADER
|