diff --git a/.gitignore b/.gitignore
index 4f22965f..caf98bf3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,7 @@ debug/
release/
*-debug/
*-release/
+/docs/Doxygen/html/
+
+# Intermediate Files
+*.bc
\ No newline at end of file
diff --git a/apps/metro/readme.txt b/apps/metro/readme.txt
index 7fd9e060..5f2ee761 100644
--- a/apps/metro/readme.txt
+++ b/apps/metro/readme.txt
@@ -1,5 +1,5 @@
- VCGLib http://vcg.sf.net o o
+ VCGLib http://www.vcglib.net o o
Visual and Computer Graphics Library o o
_ O _
Copyright(C) 2005-2006 \/)\/
@@ -31,14 +31,10 @@ Please, when using this tool, cite the following reference:
P. Cignoni, C. Rocchini and R. Scopigno
"Metro: measuring error on simplified surfaces"
Computer Graphics Forum, Blackwell Publishers, vol. 17(2), June 1998, pp 167-174
-Available at http://vcg.sf.net
-
-You can find some sample mesh to test in the 'Metro Sample dataset' package downloadable from sourceforge.
-
For any question about this software please contact:
-Paolo Cignoni ( p.cignoni@isti.cnr.it )
+Paolo Cignoni ( paolo.cignoni@isti.cnr.it )
--- General Info ---
diff --git a/apps/tridecimator/readme.txt b/apps/tridecimator/readme.txt
index b15eca5c..900b948d 100644
--- a/apps/tridecimator/readme.txt
+++ b/apps/tridecimator/readme.txt
@@ -1,5 +1,5 @@
- VCGLib http://vcg.sf.net o o
+ VCGLib http://www.vcglib.net o o
Visual and Computer Graphics Library o o
_ O _
Copyright(C) 2005-2006 \/)\/
diff --git a/apps/tridecimator/tridecimator.cpp b/apps/tridecimator/tridecimator.cpp
index 6f4bc513..51c66bec 100644
--- a/apps/tridecimator/tridecimator.cpp
+++ b/apps/tridecimator/tridecimator.cpp
@@ -73,7 +73,6 @@ void Usage()
"---------------------------------\n"
" TriDecimator 1.0 \n"
" http://vcg.isti.cnr.it\n"
- " http://vcg.sourceforge.net\n"
" release date: " __DATE__
"\n---------------------------------\n\n"
"Copyright 2003-2016 Visual Computing Lab I.S.T.I. C.N.R.\n"
diff --git a/apps/trimeshinfo/readme.txt b/apps/trimeshinfo/readme.txt
index 9d4cb761..07f9720a 100644
--- a/apps/trimeshinfo/readme.txt
+++ b/apps/trimeshinfo/readme.txt
@@ -1,5 +1,5 @@
- VCGLib http://vcg.sf.net o o
+ VCGLib http://www.vcglib.net o o
Visual and Computer Graphics Library o o
_ O _
Copyright(C) 2004-2006 \/)\/
@@ -56,7 +56,7 @@ The application has no graphical interface but works as the "Metro" tool on comm
TriMeshInfo is written in C++ and makes use of the VCG library.
The tool supports the following file formats:
- - PLY (http://vcg.sourceforge.net/img/wiki_up/plyformat.pdf)
+ - PLY
- OFF (http://www.geomview.org/docs/html/geomview_41.html#SEC44)
- STL (http://astronomy.swin.edu.au/~pbourke/dataformats/stl/)
- OBJ (http://www.eg-models.de/formats/Format_Obj.html)
diff --git a/apps/trimeshinfo/trimeshinfo1.01/trimeshinfo101/readme.txt b/apps/trimeshinfo/trimeshinfo1.01/trimeshinfo101/readme.txt
index 89d28e3c..e2f349c1 100644
--- a/apps/trimeshinfo/trimeshinfo1.01/trimeshinfo101/readme.txt
+++ b/apps/trimeshinfo/trimeshinfo1.01/trimeshinfo101/readme.txt
@@ -1,5 +1,5 @@
- VCGLib http://vcg.sf.net o o
+ VCGLib http://www.vcglib.net o o
Visual and Computer Graphics Library o o
_ O _
Copyright(C) 2004-2005 \/)\/
@@ -55,6 +55,4 @@ The application has no graphical interface but works as the "Metro" tool on comm
The application works under both Windows and Linux/Unix platforms.
TriMeshInfo is written in C++ and makes use of the VCL library.
-The tool supports two file formats ply (as described in the following document
-http://vcg.sourceforge.net/img/wiki_up/plyformat.pdf)
-and off (as described in http://www.geomview.org/docs/html/geomview_41.html#SEC44) .
+The tool supports two file formats ply and off (as described in http://www.geomview.org/docs/html/geomview_41.html#SEC44) .
diff --git a/apps/trimeshinfo/trimeshinfo1.02/trimeshinfo1.02/readme.txt b/apps/trimeshinfo/trimeshinfo1.02/trimeshinfo1.02/readme.txt
index 6894c62a..4b550b82 100644
--- a/apps/trimeshinfo/trimeshinfo1.02/trimeshinfo1.02/readme.txt
+++ b/apps/trimeshinfo/trimeshinfo1.02/trimeshinfo1.02/readme.txt
@@ -1,5 +1,5 @@
- VCGLib http://vcg.sf.net o o
+ VCGLib http://www.vcglib.net o o
Visual and Computer Graphics Library o o
_ O _
Copyright(C) 2004-2005 \/)\/
@@ -51,6 +51,4 @@ For each analyzed dataset the following information are extracted:
The application has no graphical interface but works as the "Metro" tool on command line.
TriMeshInfo is written in C++ and makes use of the VCL library.
-The tool supports two file formats ply (as described in the following document
-http://vcg.sourceforge.net/img/wiki_up/plyformat.pdf)
-and off (as described in http://www.geomview.org/docs/html/geomview_41.html#SEC44) .
+The tool supports two file formats ply and off (as described in http://www.geomview.org/docs/html/geomview_41.html#SEC44) .
diff --git a/docs/ContributorLicenseAgreement.md b/docs/ContributorLicenseAgreement.md
new file mode 100644
index 00000000..79788115
--- /dev/null
+++ b/docs/ContributorLicenseAgreement.md
@@ -0,0 +1,37 @@
+# Contributor License Agreement
+The following terms are used throughout this agreement:
+
+* **You** - the person or legal entity including its affiliates asked to accept this agreement. An affiliate is any entity that controls or is controlled by the legal entity, or is under common control with it.
+* **VCLab** - the legal representative of the **Visual Computing Lab of the ISTI-CNR** (Istituto di Scienza e Tecnologie dell’Informazione “A. Faedo” an Institute of CNR, the National Research Council of Italy).
+* **Project** - is an umbrella term that refers to any and all the open source projects managed by the VCLab, including, but not limited to, `MeshLab` and the `vcglib`.
+* **Contribution** - any type of work that is submitted to a Project, including any modifications or additions to existing work.
+* **Submitted** - conveyed to a Project via a pull request, commit, issue, or any form of electronic, written, or verbal communication with GitHub, contributors or maintainers.
+
+## 1. Grant of Copyright License.
+Subject to the terms and conditions of this agreement, You grant to the Projects’ maintainers and to VCLab a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your contributions and such derivative works. Except for this license, You reserve all rights, title, and interest in your contributions.
+
+## 2. Grant of Patent License.
+Subject to the terms and conditions of this agreement, You grant to the Projects’ maintainers and to VCLab a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer your contributions, where such license applies only to those patent claims licensable by you that are necessarily infringed by your contribution or by combination of your contribution with the project to which this contribution was submitted.
+
+If any entity institutes patent litigation - including cross-claim or counterclaim in a lawsuit - against You alleging that your contribution or any project it was submitted to constitutes or is responsible for direct or contributory patent infringement, then any patent licenses granted to that entity under this agreement shall terminate as of the date such litigation is filed.
+
+## 3. Source of Contribution.
+Your contribution is either your original creation, based upon previous work that, to the best of your knowledge, is covered under an appropriate open source license and you have the right under that license to submit that work with modifications, whether created in whole or in part by you, or you have clearly identified the source of the contribution and any license or other restriction (like related patents, trademarks, and license agreements) of which you are personally aware.
+
+### 4. Details
+Name
+
+---
+Project Contributed
+
+---
+Contribution (id of the pull request)
+
+---
+Signature
+
+---
+Date
+
+---
+
diff --git a/docs/ContributorLicenseAgreement.pdf b/docs/ContributorLicenseAgreement.pdf
new file mode 100644
index 00000000..f5e0a5fc
Binary files /dev/null and b/docs/ContributorLicenseAgreement.pdf differ
diff --git a/docs/Doxygen/attributes.dxy b/docs/Doxygen/attributes.dxy
index 7f3260f0..66895a9f 100644
--- a/docs/Doxygen/attributes.dxy
+++ b/docs/Doxygen/attributes.dxy
@@ -1,9 +1,9 @@
/** \page attributes
-User-defined attributes
+User-Defined Attributes
=======================
VCG Lib also provides a simple mechanism to associate user-defined typed 'attributes' to the simplicies and to the mesh.
-Note that both 'attributes' and 'components' are basically accessory data that are bound to a simplex.
+Note that both 'attributes' and 'components' are basically accessory data that are bound to a simplex. In short, components are statically defined member data, while attributes are run-time defined, handle accessed, data.
Conceptually the difference is that with the term component VCGLib indicates those basic values that are considered to 'define' the simplex (its position, its normal, its connectivity information), while an user defined attribute is an accessory data that is useful for some specific algorithms, like "the average direction from which a vertex is visible".
@@ -16,14 +16,14 @@ Once you have the handle retrieving and using the attributes is rather simple by
\snippet trimesh_attribute.cpp Using an attribute
-You also have functions to check if a given attribute exists, retrieve an handle for it and eventually deleting it (using the handle or by name).
-Do not get mix up the scope of the handle with the memory allocation of the attribute. If you do not delete an attribute explicitly, it will be allocated until the mesh itself is destroyed, even if you do not have any more handles to it.
+You also have functions to check if a given attribute exists, to retrieve an handle for it and for, eventually, deleting it (using the handle or by name).
+Remember that the scope of a handle does not interfere with the memory allocation of the attribute. If you do not delete an attribute explicitly, it will stay allocated until the mesh itself is destroyed, even if you do not have any more handles to it.
\snippet trimesh_attribute.cpp Deleting an attribute
-The same can be done for the faces, just replace the occurences of PerVertex with PerFace.
+The same can be done for edges, faces and for the mesh itself, just replace the occurences of PerVertex with PerFace, PerEdge and PerMesh.
Note that if you call add an attribute without specifying a name and you lose the handle, you will not be able to get your handle back.
-Attributes can also be specified per mesh; in this case the access is done in a slightly different way.
+For attributes specified as per-mesh the access is done in a slightly different way.
\snippet trimesh_attribute.cpp Per Mesh attribute
diff --git a/docs/Doxygen/main_concept.dxy b/docs/Doxygen/basic_concepts.dxy
similarity index 96%
rename from docs/Doxygen/main_concept.dxy
rename to docs/Doxygen/basic_concepts.dxy
index 71099b37..b0ab1ff8 100644
--- a/docs/Doxygen/main_concept.dxy
+++ b/docs/Doxygen/basic_concepts.dxy
@@ -1,8 +1,7 @@
-/** \page basic_concepts
-How to define a mesh type
-=====
-
-The VCG Lib may encode a mesh in several ways, the most common of which is a set of vertices and set of triangles (i.e. triangles for triangle meshes, tetrahedra for tetrahedral meshes). The following line is an example of the definition of a VCG type of mesh:
+/** \page basic_concepts Basic Concepts
+How to define the type of a mesh
+=========================
+The VCG Lib may encode a mesh in several ways, the most common of which is a vector of vertices and vector of triangles (i.e. triangles for triangle meshes, tetrahedra for tetrahedral meshes). The following line is an example of the definition of a VCG type of mesh:
\dontinclude trimesh_base.cpp
\skip MyMesh
diff --git a/docs/Doxygen/examples.dxy b/docs/Doxygen/examples.dxy
deleted file mode 100644
index fa160531..00000000
--- a/docs/Doxygen/examples.dxy
+++ /dev/null
@@ -1,13 +0,0 @@
-/**
-\page examples
-
-There are a number of very simple and short examples meant to document the various features of the library.
-
-trimesh_base.cpp
-trimesh_optional
-trimesh_attribute.cpp
-
-trimesh_normal.cpp
-
-
-*/
diff --git a/docs/Doxygen/fileformat.dxy b/docs/Doxygen/fileformat.dxy
index f5ebbd16..981cc7d0 100644
--- a/docs/Doxygen/fileformat.dxy
+++ b/docs/Doxygen/fileformat.dxy
@@ -1,4 +1,4 @@
-/** \page fileformat
+/** \page fileformat File Formats
File Formats
============
VCGLib provides importer and exporter for several file formats
diff --git a/docs/Doxygen/groups.dxy b/docs/Doxygen/groups.dxy
index b57eb7f9..7dcc31e1 100644
--- a/docs/Doxygen/groups.dxy
+++ b/docs/Doxygen/groups.dxy
@@ -28,8 +28,9 @@ This module contains the documentation for the types and the functions used for
/** \defgroup code_sample Code Examples
\brief This module contains a number of small examples to explain the library features
-All the example here reported are located under vcglib/apps/sample
-Each sample has a minimal '.pro' file
+All the examples here listed are located in the folder `vcglib/apps/sample`.
+To compile each sample, please use the corresponding `qmake` `*.pro` project files.
+
*/
diff --git a/docs/Doxygen/index.dxy b/docs/Doxygen/index.dxy
index f9b78370..fd90d182 100644
--- a/docs/Doxygen/index.dxy
+++ b/docs/Doxygen/index.dxy
@@ -3,6 +3,8 @@ The Visualization and Computer Graphics Library (VCG for short) is
a open source portable C++ templated library for manipulation, processing
and displaying with OpenGL of triangle and tetrahedral meshes.
+VCG Lib uses a git repository hosted by github at http://github.com/cnr-isti-vclab/vcglib/
+
The library, composed by more than 100k lines of code,
is released under the GPL license, and it is the base of most of the
software tools of the Visual Computing Lab of the Italian National Research Council Institute ISTI
@@ -11,7 +13,7 @@ software tools of the Visual Computing Lab of the Italian National Resear
The VCG library is tailored to mostly manage triangular meshes:
The library is fairly large and offers many state of the art functionalities for processing meshes, like:
-- high quality quadric-error edge-collapse based simplfication,
+- high quality quadric-error edge-collapse based simplification,
- efficient spatial query structures (uniform grids, hashed grids, kdtree, ...) ,
- advanced smoothing and fairing algorithms,
- computation of curvature,
@@ -41,7 +43,7 @@ Start from the following pages for basic concepts and examples.
Notable Applications
-------
A number of applications have been developed using the vcglib:
-- MeshLab: the renowed open source mesh processing is based on this library.
+- MeshLab: the renowned open source mesh processing is based on this library.
- \subpage metro "Metro, the tool for measuring differences between meshes"
- The first high quality out-of-core mesh simplifier that was used by the Stanford Digital Michelangelo project to process their huge 3D scanned models.
diff --git a/docs/Doxygen/install.dxy b/docs/Doxygen/install.dxy
index a1831cfb..5d72f675 100644
--- a/docs/Doxygen/install.dxy
+++ b/docs/Doxygen/install.dxy
@@ -3,33 +3,28 @@
Installation and folder structure
================
-VCG Lib uses a SVN repository hosted by sourceforge.
-The main project page of the library is http://sourceforge.net/projects/vcg/
+VCG Lib uses a git repository hosted by github.
+The main project page of the library is http://github.com/cnr-isti-vclab/vcglib/
-To get the right subset of the svn trunk in the devel folder you should issue the following svn command:
+The stable version of the library are available under the release page
+https://github.com/cnr-isti-vclab/vcglib/releases
- svn checkout svn://svn.code.sf.net/p/vcg/code/trunk/vcglib vcglib
+To get the development version of library clone the 'devel' branch of the library :
-Windows users with tortoisesvn (http://www.tortoisesvn.net) installed should
+ git clone -b devel https://github.com/cnr-isti-vclab/vcglib.git
-1. create a folder named vcglib.
-2. right-click in the newly created vcglib folder and choose SVN Checkout
-3. put in the first parameter: svn://svn.code.sf.net/p/vcg/code/trunk/vcglib
-4. press ok and wait, it should start to check out the last revision of the whole tree.
Folder Structure
================
-VCG Lib is mostly made of header files (and its core part it's only header files).
+VCGLib is mostly made of header files (and its core part it's only header files) with no external dependencies.
Just download the tarball from here and uncompress it in a folder, e.g. named vcg, inside you compiler "include" directory.
-Afterwards, you have to just include the file you need.
+Afterwards, you have to just include the files you need as shown in the apps/sample examples.
Inside vcg folder you will find 5 sub-folders:
- `vcg`: this is the core of the library, where all the algorithms and data structures are defined. This part is pure, quite heavily templated, C++ code with STL support for common data structures and algorithms. You will not find a single include from here to anything else than standard libraries. Note that core part is made of header files (.h files) only.
- `wrap`: here you will find the wrapping of VCG concepts towards specific needs/contexts/libraries. For example you will find all the code to import/export meshes from the hard disk in many formats, or the routines for rendering triangle meshes with OpenGL, supports for common GUI tools like a trackball, and so on..
-- `apps`: this folder contains the command line applications developed with the VCG Lib. Many (much more) examples can be found in MeshLab. The apps/simple directory contains a sub-collection of very basic apps. A good starting point for beginners!
+- `apps`: this folder contains the command line applications developed with the VCG Lib. Many (much more) examples can be found in MeshLab. The apps/sample directory contains a sub-collection of very basic apps. A good starting point for beginners!
- `docs`: documentation lives here (including this tutorial)
- `eigenlib` a copy of the latest stable version of the eigen library for linear algebra ( http://http://eigen.tuxfamily.org/ ). VCGlib relies on eigen for all the advanced matrix processing.
-
-You can browse the svn tree on the sourceforge page http://sourceforge.net/p/vcg/code/HEAD/tree/trunk/vcglib/
*/
diff --git a/vcg/complex/algorithms/clean.h b/vcg/complex/algorithms/clean.h
index 65606b59..c8f62c68 100644
--- a/vcg/complex/algorithms/clean.h
+++ b/vcg/complex/algorithms/clean.h
@@ -79,8 +79,6 @@ public:
mp=&m;
while(!sf.empty()) sf.pop();
UnMarkAll(m);
- assert(p);
- assert(!p->IsD());
tri::Mark(m,p);
sf.push(p);
}
@@ -272,7 +270,6 @@ public:
tri::Index(m,(*fi).V(2)),
&*fi));
}
- assert (size_t(m.fn) == fvec.size());
std::sort(fvec.begin(),fvec.end());
int total=0;
for(int i=0;i::DeleteEdge(m, *(eVec[i].fp) );
- //qDebug("deleting face %i (pos in fvec %i)",tri::Index(m,fvec[i].fp) ,i);
}
}
return total;
@@ -440,12 +434,10 @@ public:
CountNonManifoldVertexFF(m,true);
tri::UpdateSelection::FaceFromVertexLoose(m);
int count_removed = 0;
- FaceIterator fi;
- for(fi=m.face.begin(); fi!=m.face.end();++fi)
+ for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi)
if(!(*fi).IsD() && (*fi).IsS())
Allocator::DeleteFace(m,*fi);
- VertexIterator vi;
- for(vi=m.vert.begin(); vi!=m.vert.end();++vi)
+ for(VertexIterator vi=m.vert.begin(); vi!=m.vert.end();++vi)
if(!(*vi).IsD() && (*vi).IsS()) {
++count_removed;
Allocator::DeleteVertex(m,*vi);
@@ -631,22 +623,15 @@ public:
return count_fd;
}
- /*
- The following functions remove faces that are geometrically "bad" according to edges and area criteria.
- They remove the faces that are out of a given range of area or edges (e.g. faces too large or too small, or with edges too short or too long)
- but that could be topologically correct.
- These functions can optionally take into account only the selected faces.
- */
- template
- static int RemoveFaceOutOfRangeAreaSel(MeshType& m, ScalarType MinAreaThr=0, ScalarType MaxAreaThr=(std::numeric_limits::max)())
+ /* Remove the faces that are out of a given range of area */
+ static int RemoveFaceOutOfRangeArea(MeshType& m, ScalarType MinAreaThr=0, ScalarType MaxAreaThr=(std::numeric_limits::max)(), bool OnlyOnSelected=false)
{
- FaceIterator fi;
int count_fd = 0;
MinAreaThr*=2;
MaxAreaThr*=2;
- for(fi=m.face.begin(); fi!=m.face.end();++fi)
+ for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi){
if(!(*fi).IsD())
- if(!Selected || (*fi).IsS())
+ if(!OnlyOnSelected || (*fi).IsS())
{
const ScalarType doubleArea=DoubleArea(*fi);
if((doubleArea<=MinAreaThr) || (doubleArea>=MaxAreaThr) )
@@ -655,17 +640,13 @@ public:
count_fd++;
}
}
+ }
return count_fd;
}
- // alias for the old style. Kept for backward compatibility
- static int RemoveZeroAreaFace(MeshType& m) { return RemoveFaceOutOfRangeArea(m);}
+ static int RemoveZeroAreaFace(MeshType& m) { return RemoveFaceOutOfRangeArea(m,0);}
- // Aliases for the functions that do not look at selection
- static int RemoveFaceOutOfRangeArea(MeshType& m, ScalarType MinAreaThr=0, ScalarType MaxAreaThr=(std::numeric_limits::max)())
- {
- return RemoveFaceOutOfRangeAreaSel(m,MinAreaThr,MaxAreaThr);
- }
+
/**
* Is the mesh only composed by quadrilaterals?
@@ -850,7 +831,7 @@ public:
*/
static int CountNonManifoldEdgeEE( MeshType & m, bool SelectFlag=false)
{
- assert(m.fn == 0 && m.en >0); // just to be sure we are using an edge mesh...
+ MeshAssert::OnlyEdgeMesh(m);
RequireEEAdjacency(m);
tri::UpdateTopology::EdgeEdge(m);
@@ -1031,61 +1012,27 @@ public:
static int CountHoles( MeshType & m)
{
- int numholev=0;
- FaceIterator fi;
-
- FaceIterator gi;
- vcg::face::Pos he;
- vcg::face::Pos hei;
-
- std::vector< std::vector > holes; //indices of vertices
-
- vcg::tri::UpdateFlags::VertexClearS(m);
-
- gi=m.face.begin(); fi=gi;
-
- for(fi=m.face.begin();fi!=m.face.end();fi++)//for all faces do
+ UpdateFlags::FaceClearV(m);
+ int loopNum=0;
+ for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi) if(!fi->IsD())
{
- for(int j=0;j<3;j++)//for all edges
- {
- if(fi->V(j)->IsS()) continue;
-
- if(face::IsBorder(*fi,j))//found an unvisited border edge
+ for(int j=0;j<3;++j)
{
- he.Set(&(*fi),j,fi->V(j)); //set the face-face iterator to the current face, edge and vertex
- std::vector hole; //start of a new hole
- hole.push_back(fi->P(j)); // including the first vertex
- numholev++;
- he.v->SetS(); //set the current vertex as selected
- he.NextB(); //go to the next boundary edge
-
-
- while(fi->V(j) != he.v)//will we do not encounter the first boundary edge.
+ if(!fi->IsV() && face::IsBorder(*fi,j))
{
- CoordType newpoint = he.v->P(); //select its vertex.
- if(he.v->IsS())//check if this vertex was selected already, because then we have an additional hole.
+ face::Pos startPos(&*fi,j);
+ face::Pos curPos=startPos;
+ do
{
- //cut and paste the additional hole.
- std::vector hole2;
- int index = static_cast(find(hole.begin(),hole.end(),newpoint)
- - hole.begin());
- for(unsigned int i=index; iSetV();
}
- hole.push_back(newpoint);
- numholev++;
- he.v->SetS(); //set the current vertex as selected
- he.NextB(); //go to the next boundary edge
+ while(curPos!=startPos);
+ ++loopNum;
}
- holes.push_back(hole);
}
- }
}
- return static_cast(holes.size());
+ return loopNum;
}
/*
@@ -1102,14 +1049,14 @@ public:
{
tri::RequireFFAdjacency(m);
CCV.clear();
- tri::UpdateSelection::FaceClear(m);
+ tri::UpdateFlags::FaceClearV(m);
std::stack sf;
FacePointer fpt=&*(m.face.begin());
for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
{
- if(!((*fi).IsD()) && !(*fi).IsS())
+ if(!((*fi).IsD()) && !(*fi).IsV())
{
- (*fi).SetS();
+ (*fi).SetV();
CCV.push_back(std::make_pair(0,&*fi));
sf.push(&*fi);
while (!sf.empty())
@@ -1122,9 +1069,9 @@ public:
if( !face::IsBorder(*fpt,j) )
{
FacePointer l = fpt->FFp(j);
- if( !(*l).IsS() )
+ if( !(*l).IsV() )
{
- (*l).SetS();
+ (*l).SetV();
sf.push(l);
}
}
@@ -1260,6 +1207,8 @@ public:
static bool IsCoherentlyOrientedMesh(MeshType &m)
{
+ RequireFFAdjacency(m);
+ MeshAssert::FFAdjacencyIsInitialized(m);
for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
if (!fi->IsD())
for(int i=0;i<3;++i)
@@ -1269,26 +1218,22 @@ public:
return true;
}
- static void OrientCoherentlyMesh(MeshType &m, bool &Oriented, bool &Orientable)
+ static void OrientCoherentlyMesh(MeshType &m, bool &_IsOriented, bool &_IsOrientable)
{
RequireFFAdjacency(m);
- assert(&Oriented != &Orientable);
- assert(m.face.back().FFp(0)); // This algorithms require FF topology initialized
+ MeshAssert::FFAdjacencyIsInitialized(m);
+ bool IsOrientable = true;
+ bool IsOriented = true;
- Orientable = true;
- Oriented = true;
-
- tri::UpdateSelection::FaceClear(m);
+ UpdateFlags::FaceClearV(m);
std::stack faces;
for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
{
- if (!fi->IsD() && !fi->IsS())
+ if (!fi->IsD() && !fi->IsV())
{
// each face put in the stack is selected (and oriented)
- fi->SetS();
+ fi->SetV();
faces.push(&(*fi));
-
- // empty the stack
while (!faces.empty())
{
FacePointer fp = faces.top();
@@ -1297,42 +1242,35 @@ public:
// make consistently oriented the adjacent faces
for (int j = 0; j < 3; j++)
{
- // get one of the adjacent face
- FacePointer fpaux = fp->FFp(j);
- int iaux = fp->FFi(j);
-
- if (!fpaux->IsD() && fpaux != fp && face::IsManifold(*fp, j))
+ if (!face::IsBorder(*fp,j) && face::IsManifold(*fp, j))
{
+ FacePointer fpaux = fp->FFp(j);
+ int iaux = fp->FFi(j);
if (!CheckOrientation(*fpaux, iaux))
{
- Oriented = false;
+ IsOriented = false;
- if (!fpaux->IsS())
- {
+ if (!fpaux->IsV())
face::SwapEdge(*fpaux, iaux);
- assert(CheckOrientation(*fpaux, iaux));
- }
else
{
- Orientable = false;
+ IsOrientable = false;
break;
}
}
-
- // put the oriented face into the stack
-
- if (!fpaux->IsS())
+ if (!fpaux->IsV())
{
- fpaux->SetS();
+ fpaux->SetV();
faces.push(fpaux);
}
}
}
}
}
-
- if (!Orientable) break;
+ if (!IsOrientable) break;
}
+ _IsOriented = IsOriented;
+ _IsOrientable = IsOrientable;
}
@@ -1666,7 +1604,6 @@ public:
*/
static bool TestFaceFaceIntersection(FaceType *f0,FaceType *f1)
{
- assert(f0!=f1);
int sv = face::CountSharedVertex(f0,f1);
if(sv==3) return true;
if(sv==0) return (vcg::IntersectionTriangleTriangle((*f0),(*f1)));
diff --git a/vcg/complex/algorithms/closest.h b/vcg/complex/algorithms/closest.h
index f98f48d1..062404d0 100644
--- a/vcg/complex/algorithms/closest.h
+++ b/vcg/complex/algorithms/closest.h
@@ -82,7 +82,8 @@ namespace vcg {
{
public:
typedef typename MESH_TYPE::VertexType VertexType;
- typedef typename MESH_TYPE::EdgeType EdgeType;
+ typedef typename MESH_TYPE::EdgeType EdgeType;
+ typedef typename MESH_TYPE::FaceType FaceType;
inline EmptyTMark(){}
inline EmptyTMark(MESH_TYPE *){}
inline void UnMarkAll() const {}
@@ -90,6 +91,8 @@ namespace vcg {
inline void Mark(VertexType*) const {}
inline bool IsMarked(EdgeType*) const { return false; }
inline void Mark(EdgeType*) const {}
+ inline bool IsMarked(FaceType*) const { return false; }
+ inline void Mark(FaceType*) const {}
inline void SetMesh(void * /*m=0*/) const {}
};
diff --git a/vcg/complex/algorithms/create/mc_trivial_walker.h b/vcg/complex/algorithms/create/mc_trivial_walker.h
index b7fc9df1..8a745560 100644
--- a/vcg/complex/algorithms/create/mc_trivial_walker.h
+++ b/vcg/complex/algorithms/create/mc_trivial_walker.h
@@ -108,10 +108,8 @@ public:
Vol.resize(this->siz[0]*this->siz[1]*this->siz[2]);
this->ComputeDimAndVoxel();
}
-
-
-
};
+
template
class SimpleVoxel
{
@@ -163,18 +161,10 @@ private:
typedef typename MeshType::VertexPointer VertexPointer;
public:
- // subbox is the portion of the volume to be computed
- // resolution determine the sampling step:
- // should be a divisor of bbox size (e.g. if bbox size is 256^3 resolution could be 128,64, etc)
-
- void Init(VolumeType &volume)
- {
- Init(volume,Box3i(Point3i(0,0,0),volume.ISize()));
- }
-
- void Init(VolumeType &/*volume*/, Box3i subbox)
+ // SetExtractionBox set the portion of the volume to be traversed
+ void SetExtractionBox(Box3i subbox)
{
- _bbox = subbox;
+ _bbox = subbox;
_slice_dimension = _bbox.DimX()*_bbox.DimZ();
_x_cs = new VertexIndex[ _slice_dimension ];
@@ -182,40 +172,39 @@ private:
_z_cs = new VertexIndex[ _slice_dimension ];
_x_ns = new VertexIndex[ _slice_dimension ];
_z_ns = new VertexIndex[ _slice_dimension ];
-
}
-
- ~TrivialWalker()
- {_thr=0;}
+
+ TrivialWalker()
+ {
+ _bbox.SetNull();
+ _slice_dimension=0;
+ }
template
void BuildMesh(MeshType &mesh, VolumeType &volume, EXTRACTOR_TYPE &extractor, const float threshold, vcg::CallBackPos * cb=0)
{
- Init(volume);
+ if(_bbox.IsNull() || _slice_dimension==0)
+ SetExtractionBox(Box3i(Point3i(0,0,0),volume.ISize()));
_volume = &volume;
_mesh = &mesh;
_mesh->Clear();
_thr=threshold;
- vcg::Point3i p1, p2;
-
Begin();
extractor.Initialize();
for (int j=_bbox.min.Y(); j<(_bbox.max.Y()-1)-1; j+=1)
{
-
if(cb && ((j%10)==0) ) cb(j*_bbox.DimY()/100.0,"Marching volume");
-
for (int i=_bbox.min.X(); i<(_bbox.max.X()-1)-1; i+=1)
{
for (int k=_bbox.min.Z(); k<(_bbox.max.Z()-1)-1; k+=1)
{
- p1.X()=i; p1.Y()=j; p1.Z()=k;
- p2.X()=i+1; p2.Y()=j+1; p2.Z()=k+1;
+ Point3i p1(i,j,k);
+ Point3i p2(i+1,j+1,k+1);
if(volume.ValidCell(p1,p2))
extractor.ProcessCell(p1, p2);
}
}
- NextSlice();
+ NextYSlice();
}
extractor.Finalize();
_volume = NULL;
@@ -229,7 +218,7 @@ private:
bool Exist(const vcg::Point3i &p0, const vcg::Point3i &p1, VertexPointer &v)
{
- int pos = p0.X()+p0.Z()*_bbox.max.X();
+ int pos = p0.X()+p0.Z()*_bbox.DimX();
int vidx;
if (p0.X()!=p1.X()) // punti allineati lungo l'asse X
@@ -249,8 +238,8 @@ private:
{
int i = p1.X() - _bbox.min.X();
int z = p1.Z() - _bbox.min.Z();
- VertexIndex index = i+z*_bbox.max.X();
- VertexIndex pos;
+ VertexIndex index = i+z*_bbox.DimX();
+ VertexIndex pos=-1;
if (p1.Y()==_current_slice)
{
if ((pos=_x_cs[index])==-1)
@@ -282,7 +271,7 @@ private:
{
int i = p1.X() - _bbox.min.X();
int z = p1.Z() - _bbox.min.Z();
- VertexIndex index = i+z*_bbox.max.X();
+ VertexIndex index = i+z*_bbox.DimX();
VertexIndex pos;
if ((pos=_y_cs[index])==-1)
{
@@ -298,7 +287,7 @@ private:
{
int i = p1.X() - _bbox.min.X();
int z = p1.Z() - _bbox.min.Z();
- VertexIndex index = i+z*_bbox.max.X();
+ VertexIndex index = i+z*_bbox.DimX();
VertexIndex pos;
if (p1.Y()==_current_slice)
{
@@ -343,7 +332,7 @@ protected:
VolumeType *_volume;
float _thr;
- void NextSlice()
+ void NextYSlice()
{
memset(_x_cs, -1, _slice_dimension*sizeof(VertexIndex));
memset(_y_cs, -1, _slice_dimension*sizeof(VertexIndex));
diff --git a/vcg/complex/algorithms/create/platonic.h b/vcg/complex/algorithms/create/platonic.h
index ef509320..f696c964 100644
--- a/vcg/complex/algorithms/create/platonic.h
+++ b/vcg/complex/algorithms/create/platonic.h
@@ -689,10 +689,14 @@ void SuperEllipsoid(MeshType &m, float rFeature, float sFeature, float tFeature,
tri::Clean::OrientCoherentlyMesh(m,oriented,orientable);
tri::UpdateSelection::Clear(m);
}
-// this function build a mesh starting from a vector of generic coords (objects having a triple of float at their beginning)
-// and a vector of faces (objects having a triple of ints at theri beginning).
-template
-void BuildMeshFromCoordVectorIndexVector( MeshType & in, const V & v, const F & f)
+
+/** This function build a mesh starting from a vector of generic coords (InCoordType) and indexes (InFaceIndexType)
+ * InCoordsType needs to have a [] access method for accessing the three coordinates
+ * and similarly the InFaceIndexType requires [] access method for accessing the three indexes
+ */
+
+template
+void BuildMeshFromCoordVectorIndexVector(MeshType & in, const std::vector & v, const std::vector & f)
{
typedef typename MeshType::CoordType CoordType;
typedef typename MeshType::VertexPointer VertexPointer;
@@ -704,7 +708,7 @@ void BuildMeshFromCoordVectorIndexVector( MeshType & in, const V & v, const F &
for(size_t i=0;i=0 );
assert( ff[1]>=0 );
assert( ff[2]>=0 );
@@ -833,12 +837,13 @@ void FaceGrid(MeshType & in, int w, int h)
}
-// Build a regular grid mesh of faces as a typical height field mesh
-// Vertexes are assumed to be already be allocated, but not oll the grid vertexes are present.
-// For this purpos a grid of indexes is also passed. negative indexes means that there is no vertex.
+// Build a regular grid mesh of faces as the resulto of a sparsely regularly sampled height field.
+// Vertexes are assumed to be already be allocated, but not all the grid vertexes are present.
+// For this purpose vector with a grid of indexes is also passed.
+// Negative indexes in this vector means that there is no vertex.
template
-void FaceGrid(MeshType & in, const std::vector &grid, int w, int h)
+void SparseFaceGrid(MeshType & in, const std::vector &grid, int w, int h)
{
tri::RequireCompactness(in);
assert(in.vn <= w*h); // the number of vertices should match the number of expected grid vertices
diff --git a/vcg/complex/algorithms/create/plymc/plymc.h b/vcg/complex/algorithms/create/plymc/plymc.h
index ed43bfe7..2f3315d3 100644
--- a/vcg/complex/algorithms/create/plymc/plymc.h
+++ b/vcg/complex/algorithms/create/plymc/plymc.h
@@ -35,23 +35,13 @@
#include
#include
-#include
-#include
-
-#include
-#include
#include
-#include
-#include
-#include
-#include
#include
-#include
#include
#include
#include
-#include
+//#include
#include
#include
@@ -61,7 +51,6 @@
#include
#include
-//#include
#include
#include "volume.h"
#include "tri_edge_collapse_mc.h"
@@ -73,6 +62,15 @@ template
void MCSimplify( MeshType &m, float perc, bool preserveBB=true, vcg::CallBackPos *cb=0);
+/** Surface Reconstruction
+ *
+ * To allow the managment of a very large set of meshes to be merged,
+ * it is templated on a MeshProvider class that is able to provide the meshes to be merged.
+ * IT is the surface reconstrction algorithm that have been used for a long time inside the ISTI-Visual Computer Lab.
+ * It is mostly a variant of the Curless et al. e.g. a volumetric approach with some original weighting schemes,"
+ * a different expansion rule, and another approach to hole filling through volume dilation/relaxations.
+ */
+
template < class SMesh, class MeshProvider>
class PlyMC
{
@@ -175,6 +173,7 @@ public:
MeshProvider MP;
Parameter p;
Volume VV;
+ char errorMessage[1024];
/// PLYMC Methods
@@ -192,21 +191,36 @@ public:
{
if(!(loadmask & tri::io::Mask::IOM_VERTNORMAL))
{
- printf("Error, pointset MUST have normals");
- return false;
+ if(m.FN()==0)
+ {
+ sprintf(errorMessage,"%sError: mesh has not per vertex normals\n",errorMessage);
+ return false;
+ }
+ else
+ {
+ tri::Clean::RemoveUnreferencedVertex(m);
+ tri::Allocator::CompactEveryVector(m);
+ tri::UpdateNormal::PerVertexNormalizedPerFaceNormalized(m);
+ }
}
+ tri::UpdateNormal::NormalizePerVertex(m);
+ int badNormalCnt=0;
for(SVertexIterator vi=m.vert.begin(); vi!=m.vert.end();++vi)
if(math::Abs(SquaredNorm((*vi).N())-1.0)>0.0001)
{
- printf("Error: mesh has not per vertex normalized normals\n");
+ badNormalCnt++;
+ tri::Allocator::DeleteVertex(m,*vi);
+ }
+ tri::Allocator::CompactEveryVector(m);
+ if(badNormalCnt > m.VN()/10)
+ {
+ sprintf(errorMessage,"%sError: mesh has null normals\n",errorMessage);
return false;
}
-
+
if(!(loadmask & tri::io::Mask::IOM_VERTQUALITY))
tri::UpdateQuality::VertexConstant(m,0);
tri::UpdateNormal::PerVertexMatrix(m,Tr);
- //if(!(loadmask & tri::io::Mask::IOM_VERTCOLOR))
- // saveMask &= ~tri::io::Mask::IOM_VERTCOLOR;
}
else // processing for triangle meshes
{
@@ -223,7 +237,6 @@ public:
tri::UpdateTopology::VertexFace(m);
tri::UpdateFlags::FaceBorderFromVF(m);
tri::Geodesic::DistanceFromBorder(m);
- // tri::UpdateQuality::VertexGeodesicFromBorder(m);
}
}
@@ -325,8 +338,9 @@ public:
return true;
}
-void Process(vcg::CallBackPos *cb=0)
+bool Process(vcg::CallBackPos *cb=0)
{
+ sprintf(errorMessage,"");
printf("bbox scanning...\n"); fflush(stdout);
Matrix44f Id; Id.SetIdentity();
MP.InitBBox();
@@ -344,7 +358,6 @@ void Process(vcg::CallBackPos *cb=0)
voxdim = fullb.max - fullb.min;
- int TotAdd=0,TotMC=0,TotSav=0;
// if kcell==0 the number of cells is computed starting from required voxel size;
__int64 cells;
if(p.NCell>0) cells = (__int64)(p.NCell)*(__int64)(1000);
@@ -364,6 +377,7 @@ void Process(vcg::CallBackPos *cb=0)
}
+ int TotAdd=0,TotMC=0,TotSav=0; // partial timings counter
for(p.IPos[0]=p.IPosS[0];p.IPos[0]<=p.IPosE[0];++p.IPos[0])
for(p.IPos[1]=p.IPosS[1];p.IPos[1]<=p.IPosE[1];++p.IPos[1])
@@ -405,8 +419,8 @@ void Process(vcg::CallBackPos *cb=0)
res = InitMesh(*sm,MP.MeshName(i).c_str(),MP.Tr(i));
if(!res)
{
- printf("Failed Init of mesh %s",MP.MeshName(i).c_str());
- return;
+ sprintf(errorMessage,"%sFailed Init of mesh %s\n",errorMessage,MP.MeshName(i).c_str());
+ return false ;
}
}
res |= AddMeshToVolumeM(*sm, MP.MeshName(i),MP.W(i));
@@ -452,26 +466,20 @@ void Process(vcg::CallBackPos *cb=0)
VV.SlicedPPM("final","__",p.SliceNum);
VV.SlicedPPMQ("final","__",p.SliceNum);
}
- //MCMesh me;
- //
MCMesh me;
if(res)
{
- typedef vcg::tri::TrivialWalker > Walker;
+ typedef vcg::tri::TrivialWalker > Walker;
typedef vcg::tri::MarchingCubes MarchingCubes;
- //typedef vcg::tri::ExtendedMarchingCubes ExtendedMarchingCubes;
Walker walker;
MarchingCubes mc(me, walker);
- Box3i currentSubBox=VV.SubPartSafe;
- Point3i currentSubBoxRes=VV.ssz;
/**********************/
if(cb) cb(50,"Step 2: Marching Cube...");
else printf("Step 2: Marching Cube...\n");
/**********************/
- walker.Init(VV,currentSubBox);
+ walker.SetExtractionBox(VV.SubPartSafe);
walker.BuildMesh(me,VV,mc,0);
- // walker.BuildMesh(me,VV,mc,currentSubBox,currentSubBoxRes);
typename MCMesh::VertexIterator vi;
Box3f bbb; bbb.Import(VV.SubPart);
@@ -481,8 +489,7 @@ void Process(vcg::CallBackPos *cb=0)
vcg::tri::Allocator< MCMesh >::DeleteVertex(me,*vi);
VV.DeInterize((*vi).P());
}
- typename MCMesh::FaceIterator fi;
- for (fi = me.face.begin(); fi != me.face.end(); ++fi)
+ for (typename MCMesh::FaceIterator fi = me.face.begin(); fi != me.face.end(); ++fi)
{
if((*fi).V(0)->IsD() || (*fi).V(1)->IsD() || (*fi).V(2)->IsD() )
vcg::tri::Allocator< MCMesh >::DeleteFace(me,*fi);
@@ -526,6 +533,7 @@ void Process(vcg::CallBackPos *cb=0)
{
printf("----------- skipping SubBlock %2i %2i %2i ----------\n",p.IPos[0],p.IPos[1],p.IPos[2]);
}
+ return true;
}
diff --git a/vcg/complex/algorithms/create/plymc/simplemeshprovider.h b/vcg/complex/algorithms/create/plymc/simplemeshprovider.h
new file mode 100644
index 00000000..1ce3be53
--- /dev/null
+++ b/vcg/complex/algorithms/create/plymc/simplemeshprovider.h
@@ -0,0 +1,233 @@
+#ifndef SIMPLEMESHPROVIDER_H
+#define SIMPLEMESHPROVIDER_H
+#include "../../meshlab/alnParser.h"
+#include
+#include
+#include
+#include
+#include
+
+/*
+ * A mesh provider class has the simpler role of passing the set of meshes to be merged to the surface reconstrcution algorithm.
+ * The only reason for this abstraction is that, plymc can work in a out-of-core way and the loading of the needed range maps can be optimized with a high level caching system.
+ */
+template
+class MinimalMeshProvider
+{
+private:
+
+ std::vector< std::string > nameVec;
+ std::vector< TriMeshType * > meshVec;
+ std::vector trVec;
+ std::vector weightVec; // weight tot be applied to each mesh.
+ vcg::Box3f fullBBox;
+
+public:
+ bool Find(const std::string &name, TriMeshType * &sm)
+ {
+ for(int i=0;i
+class MeshCache
+{
+ class Pair
+ {
+ public:
+ Pair(){used=0;}
+ TriMeshType *M;
+ std::string Name;
+ int used; // 'data' dell'ultimo accesso. si butta fuori quello lru
+ };
+
+ std::list MV;
+
+public:
+ void clear();
+
+ MeshCache() {MeshCacheSize=6;}
+ ~MeshCache() {
+ typename std::list::iterator mi;
+ for(mi=MV.begin();mi!=MV.end();++mi)
+ delete (*mi).M;
+ }
+
+
+ /**
+ * @brief Find load a mesh form the cache if it is in or from the disk otherwise
+ * @param name what mesh to find
+ * @param sm the pointer loaded mesh
+ * @return true if the mesh was already in cache
+ *
+ */
+ bool Find(const std::string &name, TriMeshType * &sm)
+ {
+ typename std::list::iterator mi;
+ typename std::list::iterator oldest; // quello che e' piu' tempo che non viene acceduto.
+ int last;
+
+ last = std::numeric_limits::max();
+ oldest = MV.begin();
+
+ for(mi=MV.begin();mi!=MV.end();++mi)
+ {
+ if((*mi).usedMeshCacheSize) {
+ sm=(*oldest).M;
+ (*oldest).used=0;
+ (*oldest).Name=name;
+ } else {
+ MV.push_back(Pair());
+ MV.back().Name=name;
+ MV.back().M=new TriMeshType();
+ sm=MV.back().M;
+ }
+ return false;
+ }
+
+
+ size_t MeshCacheSize;
+ size_t size() const {return MV.size();}
+};
+
+template
+class SimpleMeshProvider
+{
+private:
+ std::vector< std::string > meshnames;
+ std::vector TrV;
+ std::vector WV; // weight tot be applied to each mesh.
+ std::vector BBV; // bbox of the transformed meshes..
+ vcg::Box3f fullBBox;
+ MeshCache MC;
+
+public:
+
+ int size() {return meshnames.size();}
+
+ int getCacheSize() {return MC.MeshCacheSize;}
+ int setCacheSize(size_t newsize)
+ {
+ if(newsize == MC.MeshCacheSize)
+ return MC.MeshCacheSize;
+ if(newsize <= 0)
+ return MC.MeshCacheSize;
+
+ MC.MeshCacheSize = newsize;
+ return newsize;
+ }
+
+ bool openALN (const char* alnName)
+ {
+ vector rmaps;
+ ALNParser::ParseALN(rmaps, alnName);
+
+ for(size_t i=0; i::FileExtension(meshnames[i],"PLY") || tri::io::Importer::FileExtension(meshnames[i],"ply"))
+ {
+ ret=ply::ScanBBox(meshnames[i].c_str(),BBV[i],TrV[i],true,0);
+ }
+ else
+ {
+ printf("Trying to import a non-ply file %s\n",meshnames[i].c_str());fflush(stdout);
+ TriMeshType m;
+ ret = (tri::io::Importer::Open(m,meshnames[i].c_str()) == tri::io::Importer::E_NOERROR);
+ tri::UpdatePosition::Matrix(m,TrV[i]);
+ tri::UpdateBounding::Box(m);
+ BBV[i].Import(m.bbox);
+ }
+ if( ! ret)
+ {
+ printf("\n\nwarning:\n file '%s' not found\n",meshnames[i].c_str());fflush(stdout);
+ continue;
+ }
+ fullBBox.Add(BBV[i]);
+ }
+ return true;
+ }
+
+};
+
+class SVertex;
+class SFace;
+class SUsedTypes: public vcg::UsedTypes < vcg::Use::AsVertexType,
+ vcg::Use::AsFaceType >{};
+
+class SVertex : public Vertex< SUsedTypes, vertex::Coord3f, vertex::Normal3f,vertex::VFAdj, vertex::BitFlags, vertex::Color4b, vertex::Qualityf>{};
+class SFace : public Face< SUsedTypes, face::VertexRef, face::Normal3f,face::Qualityf, face::VFAdj, face::BitFlags> {};
+class SMesh : public tri::TriMesh< std::vector< SVertex>, std::vector< SFace > > {};
+
+}
+
+#endif // SIMPLEMESHPROVIDER_H
diff --git a/vcg/complex/algorithms/create/plymc/tri_edge_collapse_mc.h b/vcg/complex/algorithms/create/plymc/tri_edge_collapse_mc.h
index 733b4b96..72a391be 100644
--- a/vcg/complex/algorithms/create/plymc/tri_edge_collapse_mc.h
+++ b/vcg/complex/algorithms/create/plymc/tri_edge_collapse_mc.h
@@ -22,7 +22,8 @@
****************************************************************************/
#ifndef __TRI_EDGE_COLLAPSE_MC__
#define __TRI_EDGE_COLLAPSE_MC__
-#include
+namespace vcg{
+namespace tri{
class TriEdgeCollapseMCParameter : public BaseParameterClass
{
@@ -125,5 +126,7 @@ class MCTriEdgeCollapse: public tri::TriEdgeCollapse< MCTriMesh, VertexPair, MYT
};
+}
+}
#endif
diff --git a/vcg/complex/algorithms/create/plymc/volume.h b/vcg/complex/algorithms/create/plymc/volume.h
index d543c32e..0a9ba7fc 100644
--- a/vcg/complex/algorithms/create/plymc/volume.h
+++ b/vcg/complex/algorithms/create/plymc/volume.h
@@ -24,26 +24,10 @@
#ifndef __VOLUME_H__
#define __VOLUME_H__
-#ifdef __MINGW32__
-#define _int64 __int64
-#endif
-
#include "voxel.h"
-#include "svoxel.h"
-#include
#include
-//#define BLOCKSIDE() 8
-
-// Stato di un voxel
-
-// B() dice se ci sono dati in uno stadio usabile.
-// Cnt() dice quanti ce ne sono stati sommati (per la normalizzazione)
-
-// b==false cnt==0 totalmente non inzializzato (Zero)
-// b==false cnt >0 da normalizzare
-// b==true cnt==0 gia' normalizzato
-// b==true cnt >0 Errore!!!
+namespace vcg {
// forward definition
template < class VOL >
@@ -67,7 +51,7 @@ const char *SFormat( const char * f, ... )
template
class Volume {
public:
- typedef SCALAR_TYPE scalar;
+ typedef SCALAR_TYPE scalar;
typedef Point3 Point3x;
typedef Box3 Box3x;
@@ -172,7 +156,7 @@ bool Verbose; // se true stampa un sacco di info in piu su logfp;
for(size_t i=0;i inside the subblock of voxel (x,y,z).
+ * return true if the subblock is allocated.
+ */
bool Pos(const int &_x,const int &_y,const int &_z, int & rpos,int &lpos) const
{
int x=_x-SubPartSafe.min[0]; int y=_y-SubPartSafe.min[1]; int z=_z-SubPartSafe.min[2];
assert(_x>=SubPartSafe.min[0] && _x=SubPartSafe.min[1] && _y=SubPartSafe.min[2] && _z=SubPartSafe.min[1] && _y=SubPartSafe.min[2] && _z=0 && x=0 && y=0 && z0 da normalizzare
+// b==true cnt==0 gia' normalizzato
+// b==true cnt >0 Errore!!!
+
+
+/**
+ *
+ */
+
template
class Voxel
{
- public:
- typedef SCALAR_TYPE scalar;
+public:
+ typedef SCALAR_TYPE scalar;
- Voxel(SCALAR_TYPE vv, bool bb, Point3 nn, short _cnt) {v=vv;b=bb;n=nn;cnt=_cnt;}
- Voxel(SCALAR_TYPE vv, Point3 nn, scalar qq) {v=vv;b=true;n=nn;cnt=0;q=qq;}
+ Voxel(SCALAR_TYPE vv, bool bb, Point3 nn, short _cnt) {v=vv;b=bb;n=nn;cnt=_cnt;}
+ Voxel(SCALAR_TYPE vv, Point3 nn, scalar qq) {v=vv;b=true;n=nn;cnt=0;q=qq;}
- const scalar &N(const int i) const { return n[i]; }
+ const Point3 &N() const { return n; }
- const Point3 &N() const { return n; }
+ void SetN(const Point3 &nn) { n=nn; }
+ const scalar &V() const { return v; }
- void SetN(const Point3 &nn) { n=nn; }
- const scalar &V() const { return v; }
+ void SetV(const scalar &vv) { v=vv; }
- void SetV(const scalar &vv) { v=vv; }
+ const scalar &Q() const { return q; }
- const scalar &Q() const { return q; }
-
- void SetQ(const scalar &qq) { q=qq; }
+ void SetQ(const scalar &qq) { q=qq; }
- bool B() const {return b;};
- void SetB(bool val) {b=val;}
- int Cnt() const {return cnt;}
- void SetCnt(int val) {cnt=val;}
- inline void Blend( Voxel const & vx, scalar w)
+ bool B() const {return b;};
+ void SetB(bool val) {b=val;}
+ int Cnt() const {return cnt;}
+ void SetCnt(int val) {cnt=val;}
+ inline void Blend( Voxel const & vx, scalar w)
+ {
+ float w1=1.0-w;
+ v=v*w1+vx.v*w;
+ q=q*w1+vx.q*w;
+ n=n*w1+vx.n*w;
+ //return *this;
+ }
+
+ inline Voxel & operator += ( Voxel const & vx)
+ {
+ assert(!b);
+ if(cnt==0)
{
- float w1=1.0-w;
- v=v*w1+vx.v*w;
- q=q*w1+vx.q*w;
- n=n*w1+vx.n*w;
- //return *this;
+ v=vx.v;
+ q=vx.q;
+ n=vx.n;
+ cnt=1;
+ b=false;
}
-
- inline Voxel & operator += ( Voxel const & vx)
+ else
{
- if(cnt==0)
- {
- assert(!b);
- v=vx.v;
- q=vx.q;
- n=vx.n;
- cnt=1;
- b=false;
- }
- else
- {
- assert(!b);
- v+=vx.v;
- q+=vx.q;
- n+=vx.n;
- ++cnt;
- }
- return *this;
+ v+=vx.v;
+ q+=vx.q;
+ n+=vx.n;
+ ++cnt;
}
+ return *this;
+ }
- inline bool Normalize(int thr)
+ inline bool Normalize(int thr)
+ {
+ assert(cnt>0);
+ assert(!B());
+ if(cnt0);
- assert(!B());
- if(cnt n;
+protected:
+ bool b;
+ short cnt;
+ scalar v;
+ scalar q;
+ Point3 n;
};
@@ -129,67 +144,67 @@ class Voxelfc :public Voxel
{
public:
- Voxelfc(float vv, bool bb, Point3f nn, short _cnt) :Voxel(vv,bb,nn,_cnt){}
- Voxelfc(float vv, Point3f nn, scalar qq) :Voxel(vv,nn,qq) {}
- Voxelfc(float vv, Point3f nn, scalar qq,Color4b cc) :Voxel(vv,nn,qq)
- {
- c[0]=cc[0];
- c[1]=cc[1];
- c[2]=cc[2];
- }
+ Voxelfc(float vv, bool bb, Point3f nn, short _cnt) :Voxel(vv,bb,nn,_cnt){}
+ Voxelfc(float vv, Point3f nn, scalar qq) :Voxel(vv,nn,qq) {}
+ Voxelfc(float vv, Point3f nn, scalar qq,Color4b cc) :Voxel(vv,nn,qq)
+ {
+ c[0]=cc[0];
+ c[1]=cc[1];
+ c[2]=cc[2];
+ }
- inline bool Normalize(int thr)
- {
- if(cnt>=thr) c/=cnt;
- return Voxel::Normalize(thr);
- }
+ inline bool Normalize(int thr)
+ {
+ if(cnt>=thr) c/=cnt;
+ return Voxel::Normalize(thr);
+ }
- static const Voxelfc &Zero() {
- static Voxelfc tt(0,false,Point3f(0,0,0),0);
- return tt;
- }
+ static const Voxelfc &Zero() {
+ static Voxelfc tt(0,false,Point3f(0,0,0),0);
+ return tt;
+ }
- void Merge(const Voxelfc &VOX)
- {
- c=( c*q + VOX.C()*VOX.Q() )/(q+VOX.Q());
- Voxel::Merge(VOX);
- }
+ void Merge(const Voxelfc &VOX)
+ {
+ c=( c*q + VOX.C()*VOX.Q() )/(q+VOX.Q());
+ Voxel::Merge(VOX);
+ }
- void Set(const Voxelfc &VOX)
- {
- Voxel::Set(VOX);
- c=VOX.c;
- }
+ void Set(const Voxelfc &VOX)
+ {
+ Voxel::Set(VOX);
+ c=VOX.c;
+ }
- const float &C(const int i) const { return c[i]; }
- const Point3f &C() const { return c; }
- void SetC(const Point3f &cc) { c=cc; }
- Color4b C4b() const
- {
- static Color4b cc;
- cc=Color4b(c[0],c[1],c[2],255);
- return cc;
- }
- inline void Blend( Voxelfc const & vx, scalar w)
- {
- float w1=1.0-w;
- v=v*w1+vx.v*w;
- q=q*w1+vx.q*w;
- n=n*w1+vx.n*w;
- c=c*w1+vx.c*w;
- //return *this;
- }
+ const float &C(const int i) const { return c[i]; }
+ const Point3f &C() const { return c; }
+ void SetC(const Point3f &cc) { c=cc; }
+ Color4b C4b() const
+ {
+ static Color4b cc;
+ cc=Color4b(c[0],c[1],c[2],255);
+ return cc;
+ }
+ inline void Blend( Voxelfc const & vx, scalar w)
+ {
+ float w1=1.0-w;
+ v=v*w1+vx.v*w;
+ q=q*w1+vx.q*w;
+ n=n*w1+vx.n*w;
+ c=c*w1+vx.c*w;
+ //return *this;
+ }
- inline Voxelfc & operator += ( Voxelfc const & vx)
- {
- Voxel::operator +=(vx);
- if(cnt==1) c =vx.c;
- else c+=vx.c;
- return *this;
- }
+ inline Voxelfc & operator += ( Voxelfc const & vx)
+ {
+ Voxel::operator +=(vx);
+ if(cnt==1) c =vx.c;
+ else c+=vx.c;
+ return *this;
+ }
private:
- Point3f c;
+ Point3f c;
};
-
+}
#endif
diff --git a/vcg/complex/algorithms/hole.h b/vcg/complex/algorithms/hole.h
index 1febb289..c906ccb6 100644
--- a/vcg/complex/algorithms/hole.h
+++ b/vcg/complex/algorithms/hole.h
@@ -36,6 +36,7 @@
namespace vcg {
namespace tri {
+
/*
An ear is identified by TWO pos.
The Three vertexes of an Ear are:
@@ -46,31 +47,32 @@ namespace vcg {
e1 == e0.NextB();
e1.FlipV() == e0;
- Situazioni ear non manifold, e degeneri (buco triangolare)
-
- T XXXXXXXXXXXXX A /XXXXX B en/XXXXX
- /XXXXXXXXXXXXXXX /XXXXXX /XXXXXX
- XXXXXXep==en XXX ep\ /en XXXX /e1 XXXX
- XXXXXX ----/| XX ------ ----/| XX ------ ----/|XXX
- XXXXXX| /e1 XX XXXXXX| /e1 XX XXXXXX| o/e0 XX
- XXXXXX| /XXXXXX XXXXXX| /XXXXXX XXXXXX| /XXXXXX
- XXX e0|o/XXXXXXX XXX e0|o/XXXXXXX XXX ep| /XXXXXXX
- XXX \|/XXXXXXXX XXX \|/XXXXXXXX XXX \|/XXXXXXXX
- XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
*/
+/**
+ * Basic class for representing an 'ear' in a hole.
+ *
+ * Require FF-adajcncy and edge-manifoldness around the mesh (at most two triangles per edge)
+ *
+ * An ear is represented by two consecutive Pos e0,e1.
+ * The vertex pointed by the first pos is the 'corner' of the ear
+ *
+ *
+ */
template class TrivialEar
{
public:
- typedef typename MESH::FaceType FaceType;
- typedef typename MESH::FacePointer FacePointer;
+ typedef typename MESH::FaceType FaceType;
+ typedef typename MESH::VertexType VertexType;
+ typedef typename MESH::FacePointer FacePointer;
typedef typename MESH::VertexPointer VertexPointer;
- typedef typename face::Pos PosType;
- typedef typename MESH::ScalarType ScalarType;
- typedef typename MESH::CoordType CoordType;
-
+ typedef typename face::Pos PosType;
+ typedef typename MESH::ScalarType ScalarType;
+ typedef typename MESH::CoordType CoordType;
+
PosType e0;
PosType e1;
CoordType n; // the normal of the face defined by the ear
+
const char * Dump() {return 0;}
// The following members are useful to consider the Ear as a generic
// with p0 the 'center' of the ear.
@@ -116,14 +118,50 @@ public:
virtual void ComputeQuality() { quality = QualityFace(*this) ; }
bool IsUpToDate() {return ( e0.IsBorder() && e1.IsBorder());}
// An ear is degenerated if both of its two endpoints are non manifold.
- bool IsDegen(const int nonManifoldBit)
+ bool IsDegen()
{
- if(e0.VFlip()->IsUserBit(nonManifoldBit) && e1.V()->IsUserBit(nonManifoldBit))
+ if(e0.VFlip()->IsUserBit(NonManifoldBit()) && e1.V()->IsUserBit(NonManifoldBit()))
return true;
else return false;
}
bool IsConcave() const {return(angleRad > (float)M_PI);}
+
+ /** NonManifoldBit
+ * To handle non manifoldness situations we keep track
+ * of the vertices of the hole boundary that are traversed by more than a single boundary.
+ *
+ */
+ static int &NonManifoldBit() { static int _NonManifoldBit=0; return _NonManifoldBit; }
+ static int InitNonManifoldBitOnHoleBoundary(const PosType &p)
+ {
+ if(NonManifoldBit()==0)
+ NonManifoldBit() = VertexType::NewBitFlag();
+ int holeSize=0;
+
+ //First loop around the hole to mark non manifold vertices.
+ PosType ip = p; // Pos iterator
+ do{
+ ip.V()->ClearUserBit(NonManifoldBit());
+ ip.V()->ClearV();
+ ip.NextB();
+ holeSize++;
+ } while(ip!=p);
+
+ ip = p; // Re init the pos iterator for another loop (useless if everithing is ok!!)
+ do{
+ if(!ip.V()->IsV())
+ ip.V()->SetV();
+ else // All the vertexes that are visited more than once are non manifold
+ ip.V()->SetUserBit(NonManifoldBit());
+ ip.NextB();
+ } while(ip!=p);
+ return holeSize;
+ }
+
+
+
+
// When you close an ear you have to check that the newly added triangle does not create non manifold situations
// This can happen if the new edge already exists in the mesh.
// We test that looping around one extreme of the ear we do not find the other vertex
@@ -141,8 +179,38 @@ public:
while(!pp.IsBorder());
return true;
}
-
- virtual bool Close(PosType &np0, PosType &np1, FaceType * f)
+ /**
+ * @brief Close the current ear by adding a triangle to the mesh
+ * and returning up to two new possible ears to be closed.
+ *
+ * @param np0 The first new pos to be inserted in the heap
+ * @param np1 The second new pos
+ * @param f the already allocated face to be used to close the ear
+ * @return true if it successfully add a triangle
+ *
+ * +\
+ * +++\ -------
+ * +++ep\ /| +++en/\
+ * +++---| /e1 ++++++++\
+ * ++++++| /++++++++++++++\
+ * +++ e0|o /+++++++++++++++++++
+ * +++ \|/+++++++++++++++++++++
+ * +++++++++++++++++++++++++++++
+ *
+ * There are three main peculiar cases:
+
+ * (T)+++++++++++++ (A) /+++++ (B) /en+++++++
+ * /+++++++++++++++ /++++++ /++++++++++
+ * ++++++ep==en +++ ep\ /en ++++ /e1 ++++++++
+ * ++++++ ----/| ++ ------ ----/| ++ ------------/|+++
+ * ++++++| /e1 ++ ++++++| /e1 ++ ++++++| o/e0|+++
+ * ++++++| /++++++ ++++++| /++++++ ++++++| /++++++++
+ * +++ e0|o/+++++++ +++ e0|o/+++++++ +++ ep| /++++++++++
+ * +++ \|/++++++++ +++ \|/++++++++ +++ \|/++++++++++++
+ * ++++++++++++++++ ++++++++++++++++ ++++++++++++++++++++
+ */
+
+ virtual bool Close(PosType &np0, PosType &np1, FaceType *f)
{
// simple topological check
if(e0.f==e1.f) {
@@ -150,9 +218,8 @@ public:
return false;
}
- //usato per generare una delle due nuove orecchie.
- PosType ep=e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // he precedente a e0
- PosType en=e1; en.NextB(); // he successivo a e1
+ PosType ep=e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // ep previous
+ PosType en=e1; en.NextB(); // en next
if(ep!=en)
if(!CheckManifoldAfterEarClose()) return false;
@@ -165,7 +232,7 @@ public:
face::FFAttachManifold(f,1,e1.f,e1.z);
face::FFSetBorder(f,2);
- // caso ear degenere per buco triangolare
+ // First Special Case (T): Triangular hole
if(ep==en)
{
//printf("Closing the last triangle");
@@ -173,30 +240,38 @@ public:
np0.SetNull();
np1.SetNull();
}
- // Caso ear non manifold a
+ // Second Special Case (A): Non Manifold on ep
else if(ep.v==en.v)
{
//printf("Ear Non manif A\n");
+ assert(ep.v->IsUserBit(NonManifoldBit()));
+ ep.v->ClearUserBit(NonManifoldBit());
PosType enold=en;
en.NextB();
face::FFAttachManifold(f,2,enold.f,enold.z);
np0=ep;
- np1=en;
+ assert(!np0.v->IsUserBit(NonManifoldBit()));
+ np1.SetNull();
}
- // Caso ear non manifold b
+ // Third Special Case (B): Non Manifold on e1
else if(ep.VFlip()==e1.v)
{
+ assert(e1.v->IsUserBit(NonManifoldBit()));
+ e1.v->ClearUserBit(NonManifoldBit());
//printf("Ear Non manif B\n");
PosType epold=ep;
ep.FlipV(); ep.NextB(); ep.FlipV();
face::FFAttachManifold(f,2,epold.f,epold.z);
np0=ep; // assign the two new
- np1=en; // pos that denote the ears
+ assert(!np0.v->IsUserBit(NonManifoldBit()));
+ np1.SetNull(); // pos that denote the ears
}
- else // caso standard // Now compute the new ears;
+ else // Standard Case.
{
np0=ep;
+ if(np0.v->IsUserBit(NonManifoldBit())) np0.SetNull();
np1=PosType(f,2,e1.v);
+ if(np1.v->IsUserBit(NonManifoldBit())) np1.SetNull();
}
return true;
@@ -315,174 +390,138 @@ public:
}
}; // end class SelfIntersectionEar
-// Funzione principale per chiudier un buco in maniera topologicamente corretta.
-// Gestisce situazioni non manifold ragionevoli
-// (tutte eccetto quelle piu' di 2 facce per 1 edge).
-// Controlla che non si generino nuove situazioni non manifold chiudendo orecchie
-// che sottendono un edge che gia'esiste.
+
+/** Hole
+ * Main hole filling templated class.
+ *
+ */
template
class Hole
{
public:
- typedef typename MESH::VertexType VertexType;
- typedef typename MESH::VertexPointer VertexPointer;
- typedef typename MESH::ScalarType ScalarType;
- typedef typename MESH::FaceType FaceType;
- typedef typename MESH::FacePointer FacePointer;
- typedef typename MESH::FaceIterator FaceIterator;
- typedef typename MESH::CoordType CoordType;
- typedef typename vcg::Box3 Box3Type;
- typedef typename face::Pos PosType;
-
+ typedef typename MESH::VertexType VertexType;
+ typedef typename MESH::VertexPointer VertexPointer;
+ typedef typename MESH::ScalarType ScalarType;
+ typedef typename MESH::FaceType FaceType;
+ typedef typename MESH::FacePointer FacePointer;
+ typedef typename MESH::FaceIterator FaceIterator;
+ typedef typename MESH::CoordType CoordType;
+ typedef typename vcg::Box3 Box3Type;
+ typedef typename face::Pos PosType;
+
public:
- class Info
- {
- public:
- Info(){}
- Info(PosType const &pHole, int const pHoleSize, Box3 &pHoleBB)
- {
- p=pHole;
- size=pHoleSize;
- bb=pHoleBB;
- }
-
- PosType p;
- int size;
- Box3Type bb;
-
- bool operator < (const Info & hh) const {return size < hh.size;}
-
- ScalarType Perimeter()
- {
- ScalarType sum=0;
- PosType ip = p;
- do
- {
- sum+=Distance(ip.v->cP(),ip.VFlip()->cP());
- ip.NextB();
- }
- while (ip != p);
- return sum;
- }
-
- // Support function to test the validity of a single hole loop
- // for now it test only that all the edges are border;
- // The real test should check if all non manifold vertices
- // are touched only by edges belonging to this hole loop.
- bool CheckValidity()
+ class Info
+ {
+ public:
+ Info(){}
+ Info(PosType const &pHole, int const pHoleSize, Box3 &pHoleBB)
+ {
+ p=pHole;
+ size=pHoleSize;
+ bb=pHoleBB;
+ }
+
+ PosType p;
+ int size;
+ Box3Type bb;
+
+ bool operator < (const Info & hh) const {return size < hh.size;}
+
+ ScalarType Perimeter()
+ {
+ ScalarType sum=0;
+ PosType ip = p;
+ do
{
- if(!p.IsBorder())
- return false;
- PosType ip=p;ip.NextB();
- for(;ip!=p;ip.NextB())
- {
- if(!ip.IsBorder())
- return false;
- }
- return true;
+ sum+=Distance(ip.v->cP(),ip.VFlip()->cP());
+ ip.NextB();
}
- };
-
-
- class EdgeToBeAvoided
- {
- VertexPointer v0,v1;
- EdgeToBeAvoided(VertexPointer _v0, VertexPointer _v1):v0(_v0),v1(_v1)
- {
- if(v0>v1) swap(v0,v1);
- }
- bool operator < (const EdgeToBeAvoided &e)
- {
- if(this->v0!=e.v0) return this->v0v1
static void FillHoleEar(MESH &m, // The mesh to be filled
- Info &h, // the particular hole to be filled
+ const PosType &p, // the particular hole to be filled
std::vector &facePointersToBeUpdated)
{
- //Aggiungo le facce e aggiorno il puntatore alla faccia!
- FaceIterator f = tri::Allocator::AddFaces(m, h.size-2, facePointersToBeUpdated);
+
+ assert(tri::IsValidPointer(m,p.f));
+ assert(p.IsBorder());
+ int holeSize = EAR::InitNonManifoldBitOnHoleBoundary(p);
+ FaceIterator f = tri::Allocator::AddFaces(m, holeSize-2, facePointersToBeUpdated);
- assert(h.p.f >= &*m.face.begin());
- assert(h.p.f <= &m.face.back());
- assert(h.p.IsBorder());
-
- std::vector< EAR > EarHeap;
- EarHeap.reserve(h.size);
- int nmBit= VertexType::NewBitFlag(); // non manifoldness bit
-
- //First loops around the hole to mark non manifold vertices.
- PosType ip = h.p; // Pos iterator
- do{
- ip.V()->ClearUserBit(nmBit);
- ip.V()->ClearV();
- ip.NextB();
- } while(ip!=h.p);
-
- ip = h.p; // Re init the pos iterator for another loop (useless if everithing is ok!!)
- do{
- if(!ip.V()->IsV())
- ip.V()->SetV(); // All the vertexes that are visited more than once are non manifold
- else ip.V()->SetUserBit(nmBit);
- ip.NextB();
- } while(ip!=h.p);
-
- PosType fp = h.p;
+ std::priority_queue< EAR > EarHeap;
+ PosType fp = p;
do{
EAR appEar = EAR(fp);
- EarHeap.push_back( appEar );
+ if(!fp.v->IsUserBit(EAR::NonManifoldBit()))
+ EarHeap.push( appEar );
//printf("Adding ear %s ",app.Dump());
fp.NextB();
assert(fp.IsBorder());
- }while(fp!=h.p);
+ }while(fp!=p);
- int cnt=h.size;
-
- make_heap(EarHeap.begin(), EarHeap.end());
-
- //finche' il buco non e' chiuso o non ci sono piu' orecchie da analizzare.
- while( cnt > 2 && !EarHeap.empty() )
+ // Main Ear closing Loop
+ while( holeSize > 2 && !EarHeap.empty() )
{
- //printf("Front of the heap is %s", H.front().Dump());
- pop_heap(EarHeap.begin(), EarHeap.end()); // retrieve the MAXIMUM value and put in the back;
- EAR BestEar=EarHeap.back();
- EarHeap.pop_back();
+ EAR BestEar=EarHeap.top();
+ EarHeap.pop();
- if(BestEar.IsUpToDate() && !BestEar.IsDegen(nmBit))
+ if(BestEar.IsUpToDate() && !BestEar.IsDegen())
{
if((*f).HasPolyInfo()) (*f).Alloc(3);
PosType ep0,ep1;
if(BestEar.Close(ep0,ep1,&*f))
{
if(!ep0.IsNull()){
- EarHeap.push_back(EAR(ep0));
- push_heap( EarHeap.begin(), EarHeap.end());
+ assert(!ep0.v->IsUserBit(EAR::NonManifoldBit()));
+ EarHeap.push(EAR(ep0));
}
if(!ep1.IsNull()){
- EarHeap.push_back(EAR(ep1));
- push_heap( EarHeap.begin(), EarHeap.end());
+ assert(!ep1.v->IsUserBit(EAR::NonManifoldBit()));
+ EarHeap.push(EAR(ep1));
}
- --cnt;
+ --holeSize;
++f;
}
}//is update()
- }//fine del while principale.
-
+ }
+
+ // If the hole had k non manifold vertexes it requires less than n-2 face ( it should be n - 2*(k+1) ),
+ // so we delete the remaining ones.
while(f!=m.face.end()){
tri::Allocator::DeleteFace(m,*f);
f++;
}
-
- VertexType::DeleteBitFlag(nmBit); // non manifoldness bit
}
template
@@ -504,7 +543,7 @@ template
if(cb) (*cb)(indCb*10/vinfo.size(),"Closing Holes");
if((*ith).size < sizeHole){
holeCnt++;
- FillHoleEar< EAR >(m, *ith,facePtrToBeUpdated);
+ FillHoleEar< EAR >(m, (*ith).p,facePtrToBeUpdated);
}
}
return holeCnt;
@@ -555,7 +594,7 @@ template
for(fpi=EAR::AdjacencyRing().begin();fpi!=EAR::AdjacencyRing().end();++fpi)
facePtrToBeUpdated.push_back( &*fpi );
- FillHoleEar(m, *ith,facePtrToBeUpdated);
+ FillHoleEar(m, ith->p,facePtrToBeUpdated);
EAR::AdjacencyRing().clear();
}
}
@@ -671,207 +710,207 @@ template
return false;
}
- static Weight computeWeight( int i, int j, int k,
- std::vector pv,
- std::vector< std::vector< int > > v)
+ static Weight computeWeight( int i, int j, int k,
+ std::vector pv,
+ std::vector< std::vector< int > > v)
+ {
+ PosType pi = pv[i];
+ PosType pj = pv[j];
+ PosType pk = pv[k];
+
+ //test complex edge
+ if(existEdge(pi,pj) || existEdge(pj,pk)|| existEdge(pk,pi) )
+ {
+ return Weight();
+ }
+ // Return an infinite weight, if one of the neighboring patches
+ // could not be created.
+ if(v[i][j] == -1){return Weight();}
+ if(v[j][k] == -1){return Weight();}
+
+ //calcolo il massimo angolo diedrale, se esiste.
+ float angle = 0.0f;
+ PosType px;
+ if(i + 1 == j)
+ {
+ px = pj;
+ px.FlipE(); px.FlipV();
+ angle = std::max(angle , ComputeDihedralAngle(pi.v->P(), pj.v->P(), pk.v->P(), px.v->P()) );
+ }
+ else
+ {
+ angle = std::max( angle, ComputeDihedralAngle(pi.v->P(),pj.v->P(), pk.v->P(), pv[ v[i][j] ].v->P()));
+ }
+
+ if(j + 1 == k)
+ {
+ px = pk;
+ px.FlipE(); px.FlipV();
+ angle = std::max(angle , ComputeDihedralAngle(pj.v->P(), pk.v->P(), pi.v->P(), px.v->P()) );
+ }
+ else
+ {
+ angle = std::max( angle, ComputeDihedralAngle(pj.v->P(),pk.v->P(), pi.v->P(), pv[ v[j][k] ].v->P()));
+ }
+
+ if( i == 0 && k == (int)v.size() - 1)
+ {
+ px = pi;
+ px.FlipE(); px.FlipV();
+ angle = std::max(angle , ComputeDihedralAngle(pk.v->P(), pi.v->P(), pj.v->P(),px.v->P() ) );
+ }
+
+ ScalarType area = ( (pj.v->P() - pi.v->P()) ^ (pk.v->P() - pi.v->P()) ).Norm() * 0.5;
+
+ return Weight(angle, area);
+ }
+
+ static void calculateMinimumWeightTriangulation(MESH &m, FaceIterator f,std::vector vv )
+ {
+ std::vector< std::vector< Weight > > w; //matrice dei pesi minimali di ogni orecchio preso in conzideraione
+ std::vector< std::vector< int > > vi;//memorizza l'indice del terzo vertice del triangolo
+
+ //hole size
+ int nv = vv.size();
+
+ w.clear();
+ w.resize( nv, std::vector( nv, Weight() ) );
+
+ vi.resize( nv, std::vector( nv, 0 ) );
+
+ //inizializzo tutti i pesi possibili del buco
+ for ( int i = 0; i < nv-1; ++i )
+ w[i][i+1] = Weight( 0, 0 );
+
+ //doppio ciclo for per calcolare di tutti i possibili triangoli i loro pesi.
+ for ( int j = 2; j < nv; ++j )
+ {
+ for ( int i = 0; i + j < nv; ++i )
+ {
+ //per ogni triangolazione mi mantengo il minimo valore del peso tra i triangoli possibili
+ Weight minval;
+
+ //indice del vertice che da il peso minimo nella triangolazione corrente
+ int minIndex = -1;
+
+ //ciclo tra i vertici in mezzo a i due prefissati
+ for ( int m = i + 1; m < i + j; ++m )
{
- PosType pi = pv[i];
- PosType pj = pv[j];
- PosType pk = pv[k];
-
- //test complex edge
- if(existEdge(pi,pj) || existEdge(pj,pk)|| existEdge(pk,pi) )
- {
- return Weight();
- }
- // Return an infinite weight, if one of the neighboring patches
- // could not be created.
- if(v[i][j] == -1){return Weight();}
- if(v[j][k] == -1){return Weight();}
-
- //calcolo il massimo angolo diedrale, se esiste.
- float angle = 0.0f;
- PosType px;
- if(i + 1 == j)
- {
- px = pj;
- px.FlipE(); px.FlipV();
- angle = std::max(angle , ComputeDihedralAngle(pi.v->P(), pj.v->P(), pk.v->P(), px.v->P()) );
- }
- else
- {
- angle = std::max( angle, ComputeDihedralAngle(pi.v->P(),pj.v->P(), pk.v->P(), pv[ v[i][j] ].v->P()));
- }
-
- if(j + 1 == k)
- {
- px = pk;
- px.FlipE(); px.FlipV();
- angle = std::max(angle , ComputeDihedralAngle(pj.v->P(), pk.v->P(), pi.v->P(), px.v->P()) );
- }
- else
- {
- angle = std::max( angle, ComputeDihedralAngle(pj.v->P(),pk.v->P(), pi.v->P(), pv[ v[j][k] ].v->P()));
- }
-
- if( i == 0 && k == (int)v.size() - 1)
- {
- px = pi;
- px.FlipE(); px.FlipV();
- angle = std::max(angle , ComputeDihedralAngle(pk.v->P(), pi.v->P(), pj.v->P(),px.v->P() ) );
- }
-
- ScalarType area = ( (pj.v->P() - pi.v->P()) ^ (pk.v->P() - pi.v->P()) ).Norm() * 0.5;
-
- return Weight(angle, area);
+ Weight a = w[i][m];
+ Weight b = w[m][i+j];
+ Weight newval = a + b + computeWeight( i, m, i+j, vv, vi);
+ if ( newval < minval )
+ {
+ minval = newval;
+ minIndex = m;
+ }
}
-
- static void calculateMinimumWeightTriangulation(MESH &m, FaceIterator f,std::vector vv )
- {
- std::vector< std::vector< Weight > > w; //matrice dei pesi minimali di ogni orecchio preso in conzideraione
- std::vector< std::vector< int > > vi;//memorizza l'indice del terzo vertice del triangolo
-
- //hole size
- int nv = vv.size();
-
- w.clear();
- w.resize( nv, std::vector( nv, Weight() ) );
-
- vi.resize( nv, std::vector( nv, 0 ) );
-
- //inizializzo tutti i pesi possibili del buco
- for ( int i = 0; i < nv-1; ++i )
- w[i][i+1] = Weight( 0, 0 );
-
- //doppio ciclo for per calcolare di tutti i possibili triangoli i loro pesi.
- for ( int j = 2; j < nv; ++j )
- {
- for ( int i = 0; i + j < nv; ++i )
- {
- //per ogni triangolazione mi mantengo il minimo valore del peso tra i triangoli possibili
- Weight minval;
-
- //indice del vertice che da il peso minimo nella triangolazione corrente
- int minIndex = -1;
-
- //ciclo tra i vertici in mezzo a i due prefissati
- for ( int m = i + 1; m < i + j; ++m )
- {
- Weight a = w[i][m];
- Weight b = w[m][i+j];
- Weight newval = a + b + computeWeight( i, m, i+j, vv, vi);
- if ( newval < minval )
- {
- minval = newval;
- minIndex = m;
- }
- }
- w[i][i+j] = minval;
- vi[i][i+j] = minIndex;
- }
- }
-
- //Triangulate
- int i, j;
- i=0; j=nv-1;
-
- triangulate(m,f, i, j, vi, vv);
-
- while(f!=m.face.end())
- {
- (*f).SetD();
- ++f;
- m.fn--;
- }
- }
-
-
- static void triangulate(MESH &m, FaceIterator &f,int i, int j,
+ w[i][i+j] = minval;
+ vi[i][i+j] = minIndex;
+ }
+ }
+
+ //Triangulate
+ int i, j;
+ i=0; j=nv-1;
+
+ triangulate(m,f, i, j, vi, vv);
+
+ while(f!=m.face.end())
+ {
+ (*f).SetD();
+ ++f;
+ m.fn--;
+ }
+ }
+
+
+ static void triangulate(MESH &m, FaceIterator &f,int i, int j,
std::vector< std::vector > vi, std::vector vv)
- {
- if(i + 1 == j){return;}
- if(i==j)return;
-
- int k = vi[i][j];
-
- if(k == -1) return;
-
- //Setto i vertici
- f->V(0) = vv[i].v;
- f->V(1) = vv[k].v;
- f->V(2) = vv[j].v;
-
- f++;
- triangulate(m,f,i,k,vi,vv);
- triangulate(m,f,k,j,vi,vv);
- }
-
+ {
+ if(i + 1 == j){return;}
+ if(i==j)return;
+
+ int k = vi[i][j];
+
+ if(k == -1) return;
+
+ //Setto i vertici
+ f->V(0) = vv[i].v;
+ f->V(1) = vv[k].v;
+ f->V(2) = vv[j].v;
+
+ f++;
+ triangulate(m,f,i,k,vi,vv);
+ triangulate(m,f,k,j,vi,vv);
+ }
+
static void MinimumWeightFill(MESH &m, int holeSize, bool Selected)
- {
- std::vector vvi;
- std::vector vfp;
-
- std::vector vinfo;
- typename std::vector::iterator VIT;
- GetInfo(m, Selected,vinfo);
-
- for(VIT = vinfo.begin(); VIT != vinfo.end();++VIT)
- {
- vvi.push_back(VIT->p);
- }
-
- typename std::vector::iterator ith;
- typename std::vector::iterator ithn;
- typename std::vector::iterator itf;
-
- std::vector app;
- PosType ps;
- std::vector tr;
- std::vector vf;
-
- for(ith = vvi.begin(); ith!= vvi.end(); ++ith)
- {
- tr.clear();
- vf.clear();
- app.clear();
- vfp.clear();
-
- ps = *ith;
- getBoundHole(ps,app);
-
- if(app.size() <= size_t(holeSize) )
- {
- typename std::vector::iterator itP;
- std::vector vfp;
-
- for(ithn = vvi.begin(); ithn!= vvi.end(); ++ithn)
- vfp.push_back(&(ithn->f));
-
- for(itP = app.begin (); itP != app.end ();++itP)
- vfp.push_back( &(*itP).f );
-
- //aggiungo le facce
- FaceIterator f = tri::Allocator::AddFaces(m, (app.size()-2) , vfp);
-
- calculateMinimumWeightTriangulation(m,f, app);
- }
- }
-
- }
-
- static void getBoundHole (PosType sp,std::vector&ret)
- {
- PosType fp = sp;
- //take vertex around the hole
- do
- {
- assert(fp.IsBorder());
- ret.push_back(fp);
- fp.NextB();
- }while(sp != fp);
- }
-
-};//close class Hole
+ {
+ std::vector vvi;
+ std::vector vfp;
+
+ std::vector vinfo;
+ typename std::vector::iterator VIT;
+ GetInfo(m, Selected,vinfo);
+
+ for(VIT = vinfo.begin(); VIT != vinfo.end();++VIT)
+ {
+ vvi.push_back(VIT->p);
+ }
+
+ typename std::vector::iterator ith;
+ typename std::vector::iterator ithn;
+ typename std::vector::iterator itf;
+
+ std::vector app;
+ PosType ps;
+ std::vector tr;
+ std::vector vf;
+
+ for(ith = vvi.begin(); ith!= vvi.end(); ++ith)
+ {
+ tr.clear();
+ vf.clear();
+ app.clear();
+ vfp.clear();
+
+ ps = *ith;
+ getBoundHole(ps,app);
+
+ if(app.size() <= size_t(holeSize) )
+ {
+ typename std::vector::iterator itP;
+ std::vector vfp;
+
+ for(ithn = vvi.begin(); ithn!= vvi.end(); ++ithn)
+ vfp.push_back(&(ithn->f));
+
+ for(itP = app.begin (); itP != app.end ();++itP)
+ vfp.push_back( &(*itP).f );
+
+ //aggiungo le facce
+ FaceIterator f = tri::Allocator::AddFaces(m, (app.size()-2) , vfp);
+
+ calculateMinimumWeightTriangulation(m,f, app);
+ }
+ }
+
+ }
+
+ static void getBoundHole (PosType sp,std::vector&ret)
+ {
+ PosType fp = sp;
+ //take vertex around the hole
+ do
+ {
+ assert(fp.IsBorder());
+ ret.push_back(fp);
+ fp.NextB();
+ }while(sp != fp);
+ }
+
+};// class Hole
} // end namespace tri
} // end namespace vcg
diff --git a/vcg/complex/algorithms/local_optimization.h b/vcg/complex/algorithms/local_optimization.h
index e80a8bbb..b86edc35 100644
--- a/vcg/complex/algorithms/local_optimization.h
+++ b/vcg/complex/algorithms/local_optimization.h
@@ -20,83 +20,11 @@
* for more details. *
* *
****************************************************************************/
-/****************************************************************************
- $Log: not supported by cvs2svn $
- Revision 1.20 2007/01/19 09:13:09 cignoni
- Added Finalize() method to the interface
-
- Revision 1.19 2007/01/11 11:48:33 ganovelli
- currMetric inizialied to heap.front() (it was heap.back()- wrong)
-
- Revision 1.18 2006/12/11 14:09:44 ganovelli
- added missing initialization of currMetric
-
- Revision 1.17 2006/06/09 07:28:43 m_di_benedetto
- Corrected ClearHeap(): iterator "hi" not decrementable if it was the first of the container.
-
- Revision 1.16 2005/11/10 15:38:46 cignoni
- Added casts to remove warnings
-
- Revision 1.15 2005/10/02 23:23:52 cignoni
- Changed the sense of the < operator for heap: it is reversed according to the stl where highest score elements must float in the heap
- Completed TimeBudget Termination condition.
- Parametrized the ClearHeap procedure now there is a HeapSimplexRatio param. Removed dirty printf.
-
- Revision 1.14 2005/04/14 11:34:33 ponchio
- *** empty log message ***
-
- Revision 1.13 2005/01/19 10:33:50 cignoni
- Improved ClearHeap management
-
- Revision 1.12 2004/12/10 01:02:48 cignoni
- added an inline and removed loggng
-
- Revision 1.11 2004/12/03 21:14:39 ponchio
- Fixed memory leak...
-
- Revision 1.10 2004/11/23 10:37:17 cignoni
- Added a member with a cached copy of the floating Priority() value inside the HeapElem to optimize operator< in heap updating operator
-
- Revision 1.9 2004/11/05 10:03:47 fiorin
- Added ModifierType::TriEdgeFlipOp
-
- Revision 1.8 2004/10/25 07:02:56 ganovelli
- some inline function, logs on file (precompiler directive)
-
- Revision 1.7 2004/09/29 17:08:39 ganovelli
- changed > to < in heapelem comparison
-
- Revision 1.6 2004/09/28 09:57:08 cignoni
- Better Doxygen docs
-
- Revision 1.5 2004/09/15 10:40:20 ponchio
- typedef LocalOptimization HeapType -> public:
-
- Revision 1.4 2004/09/08 15:10:59 ganovelli
- *** empty log message ***
-
- Revision 1.3 2004/07/27 09:46:15 cignoni
- First working version of the LocalOptimization/Simplification Framework
-
- Revision 1.1 2004/07/15 12:04:14 ganovelli
- minor changes
-
- Revision 1.2 2004/07/09 10:22:56 ganovelli
- working draft
-
- Revision 1.1 2004/07/08 08:25:15 ganovelli
- first draft
-
-****************************************************************************/
#ifndef __VCGLIB_LOCALOPTIMIZATION
#define __VCGLIB_LOCALOPTIMIZATION
-#include
-#include
-#include
-#include
-#include
-
+#include
+#include
namespace vcg{
// Base class for Parameters
// all parameters must be derived from this.
diff --git a/vcg/complex/algorithms/local_optimization/tri_edge_collapse_quadric.h b/vcg/complex/algorithms/local_optimization/tri_edge_collapse_quadric.h
index 3b2791bb..eb6b86b1 100644
--- a/vcg/complex/algorithms/local_optimization/tri_edge_collapse_quadric.h
+++ b/vcg/complex/algorithms/local_optimization/tri_edge_collapse_quadric.h
@@ -78,7 +78,7 @@ namespace tri{
static void Init(){}
static math::Quadric &Qd(VERTEX_TYPE &v) {return v.Qd();}
static math::Quadric &Qd(VERTEX_TYPE *v) {return v->Qd();}
- static typename VERTEX_TYPE::ScalarType W(VERTEX_TYPE */*v*/) {return 1.0;}
+ static typename VERTEX_TYPE::ScalarType W(VERTEX_TYPE * /*v*/) {return 1.0;}
static typename VERTEX_TYPE::ScalarType W(VERTEX_TYPE &/*v*/) {return 1.0;}
static void Merge(VERTEX_TYPE & /*v_dest*/, VERTEX_TYPE const & /*v_del*/){}
};
diff --git a/vcg/complex/algorithms/local_optimization/tri_edge_flip.h b/vcg/complex/algorithms/local_optimization/tri_edge_flip.h
index 53d3c5ed..29f26b5f 100644
--- a/vcg/complex/algorithms/local_optimization/tri_edge_flip.h
+++ b/vcg/complex/algorithms/local_optimization/tri_edge_flip.h
@@ -284,7 +284,7 @@ public:
const char* Info(TRIMESH_TYPE &m)
{
static char dump[60];
- sprintf(dump,"%lu -> %lu %g\n", tri::Index(m,_pos.F()->V(0)), tri::Index(m,_pos.F()->V(1)),-_priority);
+ sprintf(dump,"%zu -> %zu %g\n", tri::Index(m,_pos.F()->V(0)), tri::Index(m,_pos.F()->V(1)),-_priority);
return dump;
}
diff --git a/vcg/complex/algorithms/mesh_assert.h b/vcg/complex/algorithms/mesh_assert.h
index f469e38c..09632022 100644
--- a/vcg/complex/algorithms/mesh_assert.h
+++ b/vcg/complex/algorithms/mesh_assert.h
@@ -104,6 +104,13 @@ public:
}
}
+ static void OnlyEdgeMesh(MeshType &m)
+ {
+ if(m.FN()>0)
+ throw vcg::MissingPreconditionException("Expecting a mesh composed only by edges (no faces needed or allowed)");
+ }
+
+
};
} // end namespace tri
diff --git a/vcg/complex/algorithms/parametrization/tangent_field_operators.h b/vcg/complex/algorithms/parametrization/tangent_field_operators.h
index 0ed1caf6..3da1a33a 100644
--- a/vcg/complex/algorithms/parametrization/tangent_field_operators.h
+++ b/vcg/complex/algorithms/parametrization/tangent_field_operators.h
@@ -666,7 +666,7 @@ public:
CoordType dirR=vcg::tri::CrossField::Rotate(f0,f1,dir0);
///then get the closest upf to K*PI/2 rotations
CoordType dir1=f1.cPD1();
- CoordType ret=vcg::tri::CrossField::K_PI(dirR,dir1,f1.cN());
+ CoordType ret=vcg::tri::CrossField::K_PI(dir1,dirR,f1.cN());
return ret;
}
diff --git a/vcg/complex/algorithms/point_sampling.h b/vcg/complex/algorithms/point_sampling.h
index a101653e..f7275dfc 100644
--- a/vcg/complex/algorithms/point_sampling.h
+++ b/vcg/complex/algorithms/point_sampling.h
@@ -105,6 +105,11 @@ private:
std::vector *sampleVec;
bool vectorOwner;
public:
+
+ std::vector &SampleVec()
+ {
+ return *sampleVec;
+ }
void AddVert(const VertexType &p)
{
@@ -839,11 +844,11 @@ static void EdgeMeshUniform(MeshType &m, VertexSampler &ps, float radius, bool c
/// \brief Sample all the border corner vertices
///
/// It assumes that the border flag have been set over the mesh both for vertex and for faces.
-/// All the vertices on the border where the surface forms an angle smaller than the given threshold are sampled.
+/// All the vertices on the border where the edges of the boundary of the surface forms an angle smaller than the given threshold are sampled.
///
static void VertexBorderCorner(MeshType & m, VertexSampler &ps, float angleRad)
{
- typename MeshType::template PerVertexAttributeHandle angleSumH = tri::Allocator:: template GetPerVertexAttribute (m);
+ typename MeshType::template PerVertexAttributeHandle angleSumH = tri::Allocator:: template GetPerVertexAttribute (m);
for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
angleSumH[vi]=0;
@@ -1846,9 +1851,14 @@ static void PoissonDiskPruningByNumber(VertexSampler &ps, MeshType &m,
/// This is the main function that is used to build a poisson distribuition
-/// starting from a dense sample cloud.
-/// Trivial approach that puts all the samples in a hashed UG and randomly choose a sample
+/// starting from a dense sample cloud (the montecarloMesh) by 'pruning' it.
+/// it puts all the samples in a hashed UG and randomly choose a sample
/// and remove all the points in the sphere centered on the chosen sample
+///
+/// You can impose some constraint: all the vertices in the montecarloMesh
+/// that are marked with a bool attribute called "fixed" are surely chosen
+/// (if you also set the preGenFlag option)
+///
static void PoissonDiskPruning(VertexSampler &ps, MeshType &montecarloMesh,
ScalarType diskRadius, PoissonDiskParam &pp)
{
@@ -2256,18 +2266,18 @@ void PoissonPruning(MeshType &m, // the mesh that has to be pruned
/// \brief Low level wrapper for Poisson Disk Pruning
///
-/// This function simply takes a mesh and a radius and returns a vector
-/// of vertex pointers listing the "surviving" points.
-//
+/// This function simply takes a mesh containing a point cloud to be pruned and a radius
+/// It returns a vector of CoordType listing the "surviving" points.
+///
template
void PoissonPruning(MeshType &m, // the mesh that has to be pruned
- std::vector