2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU Lesser General Public License as
4 * published by the Free Software Foundation, either version 3 of the
5 * License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * @author Bertrand Kerautret (\c kerautre@loria.fr )
20 * LORIA (CNRS, UMR 7503), University of Nancy, France
24 * Implementation of inline methods defined in Mesh.h
26 * This file is part of the DGtal library.
30 //////////////////////////////////////////////////////////////////////////////
33 #include <boost/bind.hpp>
34 #include <DGtal/kernel/BasicPointPredicates.h>
35 //////////////////////////////////////////////////////////////////////////////
37 ///////////////////////////////////////////////////////////////////////////////
38 // IMPLEMENTATION of inline methods.
39 ///////////////////////////////////////////////////////////////////////////////
41 ///////////////////////////////////////////////////////////////////////////////
42 // ----------------------- Standard services ------------------------------
48 template <typename TPoint>
50 DGtal::Mesh<TPoint>::Mesh(bool saveFaceColor)
52 mySaveFaceColor=saveFaceColor;
53 myDefaultColor = DGtal::Color::White;
59 template <typename TPoint>
61 DGtal::Mesh<TPoint>::Mesh(const DGtal::Color &aColor)
63 mySaveFaceColor=false;
64 myDefaultColor = aColor;
70 template <typename TPoint>
72 DGtal::Mesh<TPoint>::~Mesh()
77 template <typename TPoint>
79 DGtal::Mesh<TPoint>::Mesh ( const Mesh & other ): myFaceList(other.myFaceList),
80 myVertexList(other.myVertexList),
81 myFaceColorList(other.myFaceColorList),
82 mySaveFaceColor(other.mySaveFaceColor),
83 myDefaultColor(other.myDefaultColor)
88 template <typename TPoint>
91 DGtal::Mesh<TPoint>::operator= ( const Mesh & other )
93 myFaceList = other.myFaceList;
94 myVertexList = other.myVertexList;
95 myFaceColorList = other.myFaceColorList;
96 mySaveFaceColor = other.mySaveFaceColor;
97 myDefaultColor = other. myDefaultColor;
102 ///////////////////////////////////////////////////////////////////////////////
103 // Interface - public :
106 * Writes/Displays the object on an output stream.
107 * @param out the output stream where the object is written.
109 template <typename TPoint>
112 DGtal::Mesh<TPoint>::selfDisplay ( std::ostream & out ) const
118 * Checks the validity/consistency of the object.
119 * @return 'true' if the object is valid, 'false' otherwise.
121 template <typename TPoint>
124 DGtal::Mesh<TPoint>::isValid() const
132 ///////////////////////////////////////////////////////////////////////////////
133 // Implementation of inline functions //
141 template<typename TPoint>
143 DGtal::Mesh<TPoint>::Mesh(const VertexStorage &vertexSet)
145 mySaveFaceColor=false;
146 for(int i =0; i< vertexSet.size(); i++)
148 myVertexList.push_back(vertexSet.at(i));
155 template<typename TPoint>
158 DGtal::Mesh<TPoint>::addVertex(const TPoint &point)
160 myVertexList.push_back(point);
165 template<typename TPoint>
168 DGtal::Mesh<TPoint>::addTriangularFace(unsigned int indexVertex1, unsigned int indexVertex2,
169 unsigned int indexVertex3, const DGtal::Color &aColor)
172 aFace.push_back(indexVertex1);
173 aFace.push_back(indexVertex2);
174 aFace.push_back(indexVertex3);
175 myFaceList.push_back(aFace);
178 myFaceColorList.push_back(aColor);
185 template<typename TPoint>
188 DGtal::Mesh<TPoint>::addQuadFace(unsigned int indexVertex1, unsigned int indexVertex2,
189 unsigned int indexVertex3, unsigned int indexVertex4,
190 const DGtal::Color &aColor)
193 aFace.push_back(indexVertex1);
194 aFace.push_back(indexVertex2);
195 aFace.push_back(indexVertex3);
196 aFace.push_back(indexVertex4);
197 myFaceList.push_back(aFace);
200 myFaceColorList.push_back(aColor);
206 template<typename TPoint>
209 DGtal::Mesh<TPoint>::addFace(const MeshFace &aFace, const DGtal::Color &aColor){
210 myFaceList.push_back(aFace);
213 myFaceColorList.push_back(aColor);
219 template<typename TPoint>
222 DGtal::Mesh<TPoint>::removeFaces(const std::vector<unsigned int> &facesIndex){
223 DGtal::Mesh<TPoint> newMesh(true);
224 std::vector<unsigned int> indexVertexFaceCard(nbVertex());
225 std::vector<bool> indexFaceOK(nbFaces());
226 std::fill(indexVertexFaceCard.begin(), indexVertexFaceCard.end(), 0);
227 std::fill(indexFaceOK.begin(), indexFaceOK.end(), true);
228 for (unsigned int i = 0; i<facesIndex.size(); i++){
229 indexFaceOK[facesIndex[i]]=false;
231 // for each face remaining in the mesh we add +1 to each vertex used in a face
232 for(unsigned int i = 0; i < nbFaces(); i++){
233 if( indexFaceOK[i] ){
234 DGtal::Mesh<TPoint>::MeshFace aFace = getFace(i);
235 for (unsigned int j=0; j< aFace.size() ; j++) {
236 indexVertexFaceCard[aFace[j]] += 1;
240 // we remove all vertex with a face == 0 and compute the new vertex association:
241 std::vector<unsigned int> newVertexIndex;
242 unsigned int currentIndex=0;
243 for (unsigned int i=0; i< nbVertex(); i++) {
244 if (indexVertexFaceCard[i]!=0){
245 newMesh.addVertex(getVertex(i));
246 newVertexIndex.push_back(currentIndex);
249 newVertexIndex.push_back(0);
252 for (unsigned int i = 0; i < nbFaces(); i++) {
254 MeshFace aFace = getFace(i);
255 MeshFace aNewFace = aFace;
256 // translate the old face with new index:
257 for (unsigned int j=0; j< aFace.size() ; j++) {
258 aNewFace[j] = newVertexIndex[aFace[j]];
260 newMesh.addFace(aNewFace);
261 newMesh.setFaceColor(newMesh.nbFaces()-1, getFaceColor(i));
264 myFaceList = newMesh.myFaceList;
265 myVertexList = newMesh.myVertexList;
266 myFaceColorList = newMesh.myFaceColorList;
273 template<typename TPoint>
276 DGtal::Mesh<TPoint>::getVertex(unsigned int i) const
278 return myVertexList.at(i);
283 template<typename TPoint>
286 DGtal::Mesh<TPoint>::getVertex(unsigned int i)
288 return myVertexList.at(i);
293 template<typename TPoint>
295 const typename DGtal::Mesh<TPoint>::MeshFace &
296 DGtal::Mesh<TPoint>::getFace(unsigned int i) const
298 return myFaceList.at(i);
302 template<typename TPoint>
304 typename DGtal::Mesh<TPoint>::MeshFace &
305 DGtal::Mesh<TPoint>::getFace(unsigned int i)
307 return myFaceList.at(i);
311 template<typename TPoint>
313 typename DGtal::Mesh<TPoint>::RealPoint
314 DGtal::Mesh<TPoint>::getFaceBarycenter(unsigned int i) const
316 DGtal::Mesh<TPoint>::RealPoint c;
317 MeshFace aFace = getFace(i);
318 for ( auto &j: aFace){
319 TPoint p = getVertex(j);
320 for (typename TPoint::Dimension k = 0; k < TPoint::dimension; k++){
321 c[k] += static_cast<typename RealPoint::Component>(p[k]) ;
324 return c/static_cast<typename RealPoint::Component>(aFace.size());
328 template<typename TPoint>
331 DGtal::Mesh<TPoint>::nbFaces() const
333 return myFaceList.size();
336 template<typename TPoint>
339 DGtal::Mesh<TPoint>::nbVertex() const
341 return myVertexList.size();
345 template<typename TPoint>
348 DGtal::Mesh<TPoint>::getFaceColor(unsigned int i) const
352 return myFaceColorList.at(i);
356 return myDefaultColor;
360 template <typename TPoint>
361 struct MeshBoundingBoxCompPoints
363 MeshBoundingBoxCompPoints(typename TPoint::Dimension d): myDim(d){};
364 bool operator() (const TPoint &p1, const TPoint &p2){return p1[myDim]<p2[myDim];};
365 typename TPoint::Dimension myDim;
368 template<typename TPoint>
370 std::pair<TPoint, TPoint>
371 DGtal::Mesh<TPoint>::getBoundingBox() const
373 std::pair<TPoint, TPoint> theResult;
374 TPoint lowerBound, upperBound;
375 for(unsigned int i=0; i< TPoint::size(); i++)
377 const MeshBoundingBoxCompPoints<TPoint> cmp_points(i);
378 upperBound[i] = (*(std::max_element(vertexBegin(), vertexEnd(), cmp_points)))[i];
379 lowerBound[i] = (*(std::min_element(vertexBegin(), vertexEnd(), cmp_points)))[i];
381 theResult.first = lowerBound ;
382 theResult.second = upperBound ;
387 template<typename TPoint>
390 DGtal::Mesh<TPoint>::setFaceColor(const unsigned int index,
391 const DGtal::Color &aColor)
393 if (!mySaveFaceColor)
395 for(unsigned int i = 0; i<myFaceList.size(); i++)
397 myFaceColorList.push_back(myDefaultColor);
399 mySaveFaceColor=true;
401 myFaceColorList.at(index) = aColor;
405 template<typename TPoint>
408 DGtal::Mesh<TPoint>::isStoringFaceColors() const
410 return mySaveFaceColor;
416 template<typename TPoint>
419 DGtal::Mesh<TPoint>::invertVertexFaceOrder(){
420 for(unsigned int i=0; i<myFaceList.size(); i++)
422 std::vector<unsigned int> & aFace = myFaceList.at(i);
423 for(unsigned int j=0; j < aFace.size()/2; j++)
425 unsigned int tmp=aFace.at(j);
426 aFace.at(j)=aFace.at(aFace.size()-1-j);
427 aFace.at(aFace.size()-1-j)=tmp;
432 template<typename TPoint>
435 DGtal::Mesh<TPoint>::clearFaces(){
439 template<typename TPoint>
442 DGtal::Mesh<TPoint>::changeScale(const double aScale){
443 for(typename VertexStorage::iterator it = vertexBegin(); it != vertexEnd(); it++)
450 template<typename TPoint>
453 DGtal::Mesh<TPoint>::subDivideTriangularFaces(const double minArea){
455 std::vector<Mesh<TPoint>::MeshFace> facesToAdd;
456 for(unsigned int i =0; i< nbFaces(); i++)
458 typename Mesh<TPoint>::MeshFace aFace = getFace(i);
461 TPoint p1 = getVertex(aFace[0]);
462 TPoint p2 = getVertex(aFace[1]);
463 TPoint p3 = getVertex(aFace[2]);
464 TPoint c = (p1+p2+p3)/3.0;
465 double a = ((p2-p1).crossProduct(p3-p1)).norm()/2.0;
475 f1.push_back(aFace[0]);
476 f1.push_back(aFace[1]);
477 f1.push_back(nbVertex()-1);
478 facesToAdd.push_back(f1);
480 f2.push_back(aFace[1]);
481 f2.push_back(aFace[2]);
482 f2.push_back(nbVertex()-1);
483 facesToAdd.push_back(f2);
485 f3.push_back(aFace[2]);
486 f3.push_back(aFace[0]);
487 f3.push_back(nbVertex()-1);
488 facesToAdd.push_back(f3);
492 facesToAdd.push_back(aFace);
498 for(unsigned i=0; i<facesToAdd.size(); i++)
500 addFace(facesToAdd[i]);
507 template<typename TPoint>
510 DGtal::Mesh<TPoint>::quadToTriangularFaces(){
511 unsigned int nbQuadT=0;
512 std::vector<Mesh<TPoint>::MeshFace> facesToAdd;
513 for(unsigned int i =0; i< nbFaces(); i++)
515 typename Mesh<TPoint>::MeshFace aFace = getFace(i);
519 f1.push_back(aFace[0]);
520 f1.push_back(aFace[1]);
521 f1.push_back(aFace[2]);
522 facesToAdd.push_back(f1);
524 f2.push_back(aFace[2]);
525 f2.push_back(aFace[3]);
526 f2.push_back(aFace[0]);
527 facesToAdd.push_back(f2);
532 facesToAdd.push_back(aFace);
536 for(unsigned i=0; i<facesToAdd.size(); i++)
538 addFace(facesToAdd[i]);
546 //------------------------------------------------------------------------------
547 template<typename TPoint>
550 DGtal::Mesh<TPoint>::className() const
560 template <typename TPoint>
563 DGtal::Mesh<TPoint>::createTubularMesh(DGtal::Mesh<TPoint> &aMesh, const std::vector<TPoint> &aSkeleton,
564 const double aRadius,
565 const double angleStep, const DGtal::Color &aMeshColor)
567 std::vector<double> aVecR;
568 aVecR.push_back(aRadius);
569 DGtal::Mesh<TPoint>::createTubularMesh(aMesh, aSkeleton,
570 aVecR, angleStep, aMeshColor);
575 template <typename TPoint>
578 DGtal::Mesh<TPoint>::createTubularMesh(DGtal::Mesh<TPoint> &aMesh, const std::vector<TPoint> &aSkeleton,
579 const std::vector<double> &aVectRadius,
580 const double angleStep, const DGtal::Color &aMeshColor)
582 unsigned int nbVertexInitial = aMesh.nbVertex();
583 ASSERT(aVectRadius.size() > 0);
584 // Generating vertices..
585 for(unsigned int i = 0; i< aSkeleton.size(); i++)
588 TPoint uDir1, uDirPrec;
592 if(i != aSkeleton.size()-1)
594 vectDir = aSkeleton.at(i+1) - aSkeleton.at(i);
598 vectDir = aSkeleton.at(i) - aSkeleton.at(i-1);
601 double d = -vectDir[0]* aSkeleton.at(i)[0] - vectDir[1]*aSkeleton.at(i)[1]
602 - vectDir[2]*aSkeleton.at(i)[2];
606 pRefOrigin [0]= -d/vectDir[0];
609 if(aSkeleton.at(i) == pRefOrigin ||
610 (vectDir[1]==0 && vectDir[2]==0))
616 else if (vectDir[1]!=0)
619 pRefOrigin [1]= -d/vectDir[1];
621 if(aSkeleton.at(i) == pRefOrigin ||
622 (vectDir[0]==0 && vectDir[2]==0))
626 }else if (vectDir[2]!=0)
630 pRefOrigin [2]= -d/vectDir[2];
631 if(aSkeleton.at(i) == pRefOrigin ||
632 (vectDir[0]==0 && vectDir[1]==0))
637 uDir1=(pRefOrigin-aSkeleton.at(i))/((pRefOrigin-aSkeleton.at(i)).norm());
638 uDir2[0] = uDir1[1]*vectDir[2]-uDir1[2]*vectDir[1];
639 uDir2[1] = uDir1[2]*vectDir[0]-uDir1[0]*vectDir[2];
640 uDir2[2] = uDir1[0]*vectDir[1]-uDir1[1]*vectDir[0];
642 for(double a = 0.0; a < 2.0*M_PI; a += angleStep)
644 TPoint vMove = aVectRadius.at(i%aVectRadius.size())*(uDir1*cos(a) + uDir2*sin(a));
645 aMesh.addVertex(vMove + aSkeleton[i]);
648 firstPoint = vMove + aSkeleton[i]+vectDir;
653 unsigned int nbPtPerFaces = (aMesh.nbVertex()-nbVertexInitial)/aSkeleton.size();
655 // Generating faces...
656 for(unsigned int i = 0; i< aSkeleton.size()-1; i++)
658 if (aSkeleton.at(i)==aSkeleton.at(i+1)){
659 trace.warning() << "Two skeleton points are identical, ignoring one point." << std::endl;
662 // Computing best shift between two consecutive ring points to generate tube face.
663 // (criteria defined by the minimal distance between 4 sampling points)
664 double minDistance = std::numeric_limits<double>::max();
665 TPoint ptRefRing1 = aMesh.getVertex(nbVertexInitial+i*nbPtPerFaces);
666 TPoint ptRefRing2 = aMesh.getVertex(nbVertexInitial+i*nbPtPerFaces+nbPtPerFaces/4);
667 TPoint ptRefRing3 = aMesh.getVertex(nbVertexInitial+i*nbPtPerFaces+2*(nbPtPerFaces/4));
668 TPoint ptRefRing4 = aMesh.getVertex(nbVertexInitial+i*nbPtPerFaces+3*(nbPtPerFaces/4));
670 unsigned int shift = 0;
672 if(i != aSkeleton.size()-1)
674 vectDir = aSkeleton.at(i+1) - aSkeleton.at(i);
678 vectDir = aSkeleton.at(i) - aSkeleton.at(i-1);
681 for(unsigned int k=0; k<nbPtPerFaces; k++)
683 TPoint pScan1 = aMesh.getVertex(nbVertexInitial+(i+1)*nbPtPerFaces+k);
684 TPoint pScan2 = aMesh.getVertex(nbVertexInitial+(i+1)*nbPtPerFaces+
685 (nbPtPerFaces/4+k)%nbPtPerFaces);
686 TPoint pScan3 = aMesh.getVertex(nbVertexInitial+(i+1)*nbPtPerFaces+
687 (2*(nbPtPerFaces/4)+k)%nbPtPerFaces);
688 TPoint pScan4 = aMesh.getVertex(nbVertexInitial+(i+1)*nbPtPerFaces+
689 (3*(nbPtPerFaces/4)+k)%nbPtPerFaces);
690 double distance = (ptRefRing1 - pScan1).norm()+(ptRefRing2 - pScan2).norm()+
691 (ptRefRing3 - pScan3).norm()+(ptRefRing4 - pScan4).norm();
692 if(distance<minDistance){
694 minDistance = distance;
698 for(unsigned int k=0; k<nbPtPerFaces; k++)
700 Mesh<TPoint>::MeshFace aFace;
701 aMesh.addQuadFace(nbVertexInitial+k+i*nbPtPerFaces,
702 nbVertexInitial+(shift+k)%nbPtPerFaces+nbPtPerFaces*(i+1),
703 nbVertexInitial+(shift+k+1)%nbPtPerFaces+nbPtPerFaces*(i+1),
704 nbVertexInitial+(k+1)%nbPtPerFaces+i*nbPtPerFaces,
714 template <typename TPoint>
715 template <typename TValue>
718 DGtal::Mesh<TPoint>::createMeshFromHeightSequence(Mesh<TPoint> &aMesh, const std::vector<TValue> & anValueSequence,
719 const unsigned int lengthSequence,
720 double stepX, double stepY, double stepZ,
721 const DGtal::Color &aMeshColor ){
722 unsigned int nbVertexInitial = aMesh.nbVertex();
723 // Generating vertices..
725 unsigned int posY = 0;
726 while(i+lengthSequence-1 < anValueSequence.size()){
727 for(unsigned int j = 0; j < lengthSequence; j++, i++){
728 aMesh.addVertex(TPoint(j*stepX, posY*stepY, stepZ*anValueSequence.at(i)));
732 // Generating faces...
734 while(i+lengthSequence-1 < anValueSequence.size() - lengthSequence){
735 for(unsigned int j = 0; j < lengthSequence-1; j++, i++){
736 aMesh.addQuadFace(nbVertexInitial+i, nbVertexInitial+i+1,
737 nbVertexInitial+i+1+lengthSequence,
738 nbVertexInitial+i+lengthSequence,
749 template <typename TPoint>
752 DGtal::operator<< ( std::ostream & out,
753 const Mesh<TPoint> & object )
755 object.selfDisplay( out );
764 ///////////////////////////////////////////////////////////////////////////////