Merge branch 'devel'
This commit is contained in:
commit
a8e87662b6
|
|
@ -6,3 +6,7 @@ debug/
|
||||||
release/
|
release/
|
||||||
*-debug/
|
*-debug/
|
||||||
*-release/
|
*-release/
|
||||||
|
/docs/Doxygen/html/
|
||||||
|
|
||||||
|
# Intermediate Files
|
||||||
|
*.bc
|
||||||
|
|
@ -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
|
Visual and Computer Graphics Library o o
|
||||||
_ O _
|
_ O _
|
||||||
Copyright(C) 2005-2006 \/)\/
|
Copyright(C) 2005-2006 \/)\/
|
||||||
|
|
@ -31,14 +31,10 @@ Please, when using this tool, cite the following reference:
|
||||||
P. Cignoni, C. Rocchini and R. Scopigno
|
P. Cignoni, C. Rocchini and R. Scopigno
|
||||||
"Metro: measuring error on simplified surfaces"
|
"Metro: measuring error on simplified surfaces"
|
||||||
Computer Graphics Forum, Blackwell Publishers, vol. 17(2), June 1998, pp 167-174
|
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:
|
For any question about this software please contact:
|
||||||
Paolo Cignoni ( p.cignoni@isti.cnr.it )
|
Paolo Cignoni ( paolo.cignoni@isti.cnr.it )
|
||||||
|
|
||||||
--- General Info ---
|
--- General Info ---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
Visual and Computer Graphics Library o o
|
||||||
_ O _
|
_ O _
|
||||||
Copyright(C) 2005-2006 \/)\/
|
Copyright(C) 2005-2006 \/)\/
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,6 @@ void Usage()
|
||||||
"---------------------------------\n"
|
"---------------------------------\n"
|
||||||
" TriDecimator 1.0 \n"
|
" TriDecimator 1.0 \n"
|
||||||
" http://vcg.isti.cnr.it\n"
|
" http://vcg.isti.cnr.it\n"
|
||||||
" http://vcg.sourceforge.net\n"
|
|
||||||
" release date: " __DATE__
|
" release date: " __DATE__
|
||||||
"\n---------------------------------\n\n"
|
"\n---------------------------------\n\n"
|
||||||
"Copyright 2003-2016 Visual Computing Lab I.S.T.I. C.N.R.\n"
|
"Copyright 2003-2016 Visual Computing Lab I.S.T.I. C.N.R.\n"
|
||||||
|
|
|
||||||
|
|
@ -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
|
Visual and Computer Graphics Library o o
|
||||||
_ O _
|
_ O _
|
||||||
Copyright(C) 2004-2006 \/)\/
|
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.
|
TriMeshInfo is written in C++ and makes use of the VCG library.
|
||||||
The tool supports the following file formats:
|
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)
|
- OFF (http://www.geomview.org/docs/html/geomview_41.html#SEC44)
|
||||||
- STL (http://astronomy.swin.edu.au/~pbourke/dataformats/stl/)
|
- STL (http://astronomy.swin.edu.au/~pbourke/dataformats/stl/)
|
||||||
- OBJ (http://www.eg-models.de/formats/Format_Obj.html)
|
- OBJ (http://www.eg-models.de/formats/Format_Obj.html)
|
||||||
|
|
|
||||||
|
|
@ -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
|
Visual and Computer Graphics Library o o
|
||||||
_ O _
|
_ O _
|
||||||
Copyright(C) 2004-2005 \/)\/
|
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.
|
The application works under both Windows and Linux/Unix platforms.
|
||||||
|
|
||||||
TriMeshInfo is written in C++ and makes use of the VCL library.
|
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
|
The tool supports two file formats ply and off (as described in http://www.geomview.org/docs/html/geomview_41.html#SEC44) .
|
||||||
http://vcg.sourceforge.net/img/wiki_up/plyformat.pdf)
|
|
||||||
and off (as described in http://www.geomview.org/docs/html/geomview_41.html#SEC44) .
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
Visual and Computer Graphics Library o o
|
||||||
_ O _
|
_ O _
|
||||||
Copyright(C) 2004-2005 \/)\/
|
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.
|
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.
|
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
|
The tool supports two file formats ply and off (as described in http://www.geomview.org/docs/html/geomview_41.html#SEC44) .
|
||||||
http://vcg.sourceforge.net/img/wiki_up/plyformat.pdf)
|
|
||||||
and off (as described in http://www.geomview.org/docs/html/geomview_41.html#SEC44) .
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
/** \page attributes
|
/** \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.
|
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".
|
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
|
\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).
|
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).
|
||||||
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.
|
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
|
\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.
|
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
|
\snippet trimesh_attribute.cpp Per Mesh attribute
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/** \page basic_concepts
|
/** \page basic_concepts Basic Concepts
|
||||||
How to define a mesh type
|
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:
|
||||||
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:
|
|
||||||
|
|
||||||
\dontinclude trimesh_base.cpp
|
\dontinclude trimesh_base.cpp
|
||||||
\skip MyMesh
|
\skip MyMesh
|
||||||
|
|
@ -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
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/** \page fileformat
|
/** \page fileformat File Formats
|
||||||
File Formats
|
File Formats
|
||||||
============
|
============
|
||||||
VCGLib provides importer and exporter for several file formats
|
VCGLib provides importer and exporter for several file formats
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,9 @@ This module contains the documentation for the types and the functions used for
|
||||||
/** \defgroup code_sample Code Examples
|
/** \defgroup code_sample Code Examples
|
||||||
\brief This module contains a number of small examples to explain the library features
|
\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
|
All the examples here listed are located in the folder `vcglib/apps/sample`.
|
||||||
Each sample has a minimal '.pro' file
|
To compile each sample, please use the corresponding `qmake` `*.pro` project files.
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ The Visualization and Computer Graphics Library (VCG for short) is
|
||||||
a open source portable C++ templated library for manipulation, processing
|
a open source portable C++ templated library for manipulation, processing
|
||||||
and displaying with OpenGL of triangle and tetrahedral meshes.
|
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,
|
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
|
is released under the GPL license, and it is the base of most of the
|
||||||
software tools of the <b>Visual Computing Lab</b> of the Italian National Research Council Institute ISTI
|
software tools of the <b>Visual Computing Lab</b> of the Italian National Research Council Institute ISTI
|
||||||
|
|
@ -11,7 +13,7 @@ software tools of the <b>Visual Computing Lab</b> of the Italian National Resear
|
||||||
|
|
||||||
The VCG library is tailored to mostly manage triangular meshes:
|
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:
|
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, ...) ,
|
- efficient spatial query structures (uniform grids, hashed grids, kdtree, ...) ,
|
||||||
- advanced smoothing and fairing algorithms,
|
- advanced smoothing and fairing algorithms,
|
||||||
- computation of curvature,
|
- computation of curvature,
|
||||||
|
|
@ -41,7 +43,7 @@ Start from the following pages for basic concepts and examples.
|
||||||
Notable Applications
|
Notable Applications
|
||||||
-------
|
-------
|
||||||
A number of applications have been developed using the vcglib:
|
A number of applications have been developed using the vcglib:
|
||||||
- <a href="http://meshlab.sourceforge.net">MeshLab</a>: the renowed open source mesh processing is based on this library.
|
- <a href="http://www.meshlab.net">MeshLab</a>: the renowned open source mesh processing is based on this library.
|
||||||
- \subpage metro "Metro, the tool for measuring differences between meshes"
|
- \subpage metro "Metro, the tool for measuring differences between meshes"
|
||||||
- The first high quality <a href="http://dl.acm.org/citation.cfm?id=940008"> out-of-core mesh simplifier </a> that was used by the Stanford Digital Michelangelo project to process their huge 3D scanned models.
|
- The first high quality <a href="http://dl.acm.org/citation.cfm?id=940008"> out-of-core mesh simplifier </a> that was used by the Stanford Digital Michelangelo project to process their huge 3D scanned models.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,33 +3,28 @@
|
||||||
Installation and folder structure
|
Installation and folder structure
|
||||||
================
|
================
|
||||||
|
|
||||||
VCG Lib uses a SVN repository hosted by sourceforge.
|
VCG Lib uses a git repository hosted by github.
|
||||||
The main project page of the library is http://sourceforge.net/projects/vcg/
|
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
|
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.
|
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:
|
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.
|
- `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..
|
- `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)
|
- `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.
|
- `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/
|
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -79,8 +79,6 @@ public:
|
||||||
mp=&m;
|
mp=&m;
|
||||||
while(!sf.empty()) sf.pop();
|
while(!sf.empty()) sf.pop();
|
||||||
UnMarkAll(m);
|
UnMarkAll(m);
|
||||||
assert(p);
|
|
||||||
assert(!p->IsD());
|
|
||||||
tri::Mark(m,p);
|
tri::Mark(m,p);
|
||||||
sf.push(p);
|
sf.push(p);
|
||||||
}
|
}
|
||||||
|
|
@ -272,7 +270,6 @@ public:
|
||||||
tri::Index(m,(*fi).V(2)),
|
tri::Index(m,(*fi).V(2)),
|
||||||
&*fi));
|
&*fi));
|
||||||
}
|
}
|
||||||
assert (size_t(m.fn) == fvec.size());
|
|
||||||
std::sort(fvec.begin(),fvec.end());
|
std::sort(fvec.begin(),fvec.end());
|
||||||
int total=0;
|
int total=0;
|
||||||
for(int i=0;i<int(fvec.size())-1;++i)
|
for(int i=0;i<int(fvec.size())-1;++i)
|
||||||
|
|
@ -300,8 +297,6 @@ public:
|
||||||
{
|
{
|
||||||
eVec.push_back(SortedPair( tri::Index(m,(*ei).V(0)), tri::Index(m,(*ei).V(1)), &*ei));
|
eVec.push_back(SortedPair( tri::Index(m,(*ei).V(0)), tri::Index(m,(*ei).V(1)), &*ei));
|
||||||
}
|
}
|
||||||
assert (size_t(m.en) == eVec.size());
|
|
||||||
//for(int i=0;i<fvec.size();++i) qDebug("fvec[%i] = (%i %i %i)(%i)",i,fvec[i].v[0],fvec[i].v[1],fvec[i].v[2],tri::Index(m,fvec[i].fp));
|
|
||||||
std::sort(eVec.begin(),eVec.end());
|
std::sort(eVec.begin(),eVec.end());
|
||||||
int total=0;
|
int total=0;
|
||||||
for(int i=0;i<int(eVec.size())-1;++i)
|
for(int i=0;i<int(eVec.size())-1;++i)
|
||||||
|
|
@ -310,7 +305,6 @@ public:
|
||||||
{
|
{
|
||||||
total++;
|
total++;
|
||||||
tri::Allocator<MeshType>::DeleteEdge(m, *(eVec[i].fp) );
|
tri::Allocator<MeshType>::DeleteEdge(m, *(eVec[i].fp) );
|
||||||
//qDebug("deleting face %i (pos in fvec %i)",tri::Index(m,fvec[i].fp) ,i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
|
|
@ -440,12 +434,10 @@ public:
|
||||||
CountNonManifoldVertexFF(m,true);
|
CountNonManifoldVertexFF(m,true);
|
||||||
tri::UpdateSelection<MeshType>::FaceFromVertexLoose(m);
|
tri::UpdateSelection<MeshType>::FaceFromVertexLoose(m);
|
||||||
int count_removed = 0;
|
int count_removed = 0;
|
||||||
FaceIterator fi;
|
for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi)
|
||||||
for(fi=m.face.begin(); fi!=m.face.end();++fi)
|
|
||||||
if(!(*fi).IsD() && (*fi).IsS())
|
if(!(*fi).IsD() && (*fi).IsS())
|
||||||
Allocator<MeshType>::DeleteFace(m,*fi);
|
Allocator<MeshType>::DeleteFace(m,*fi);
|
||||||
VertexIterator vi;
|
for(VertexIterator vi=m.vert.begin(); vi!=m.vert.end();++vi)
|
||||||
for(vi=m.vert.begin(); vi!=m.vert.end();++vi)
|
|
||||||
if(!(*vi).IsD() && (*vi).IsS()) {
|
if(!(*vi).IsD() && (*vi).IsS()) {
|
||||||
++count_removed;
|
++count_removed;
|
||||||
Allocator<MeshType>::DeleteVertex(m,*vi);
|
Allocator<MeshType>::DeleteVertex(m,*vi);
|
||||||
|
|
@ -631,22 +623,15 @@ public:
|
||||||
return count_fd;
|
return count_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Remove the faces that are out of a given range of area */
|
||||||
The following functions remove faces that are geometrically "bad" according to edges and area criteria.
|
static int RemoveFaceOutOfRangeArea(MeshType& m, ScalarType MinAreaThr=0, ScalarType MaxAreaThr=(std::numeric_limits<ScalarType>::max)(), bool OnlyOnSelected=false)
|
||||||
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<bool Selected>
|
|
||||||
static int RemoveFaceOutOfRangeAreaSel(MeshType& m, ScalarType MinAreaThr=0, ScalarType MaxAreaThr=(std::numeric_limits<ScalarType>::max)())
|
|
||||||
{
|
{
|
||||||
FaceIterator fi;
|
|
||||||
int count_fd = 0;
|
int count_fd = 0;
|
||||||
MinAreaThr*=2;
|
MinAreaThr*=2;
|
||||||
MaxAreaThr*=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(!(*fi).IsD())
|
||||||
if(!Selected || (*fi).IsS())
|
if(!OnlyOnSelected || (*fi).IsS())
|
||||||
{
|
{
|
||||||
const ScalarType doubleArea=DoubleArea<FaceType>(*fi);
|
const ScalarType doubleArea=DoubleArea<FaceType>(*fi);
|
||||||
if((doubleArea<=MinAreaThr) || (doubleArea>=MaxAreaThr) )
|
if((doubleArea<=MinAreaThr) || (doubleArea>=MaxAreaThr) )
|
||||||
|
|
@ -655,17 +640,13 @@ public:
|
||||||
count_fd++;
|
count_fd++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return count_fd;
|
return count_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// alias for the old style. Kept for backward compatibility
|
static int RemoveZeroAreaFace(MeshType& m) { return RemoveFaceOutOfRangeArea(m,0);}
|
||||||
static int RemoveZeroAreaFace(MeshType& m) { return RemoveFaceOutOfRangeArea(m);}
|
|
||||||
|
|
||||||
// Aliases for the functions that do not look at selection
|
|
||||||
static int RemoveFaceOutOfRangeArea(MeshType& m, ScalarType MinAreaThr=0, ScalarType MaxAreaThr=(std::numeric_limits<ScalarType>::max)())
|
|
||||||
{
|
|
||||||
return RemoveFaceOutOfRangeAreaSel<false>(m,MinAreaThr,MaxAreaThr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the mesh only composed by quadrilaterals?
|
* Is the mesh only composed by quadrilaterals?
|
||||||
|
|
@ -850,7 +831,7 @@ public:
|
||||||
*/
|
*/
|
||||||
static int CountNonManifoldEdgeEE( MeshType & m, bool SelectFlag=false)
|
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<MeshType>::OnlyEdgeMesh(m);
|
||||||
RequireEEAdjacency(m);
|
RequireEEAdjacency(m);
|
||||||
tri::UpdateTopology<MeshType>::EdgeEdge(m);
|
tri::UpdateTopology<MeshType>::EdgeEdge(m);
|
||||||
|
|
||||||
|
|
@ -1031,61 +1012,27 @@ public:
|
||||||
|
|
||||||
static int CountHoles( MeshType & m)
|
static int CountHoles( MeshType & m)
|
||||||
{
|
{
|
||||||
int numholev=0;
|
UpdateFlags<MeshType>::FaceClearV(m);
|
||||||
FaceIterator fi;
|
int loopNum=0;
|
||||||
|
for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi) if(!fi->IsD())
|
||||||
FaceIterator gi;
|
|
||||||
vcg::face::Pos<FaceType> he;
|
|
||||||
vcg::face::Pos<FaceType> hei;
|
|
||||||
|
|
||||||
std::vector< std::vector<CoordType> > holes; //indices of vertices
|
|
||||||
|
|
||||||
vcg::tri::UpdateFlags<MeshType>::VertexClearS(m);
|
|
||||||
|
|
||||||
gi=m.face.begin(); fi=gi;
|
|
||||||
|
|
||||||
for(fi=m.face.begin();fi!=m.face.end();fi++)//for all faces do
|
|
||||||
{
|
{
|
||||||
for(int j=0;j<3;j++)//for all edges
|
for(int j=0;j<3;++j)
|
||||||
{
|
{
|
||||||
if(fi->V(j)->IsS()) continue;
|
if(!fi->IsV() && face::IsBorder(*fi,j))
|
||||||
|
|
||||||
if(face::IsBorder(*fi,j))//found an unvisited border edge
|
|
||||||
{
|
{
|
||||||
he.Set(&(*fi),j,fi->V(j)); //set the face-face iterator to the current face, edge and vertex
|
face::Pos<FaceType> startPos(&*fi,j);
|
||||||
std::vector<CoordType> hole; //start of a new hole
|
face::Pos<FaceType> curPos=startPos;
|
||||||
hole.push_back(fi->P(j)); // including the first vertex
|
do
|
||||||
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.
|
|
||||||
{
|
{
|
||||||
CoordType newpoint = he.v->P(); //select its vertex.
|
curPos.NextB();
|
||||||
if(he.v->IsS())//check if this vertex was selected already, because then we have an additional hole.
|
curPos.F()->SetV();
|
||||||
{
|
|
||||||
//cut and paste the additional hole.
|
|
||||||
std::vector<CoordType> hole2;
|
|
||||||
int index = static_cast<int>(find(hole.begin(),hole.end(),newpoint)
|
|
||||||
- hole.begin());
|
|
||||||
for(unsigned int i=index; i<hole.size(); i++)
|
|
||||||
hole2.push_back(hole[i]);
|
|
||||||
|
|
||||||
hole.resize(index);
|
|
||||||
if(hole2.size()!=0) //annoying in degenerate cases
|
|
||||||
holes.push_back(hole2);
|
|
||||||
}
|
}
|
||||||
hole.push_back(newpoint);
|
while(curPos!=startPos);
|
||||||
numholev++;
|
++loopNum;
|
||||||
he.v->SetS(); //set the current vertex as selected
|
|
||||||
he.NextB(); //go to the next boundary edge
|
|
||||||
}
|
|
||||||
holes.push_back(hole);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return static_cast<int>(holes.size());
|
return loopNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1102,14 +1049,14 @@ public:
|
||||||
{
|
{
|
||||||
tri::RequireFFAdjacency(m);
|
tri::RequireFFAdjacency(m);
|
||||||
CCV.clear();
|
CCV.clear();
|
||||||
tri::UpdateSelection<MeshType>::FaceClear(m);
|
tri::UpdateFlags<MeshType>::FaceClearV(m);
|
||||||
std::stack<FacePointer> sf;
|
std::stack<FacePointer> sf;
|
||||||
FacePointer fpt=&*(m.face.begin());
|
FacePointer fpt=&*(m.face.begin());
|
||||||
for(FaceIterator 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())
|
if(!((*fi).IsD()) && !(*fi).IsV())
|
||||||
{
|
{
|
||||||
(*fi).SetS();
|
(*fi).SetV();
|
||||||
CCV.push_back(std::make_pair(0,&*fi));
|
CCV.push_back(std::make_pair(0,&*fi));
|
||||||
sf.push(&*fi);
|
sf.push(&*fi);
|
||||||
while (!sf.empty())
|
while (!sf.empty())
|
||||||
|
|
@ -1122,9 +1069,9 @@ public:
|
||||||
if( !face::IsBorder(*fpt,j) )
|
if( !face::IsBorder(*fpt,j) )
|
||||||
{
|
{
|
||||||
FacePointer l = fpt->FFp(j);
|
FacePointer l = fpt->FFp(j);
|
||||||
if( !(*l).IsS() )
|
if( !(*l).IsV() )
|
||||||
{
|
{
|
||||||
(*l).SetS();
|
(*l).SetV();
|
||||||
sf.push(l);
|
sf.push(l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1260,6 +1207,8 @@ public:
|
||||||
|
|
||||||
static bool IsCoherentlyOrientedMesh(MeshType &m)
|
static bool IsCoherentlyOrientedMesh(MeshType &m)
|
||||||
{
|
{
|
||||||
|
RequireFFAdjacency(m);
|
||||||
|
MeshAssert<MeshType>::FFAdjacencyIsInitialized(m);
|
||||||
for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
|
for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
|
||||||
if (!fi->IsD())
|
if (!fi->IsD())
|
||||||
for(int i=0;i<3;++i)
|
for(int i=0;i<3;++i)
|
||||||
|
|
@ -1269,26 +1218,22 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OrientCoherentlyMesh(MeshType &m, bool &Oriented, bool &Orientable)
|
static void OrientCoherentlyMesh(MeshType &m, bool &_IsOriented, bool &_IsOrientable)
|
||||||
{
|
{
|
||||||
RequireFFAdjacency(m);
|
RequireFFAdjacency(m);
|
||||||
assert(&Oriented != &Orientable);
|
MeshAssert<MeshType>::FFAdjacencyIsInitialized(m);
|
||||||
assert(m.face.back().FFp(0)); // This algorithms require FF topology initialized
|
bool IsOrientable = true;
|
||||||
|
bool IsOriented = true;
|
||||||
|
|
||||||
Orientable = true;
|
UpdateFlags<MeshType>::FaceClearV(m);
|
||||||
Oriented = true;
|
|
||||||
|
|
||||||
tri::UpdateSelection<MeshType>::FaceClear(m);
|
|
||||||
std::stack<FacePointer> faces;
|
std::stack<FacePointer> faces;
|
||||||
for (FaceIterator 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())
|
if (!fi->IsD() && !fi->IsV())
|
||||||
{
|
{
|
||||||
// each face put in the stack is selected (and oriented)
|
// each face put in the stack is selected (and oriented)
|
||||||
fi->SetS();
|
fi->SetV();
|
||||||
faces.push(&(*fi));
|
faces.push(&(*fi));
|
||||||
|
|
||||||
// empty the stack
|
|
||||||
while (!faces.empty())
|
while (!faces.empty())
|
||||||
{
|
{
|
||||||
FacePointer fp = faces.top();
|
FacePointer fp = faces.top();
|
||||||
|
|
@ -1297,42 +1242,35 @@ public:
|
||||||
// make consistently oriented the adjacent faces
|
// make consistently oriented the adjacent faces
|
||||||
for (int j = 0; j < 3; j++)
|
for (int j = 0; j < 3; j++)
|
||||||
{
|
{
|
||||||
// get one of the adjacent face
|
if (!face::IsBorder(*fp,j) && face::IsManifold<FaceType>(*fp, j))
|
||||||
|
{
|
||||||
FacePointer fpaux = fp->FFp(j);
|
FacePointer fpaux = fp->FFp(j);
|
||||||
int iaux = fp->FFi(j);
|
int iaux = fp->FFi(j);
|
||||||
|
|
||||||
if (!fpaux->IsD() && fpaux != fp && face::IsManifold<FaceType>(*fp, j))
|
|
||||||
{
|
|
||||||
if (!CheckOrientation(*fpaux, iaux))
|
if (!CheckOrientation(*fpaux, iaux))
|
||||||
{
|
{
|
||||||
Oriented = false;
|
IsOriented = false;
|
||||||
|
|
||||||
if (!fpaux->IsS())
|
if (!fpaux->IsV())
|
||||||
{
|
|
||||||
face::SwapEdge<FaceType,true>(*fpaux, iaux);
|
face::SwapEdge<FaceType,true>(*fpaux, iaux);
|
||||||
assert(CheckOrientation(*fpaux, iaux));
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Orientable = false;
|
IsOrientable = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!fpaux->IsV())
|
||||||
// put the oriented face into the stack
|
|
||||||
|
|
||||||
if (!fpaux->IsS())
|
|
||||||
{
|
{
|
||||||
fpaux->SetS();
|
fpaux->SetV();
|
||||||
faces.push(fpaux);
|
faces.push(fpaux);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!IsOrientable) break;
|
||||||
if (!Orientable) break;
|
|
||||||
}
|
}
|
||||||
|
_IsOriented = IsOriented;
|
||||||
|
_IsOrientable = IsOrientable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1666,7 +1604,6 @@ public:
|
||||||
*/
|
*/
|
||||||
static bool TestFaceFaceIntersection(FaceType *f0,FaceType *f1)
|
static bool TestFaceFaceIntersection(FaceType *f0,FaceType *f1)
|
||||||
{
|
{
|
||||||
assert(f0!=f1);
|
|
||||||
int sv = face::CountSharedVertex(f0,f1);
|
int sv = face::CountSharedVertex(f0,f1);
|
||||||
if(sv==3) return true;
|
if(sv==3) return true;
|
||||||
if(sv==0) return (vcg::IntersectionTriangleTriangle<FaceType>((*f0),(*f1)));
|
if(sv==0) return (vcg::IntersectionTriangleTriangle<FaceType>((*f0),(*f1)));
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ namespace vcg {
|
||||||
public:
|
public:
|
||||||
typedef typename MESH_TYPE::VertexType VertexType;
|
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(){}
|
||||||
inline EmptyTMark(MESH_TYPE *){}
|
inline EmptyTMark(MESH_TYPE *){}
|
||||||
inline void UnMarkAll() const {}
|
inline void UnMarkAll() const {}
|
||||||
|
|
@ -90,6 +91,8 @@ namespace vcg {
|
||||||
inline void Mark(VertexType*) const {}
|
inline void Mark(VertexType*) const {}
|
||||||
inline bool IsMarked(EdgeType*) const { return false; }
|
inline bool IsMarked(EdgeType*) const { return false; }
|
||||||
inline void Mark(EdgeType*) const {}
|
inline void Mark(EdgeType*) const {}
|
||||||
|
inline bool IsMarked(FaceType*) const { return false; }
|
||||||
|
inline void Mark(FaceType*) const {}
|
||||||
inline void SetMesh(void * /*m=0*/) const {}
|
inline void SetMesh(void * /*m=0*/) const {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,10 +108,8 @@ public:
|
||||||
Vol.resize(this->siz[0]*this->siz[1]*this->siz[2]);
|
Vol.resize(this->siz[0]*this->siz[1]*this->siz[2]);
|
||||||
this->ComputeDimAndVoxel();
|
this->ComputeDimAndVoxel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class _ScalarType=float>
|
template <class _ScalarType=float>
|
||||||
class SimpleVoxel
|
class SimpleVoxel
|
||||||
{
|
{
|
||||||
|
|
@ -163,16 +161,8 @@ private:
|
||||||
typedef typename MeshType::VertexPointer VertexPointer;
|
typedef typename MeshType::VertexPointer VertexPointer;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// subbox is the portion of the volume to be computed
|
// SetExtractionBox set the portion of the volume to be traversed
|
||||||
// resolution determine the sampling step:
|
void SetExtractionBox(Box3i subbox)
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
_bbox = subbox;
|
_bbox = subbox;
|
||||||
_slice_dimension = _bbox.DimX()*_bbox.DimZ();
|
_slice_dimension = _bbox.DimX()*_bbox.DimZ();
|
||||||
|
|
@ -182,40 +172,39 @@ private:
|
||||||
_z_cs = new VertexIndex[ _slice_dimension ];
|
_z_cs = new VertexIndex[ _slice_dimension ];
|
||||||
_x_ns = new VertexIndex[ _slice_dimension ];
|
_x_ns = new VertexIndex[ _slice_dimension ];
|
||||||
_z_ns = new VertexIndex[ _slice_dimension ];
|
_z_ns = new VertexIndex[ _slice_dimension ];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~TrivialWalker()
|
TrivialWalker()
|
||||||
{_thr=0;}
|
{
|
||||||
|
_bbox.SetNull();
|
||||||
|
_slice_dimension=0;
|
||||||
|
}
|
||||||
|
|
||||||
template<class EXTRACTOR_TYPE>
|
template<class EXTRACTOR_TYPE>
|
||||||
void BuildMesh(MeshType &mesh, VolumeType &volume, EXTRACTOR_TYPE &extractor, const float threshold, vcg::CallBackPos * cb=0)
|
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;
|
_volume = &volume;
|
||||||
_mesh = &mesh;
|
_mesh = &mesh;
|
||||||
_mesh->Clear();
|
_mesh->Clear();
|
||||||
_thr=threshold;
|
_thr=threshold;
|
||||||
vcg::Point3i p1, p2;
|
|
||||||
|
|
||||||
Begin();
|
Begin();
|
||||||
extractor.Initialize();
|
extractor.Initialize();
|
||||||
for (int j=_bbox.min.Y(); j<(_bbox.max.Y()-1)-1; j+=1)
|
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");
|
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 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)
|
for (int k=_bbox.min.Z(); k<(_bbox.max.Z()-1)-1; k+=1)
|
||||||
{
|
{
|
||||||
p1.X()=i; p1.Y()=j; p1.Z()=k;
|
Point3i p1(i,j,k);
|
||||||
p2.X()=i+1; p2.Y()=j+1; p2.Z()=k+1;
|
Point3i p2(i+1,j+1,k+1);
|
||||||
if(volume.ValidCell(p1,p2))
|
if(volume.ValidCell(p1,p2))
|
||||||
extractor.ProcessCell(p1, p2);
|
extractor.ProcessCell(p1, p2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NextSlice();
|
NextYSlice();
|
||||||
}
|
}
|
||||||
extractor.Finalize();
|
extractor.Finalize();
|
||||||
_volume = NULL;
|
_volume = NULL;
|
||||||
|
|
@ -229,7 +218,7 @@ private:
|
||||||
|
|
||||||
bool Exist(const vcg::Point3i &p0, const vcg::Point3i &p1, VertexPointer &v)
|
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;
|
int vidx;
|
||||||
|
|
||||||
if (p0.X()!=p1.X()) // punti allineati lungo l'asse X
|
if (p0.X()!=p1.X()) // punti allineati lungo l'asse X
|
||||||
|
|
@ -249,8 +238,8 @@ private:
|
||||||
{
|
{
|
||||||
int i = p1.X() - _bbox.min.X();
|
int i = p1.X() - _bbox.min.X();
|
||||||
int z = p1.Z() - _bbox.min.Z();
|
int z = p1.Z() - _bbox.min.Z();
|
||||||
VertexIndex index = i+z*_bbox.max.X();
|
VertexIndex index = i+z*_bbox.DimX();
|
||||||
VertexIndex pos;
|
VertexIndex pos=-1;
|
||||||
if (p1.Y()==_current_slice)
|
if (p1.Y()==_current_slice)
|
||||||
{
|
{
|
||||||
if ((pos=_x_cs[index])==-1)
|
if ((pos=_x_cs[index])==-1)
|
||||||
|
|
@ -282,7 +271,7 @@ private:
|
||||||
{
|
{
|
||||||
int i = p1.X() - _bbox.min.X();
|
int i = p1.X() - _bbox.min.X();
|
||||||
int z = p1.Z() - _bbox.min.Z();
|
int z = p1.Z() - _bbox.min.Z();
|
||||||
VertexIndex index = i+z*_bbox.max.X();
|
VertexIndex index = i+z*_bbox.DimX();
|
||||||
VertexIndex pos;
|
VertexIndex pos;
|
||||||
if ((pos=_y_cs[index])==-1)
|
if ((pos=_y_cs[index])==-1)
|
||||||
{
|
{
|
||||||
|
|
@ -298,7 +287,7 @@ private:
|
||||||
{
|
{
|
||||||
int i = p1.X() - _bbox.min.X();
|
int i = p1.X() - _bbox.min.X();
|
||||||
int z = p1.Z() - _bbox.min.Z();
|
int z = p1.Z() - _bbox.min.Z();
|
||||||
VertexIndex index = i+z*_bbox.max.X();
|
VertexIndex index = i+z*_bbox.DimX();
|
||||||
VertexIndex pos;
|
VertexIndex pos;
|
||||||
if (p1.Y()==_current_slice)
|
if (p1.Y()==_current_slice)
|
||||||
{
|
{
|
||||||
|
|
@ -343,7 +332,7 @@ protected:
|
||||||
VolumeType *_volume;
|
VolumeType *_volume;
|
||||||
|
|
||||||
float _thr;
|
float _thr;
|
||||||
void NextSlice()
|
void NextYSlice()
|
||||||
{
|
{
|
||||||
memset(_x_cs, -1, _slice_dimension*sizeof(VertexIndex));
|
memset(_x_cs, -1, _slice_dimension*sizeof(VertexIndex));
|
||||||
memset(_y_cs, -1, _slice_dimension*sizeof(VertexIndex));
|
memset(_y_cs, -1, _slice_dimension*sizeof(VertexIndex));
|
||||||
|
|
|
||||||
|
|
@ -689,10 +689,14 @@ void SuperEllipsoid(MeshType &m, float rFeature, float sFeature, float tFeature,
|
||||||
tri::Clean<MeshType>::OrientCoherentlyMesh(m,oriented,orientable);
|
tri::Clean<MeshType>::OrientCoherentlyMesh(m,oriented,orientable);
|
||||||
tri::UpdateSelection<MeshType>::Clear(m);
|
tri::UpdateSelection<MeshType>::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).
|
/** This function build a mesh starting from a vector of generic coords (InCoordType) and indexes (InFaceIndexType)
|
||||||
template <class MeshType,class V, class F >
|
* InCoordsType needs to have a [] access method for accessing the three coordinates
|
||||||
void BuildMeshFromCoordVectorIndexVector( MeshType & in, const V & v, const F & f)
|
* and similarly the InFaceIndexType requires [] access method for accessing the three indexes
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <class MeshType, class InCoordType, class InFaceIndexType >
|
||||||
|
void BuildMeshFromCoordVectorIndexVector(MeshType & in, const std::vector<InCoordType> & v, const std::vector<InFaceIndexType> & f)
|
||||||
{
|
{
|
||||||
typedef typename MeshType::CoordType CoordType;
|
typedef typename MeshType::CoordType CoordType;
|
||||||
typedef typename MeshType::VertexPointer VertexPointer;
|
typedef typename MeshType::VertexPointer VertexPointer;
|
||||||
|
|
@ -704,7 +708,7 @@ void BuildMeshFromCoordVectorIndexVector( MeshType & in, const V & v, const F &
|
||||||
|
|
||||||
for(size_t i=0;i<v.size();++i)
|
for(size_t i=0;i<v.size();++i)
|
||||||
{
|
{
|
||||||
float *vv=(float *)(&v[i]);
|
const InCoordType &vv = v[i];
|
||||||
in.vert[i].P() = CoordType( vv[0],vv[1],vv[2]);
|
in.vert[i].P() = CoordType( vv[0],vv[1],vv[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -716,7 +720,7 @@ void BuildMeshFromCoordVectorIndexVector( MeshType & in, const V & v, const F &
|
||||||
|
|
||||||
for(size_t i=0;i<f.size();++i)
|
for(size_t i=0;i<f.size();++i)
|
||||||
{
|
{
|
||||||
int * ff=(int *)(&f[i]);
|
const InFaceIndexType &ff= f[i];
|
||||||
assert( ff[0]>=0 );
|
assert( ff[0]>=0 );
|
||||||
assert( ff[1]>=0 );
|
assert( ff[1]>=0 );
|
||||||
assert( ff[2]>=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
|
// 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 oll the grid vertexes are present.
|
// Vertexes are assumed to be already be allocated, but not all the grid vertexes are present.
|
||||||
// For this purpos a grid of indexes is also passed. negative indexes means that there is no vertex.
|
// For this purpose vector with a grid of indexes is also passed.
|
||||||
|
// Negative indexes in this vector means that there is no vertex.
|
||||||
|
|
||||||
template <class MeshType>
|
template <class MeshType>
|
||||||
void FaceGrid(MeshType & in, const std::vector<int> &grid, int w, int h)
|
void SparseFaceGrid(MeshType & in, const std::vector<int> &grid, int w, int h)
|
||||||
{
|
{
|
||||||
tri::RequireCompactness(in);
|
tri::RequireCompactness(in);
|
||||||
assert(in.vn <= w*h); // the number of vertices should match the number of expected grid vertices
|
assert(in.vn <= w*h); // the number of vertices should match the number of expected grid vertices
|
||||||
|
|
|
||||||
|
|
@ -35,23 +35,13 @@
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include <locale>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <vcg/space/index/grid_static_ptr.h>
|
|
||||||
#include <vcg/complex/complex.h>
|
#include <vcg/complex/complex.h>
|
||||||
|
|
||||||
#include <vcg/complex/algorithms/update/position.h>
|
|
||||||
#include <vcg/complex/algorithms/update/normal.h>
|
|
||||||
#include <vcg/complex/algorithms/update/quality.h>
|
|
||||||
#include <vcg/complex/algorithms/update/topology.h>
|
|
||||||
#include <vcg/math/histogram.h>
|
#include <vcg/math/histogram.h>
|
||||||
#include <vcg/complex/algorithms/clean.h>
|
|
||||||
#include <vcg/complex/algorithms/geodesic.h>
|
#include <vcg/complex/algorithms/geodesic.h>
|
||||||
#include <wrap/io_trimesh/import.h>
|
#include <wrap/io_trimesh/import.h>
|
||||||
#include <wrap/io_trimesh/export_ply.h>
|
#include <wrap/io_trimesh/export_ply.h>
|
||||||
#include <wrap/ply/plystuff.h>
|
//#include <wrap/ply/plystuff.h>
|
||||||
|
|
||||||
#include <vcg/complex/algorithms/create/marching_cubes.h>
|
#include <vcg/complex/algorithms/create/marching_cubes.h>
|
||||||
#include <vcg/complex/algorithms/create/mc_trivial_walker.h>
|
#include <vcg/complex/algorithms/create/mc_trivial_walker.h>
|
||||||
|
|
@ -61,7 +51,6 @@
|
||||||
#include <vcg/complex/algorithms/local_optimization/tri_edge_collapse.h>
|
#include <vcg/complex/algorithms/local_optimization/tri_edge_collapse.h>
|
||||||
#include <vcg/complex/algorithms/local_optimization/tri_edge_collapse_quadric.h>
|
#include <vcg/complex/algorithms/local_optimization/tri_edge_collapse_quadric.h>
|
||||||
|
|
||||||
//#include <vcg/simplex/edge/base.h>
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include "volume.h"
|
#include "volume.h"
|
||||||
#include "tri_edge_collapse_mc.h"
|
#include "tri_edge_collapse_mc.h"
|
||||||
|
|
@ -73,6 +62,15 @@ template<class MeshType>
|
||||||
void MCSimplify( MeshType &m, float perc, bool preserveBB=true, vcg::CallBackPos *cb=0);
|
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>
|
template < class SMesh, class MeshProvider>
|
||||||
class PlyMC
|
class PlyMC
|
||||||
{
|
{
|
||||||
|
|
@ -175,6 +173,7 @@ public:
|
||||||
MeshProvider MP;
|
MeshProvider MP;
|
||||||
Parameter p;
|
Parameter p;
|
||||||
Volume<Voxelf> VV;
|
Volume<Voxelf> VV;
|
||||||
|
char errorMessage[1024];
|
||||||
|
|
||||||
/// PLYMC Methods
|
/// PLYMC Methods
|
||||||
|
|
||||||
|
|
@ -192,21 +191,36 @@ public:
|
||||||
{
|
{
|
||||||
if(!(loadmask & tri::io::Mask::IOM_VERTNORMAL))
|
if(!(loadmask & tri::io::Mask::IOM_VERTNORMAL))
|
||||||
{
|
{
|
||||||
printf("Error, pointset MUST have normals");
|
if(m.FN()==0)
|
||||||
|
{
|
||||||
|
sprintf(errorMessage,"%sError: mesh has not per vertex normals\n",errorMessage);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tri::Clean<SMesh>::RemoveUnreferencedVertex(m);
|
||||||
|
tri::Allocator<SMesh>::CompactEveryVector(m);
|
||||||
|
tri::UpdateNormal<SMesh>::PerVertexNormalizedPerFaceNormalized(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tri::UpdateNormal<SMesh>::NormalizePerVertex(m);
|
||||||
|
int badNormalCnt=0;
|
||||||
for(SVertexIterator vi=m.vert.begin(); vi!=m.vert.end();++vi)
|
for(SVertexIterator vi=m.vert.begin(); vi!=m.vert.end();++vi)
|
||||||
if(math::Abs(SquaredNorm((*vi).N())-1.0)>0.0001)
|
if(math::Abs(SquaredNorm((*vi).N())-1.0)>0.0001)
|
||||||
{
|
{
|
||||||
printf("Error: mesh has not per vertex normalized normals\n");
|
badNormalCnt++;
|
||||||
|
tri::Allocator<SMesh>::DeleteVertex(m,*vi);
|
||||||
|
}
|
||||||
|
tri::Allocator<SMesh>::CompactEveryVector(m);
|
||||||
|
if(badNormalCnt > m.VN()/10)
|
||||||
|
{
|
||||||
|
sprintf(errorMessage,"%sError: mesh has null normals\n",errorMessage);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!(loadmask & tri::io::Mask::IOM_VERTQUALITY))
|
if(!(loadmask & tri::io::Mask::IOM_VERTQUALITY))
|
||||||
tri::UpdateQuality<SMesh>::VertexConstant(m,0);
|
tri::UpdateQuality<SMesh>::VertexConstant(m,0);
|
||||||
tri::UpdateNormal<SMesh>::PerVertexMatrix(m,Tr);
|
tri::UpdateNormal<SMesh>::PerVertexMatrix(m,Tr);
|
||||||
//if(!(loadmask & tri::io::Mask::IOM_VERTCOLOR))
|
|
||||||
// saveMask &= ~tri::io::Mask::IOM_VERTCOLOR;
|
|
||||||
}
|
}
|
||||||
else // processing for triangle meshes
|
else // processing for triangle meshes
|
||||||
{
|
{
|
||||||
|
|
@ -223,7 +237,6 @@ public:
|
||||||
tri::UpdateTopology<SMesh>::VertexFace(m);
|
tri::UpdateTopology<SMesh>::VertexFace(m);
|
||||||
tri::UpdateFlags<SMesh>::FaceBorderFromVF(m);
|
tri::UpdateFlags<SMesh>::FaceBorderFromVF(m);
|
||||||
tri::Geodesic<SMesh>::DistanceFromBorder(m);
|
tri::Geodesic<SMesh>::DistanceFromBorder(m);
|
||||||
// tri::UpdateQuality<SMesh>::VertexGeodesicFromBorder(m);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -325,8 +338,9 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process(vcg::CallBackPos *cb=0)
|
bool Process(vcg::CallBackPos *cb=0)
|
||||||
{
|
{
|
||||||
|
sprintf(errorMessage,"");
|
||||||
printf("bbox scanning...\n"); fflush(stdout);
|
printf("bbox scanning...\n"); fflush(stdout);
|
||||||
Matrix44f Id; Id.SetIdentity();
|
Matrix44f Id; Id.SetIdentity();
|
||||||
MP.InitBBox();
|
MP.InitBBox();
|
||||||
|
|
@ -344,7 +358,6 @@ void Process(vcg::CallBackPos *cb=0)
|
||||||
|
|
||||||
voxdim = fullb.max - fullb.min;
|
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;
|
// if kcell==0 the number of cells is computed starting from required voxel size;
|
||||||
__int64 cells;
|
__int64 cells;
|
||||||
if(p.NCell>0) cells = (__int64)(p.NCell)*(__int64)(1000);
|
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[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])
|
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));
|
res = InitMesh(*sm,MP.MeshName(i).c_str(),MP.Tr(i));
|
||||||
if(!res)
|
if(!res)
|
||||||
{
|
{
|
||||||
printf("Failed Init of mesh %s",MP.MeshName(i).c_str());
|
sprintf(errorMessage,"%sFailed Init of mesh %s\n",errorMessage,MP.MeshName(i).c_str());
|
||||||
return;
|
return false ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res |= AddMeshToVolumeM(*sm, MP.MeshName(i),MP.W(i));
|
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.SlicedPPM("final","__",p.SliceNum);
|
||||||
VV.SlicedPPMQ("final","__",p.SliceNum);
|
VV.SlicedPPMQ("final","__",p.SliceNum);
|
||||||
}
|
}
|
||||||
//MCMesh me;
|
|
||||||
//
|
|
||||||
MCMesh me;
|
MCMesh me;
|
||||||
if(res)
|
if(res)
|
||||||
{
|
{
|
||||||
typedef vcg::tri::TrivialWalker<MCMesh, Volume <Voxelf> > Walker;
|
typedef vcg::tri::TrivialWalker<MCMesh, Volume <Voxelf> > Walker;
|
||||||
typedef vcg::tri::MarchingCubes<MCMesh, Walker> MarchingCubes;
|
typedef vcg::tri::MarchingCubes<MCMesh, Walker> MarchingCubes;
|
||||||
//typedef vcg::tri::ExtendedMarchingCubes<MCMesh, Walker> ExtendedMarchingCubes;
|
|
||||||
|
|
||||||
Walker walker;
|
Walker walker;
|
||||||
MarchingCubes mc(me, walker);
|
MarchingCubes mc(me, walker);
|
||||||
Box3i currentSubBox=VV.SubPartSafe;
|
|
||||||
Point3i currentSubBoxRes=VV.ssz;
|
|
||||||
/**********************/
|
/**********************/
|
||||||
if(cb) cb(50,"Step 2: Marching Cube...");
|
if(cb) cb(50,"Step 2: Marching Cube...");
|
||||||
else printf("Step 2: Marching Cube...\n");
|
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,0);
|
||||||
// walker.BuildMesh(me,VV,mc,currentSubBox,currentSubBoxRes);
|
|
||||||
|
|
||||||
typename MCMesh::VertexIterator vi;
|
typename MCMesh::VertexIterator vi;
|
||||||
Box3f bbb; bbb.Import(VV.SubPart);
|
Box3f bbb; bbb.Import(VV.SubPart);
|
||||||
|
|
@ -481,8 +489,7 @@ void Process(vcg::CallBackPos *cb=0)
|
||||||
vcg::tri::Allocator< MCMesh >::DeleteVertex(me,*vi);
|
vcg::tri::Allocator< MCMesh >::DeleteVertex(me,*vi);
|
||||||
VV.DeInterize((*vi).P());
|
VV.DeInterize((*vi).P());
|
||||||
}
|
}
|
||||||
typename MCMesh::FaceIterator fi;
|
for (typename MCMesh::FaceIterator fi = me.face.begin(); fi != me.face.end(); ++fi)
|
||||||
for (fi = me.face.begin(); fi != me.face.end(); ++fi)
|
|
||||||
{
|
{
|
||||||
if((*fi).V(0)->IsD() || (*fi).V(1)->IsD() || (*fi).V(2)->IsD() )
|
if((*fi).V(0)->IsD() || (*fi).V(1)->IsD() || (*fi).V(2)->IsD() )
|
||||||
vcg::tri::Allocator< MCMesh >::DeleteFace(me,*fi);
|
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]);
|
printf("----------- skipping SubBlock %2i %2i %2i ----------\n",p.IPos[0],p.IPos[1],p.IPos[2]);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,233 @@
|
||||||
|
#ifndef SIMPLEMESHPROVIDER_H
|
||||||
|
#define SIMPLEMESHPROVIDER_H
|
||||||
|
#include "../../meshlab/alnParser.h"
|
||||||
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
|
#include <vcg/space/box3.h>
|
||||||
|
#include <wrap/ply/plystuff.h>
|
||||||
|
#include <wrap/io_trimesh/import.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 TriMeshType>
|
||||||
|
class MinimalMeshProvider
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::vector< std::string > nameVec;
|
||||||
|
std::vector< TriMeshType * > meshVec;
|
||||||
|
std::vector<vcg::Matrix44f> trVec;
|
||||||
|
std::vector<float> 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<nameVec.size();++i)
|
||||||
|
if(nameVec[i]==name) {
|
||||||
|
sm=meshVec[i];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
sm=0; return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache based Loading of meshes to avoid reloading an processing of the same mesh multiple times.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace vcg {
|
||||||
|
|
||||||
|
template<class TriMeshType>
|
||||||
|
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<Pair> MV;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
MeshCache() {MeshCacheSize=6;}
|
||||||
|
~MeshCache() {
|
||||||
|
typename std::list<Pair>::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<Pair>::iterator mi;
|
||||||
|
typename std::list<Pair>::iterator oldest; // quello che e' piu' tempo che non viene acceduto.
|
||||||
|
int last;
|
||||||
|
|
||||||
|
last = std::numeric_limits<int>::max();
|
||||||
|
oldest = MV.begin();
|
||||||
|
|
||||||
|
for(mi=MV.begin();mi!=MV.end();++mi)
|
||||||
|
{
|
||||||
|
if((*mi).used<last)
|
||||||
|
{
|
||||||
|
last=(*mi).used;
|
||||||
|
oldest=mi;
|
||||||
|
}
|
||||||
|
if((*mi).Name==name) {
|
||||||
|
sm=(*mi).M;
|
||||||
|
(*mi).used++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we have not found the requested mesh
|
||||||
|
// either allocate a new mesh or give back a previous mesh.
|
||||||
|
|
||||||
|
if(MV.size()>MeshCacheSize) {
|
||||||
|
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 TriMeshType>
|
||||||
|
class SimpleMeshProvider
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::vector< std::string > meshnames;
|
||||||
|
std::vector<vcg::Matrix44f> TrV;
|
||||||
|
std::vector<float> WV; // weight tot be applied to each mesh.
|
||||||
|
std::vector<vcg::Box3f> BBV; // bbox of the transformed meshes..
|
||||||
|
vcg::Box3f fullBBox;
|
||||||
|
MeshCache<TriMeshType> 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<RangeMap> rmaps;
|
||||||
|
ALNParser::ParseALN(rmaps, alnName);
|
||||||
|
|
||||||
|
for(size_t i=0; i<rmaps.size(); i++)
|
||||||
|
AddSingleMesh(rmaps[i].filename.c_str(), rmaps[i].trasformation, rmaps[i].quality);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddSingleMesh(const char* meshName, const Matrix44f &tr= Matrix44f::Identity(), float meshWeight=1)
|
||||||
|
{
|
||||||
|
assert(WV.size()==meshnames.size() && TrV.size() == WV.size());
|
||||||
|
TrV.push_back(tr);
|
||||||
|
meshnames.push_back(meshName);
|
||||||
|
WV.push_back(meshWeight);
|
||||||
|
BBV.push_back(Box3f());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
vcg::Box3f bb(int i) {return BBV[i];}
|
||||||
|
vcg::Box3f fullBB(){ return fullBBox;}
|
||||||
|
vcg::Matrix44f Tr(int i) const {return TrV[i];}
|
||||||
|
std::string MeshName(int i) const {return meshnames[i];}
|
||||||
|
float W(int i) const {return WV[i];}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
meshnames.clear();
|
||||||
|
TrV.clear();
|
||||||
|
WV.clear();
|
||||||
|
BBV.clear();
|
||||||
|
fullBBox.SetNull();
|
||||||
|
MC.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Find(int i, TriMeshType * &sm)
|
||||||
|
{
|
||||||
|
return MC.Find(meshnames[i],sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InitBBox()
|
||||||
|
{
|
||||||
|
fullBBox.SetNull();
|
||||||
|
for(int i=0;i<int(meshnames.size());++i)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
printf("bbox scanning %4i/%i [%16s] \r",i+1,(int)meshnames.size(), meshnames[i].c_str());
|
||||||
|
if(tri::io::Importer<TriMeshType>::FileExtension(meshnames[i],"PLY") || tri::io::Importer<TriMeshType>::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<TriMeshType>::Open(m,meshnames[i].c_str()) == tri::io::Importer<TriMeshType>::E_NOERROR);
|
||||||
|
tri::UpdatePosition<TriMeshType>::Matrix(m,TrV[i]);
|
||||||
|
tri::UpdateBounding<TriMeshType>::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<SVertex>::AsVertexType,
|
||||||
|
vcg::Use<SFace >::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
|
||||||
|
|
@ -22,7 +22,8 @@
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#ifndef __TRI_EDGE_COLLAPSE_MC__
|
#ifndef __TRI_EDGE_COLLAPSE_MC__
|
||||||
#define __TRI_EDGE_COLLAPSE_MC__
|
#define __TRI_EDGE_COLLAPSE_MC__
|
||||||
#include<vcg/simplex/face/topology.h>
|
namespace vcg{
|
||||||
|
namespace tri{
|
||||||
|
|
||||||
class TriEdgeCollapseMCParameter : public BaseParameterClass
|
class TriEdgeCollapseMCParameter : public BaseParameterClass
|
||||||
{
|
{
|
||||||
|
|
@ -125,5 +126,7 @@ class MCTriEdgeCollapse: public tri::TriEdgeCollapse< MCTriMesh, VertexPair, MYT
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -24,26 +24,10 @@
|
||||||
#ifndef __VOLUME_H__
|
#ifndef __VOLUME_H__
|
||||||
#define __VOLUME_H__
|
#define __VOLUME_H__
|
||||||
|
|
||||||
#ifdef __MINGW32__
|
|
||||||
#define _int64 __int64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "voxel.h"
|
#include "voxel.h"
|
||||||
#include "svoxel.h"
|
|
||||||
#include <vector>
|
|
||||||
#include <vcg/space/index/grid_static_ptr.h>
|
#include <vcg/space/index/grid_static_ptr.h>
|
||||||
|
|
||||||
//#define BLOCKSIDE() 8
|
namespace vcg {
|
||||||
|
|
||||||
// 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!!!
|
|
||||||
|
|
||||||
// forward definition
|
// forward definition
|
||||||
template < class VOL >
|
template < class VOL >
|
||||||
|
|
@ -172,7 +156,7 @@ bool Verbose; // se true stampa un sacco di info in piu su logfp;
|
||||||
for(size_t i=0;i<rv.size();++i)
|
for(size_t i=0;i<rv.size();++i)
|
||||||
rv[i].resize(0,VOX_TYPE::Zero());
|
rv[i].resize(0,VOX_TYPE::Zero());
|
||||||
SetDim(bb);
|
SetDim(bb);
|
||||||
};
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
@ -324,8 +308,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Data una posizione x,y,z restituisce true se tale posizione appartiene a un blocco gia' allocato
|
* Compute the offset <lpos> inside the subblock <rpos> of voxel (x,y,z).
|
||||||
In ogni caso mette in rpos la posizione del subbloc e in lpos la posizione all'interno del sottoblocco
|
* return true if the subblock is allocated.
|
||||||
*/
|
*/
|
||||||
bool Pos(const int &_x,const int &_y,const int &_z, int & rpos,int &lpos) const
|
bool Pos(const int &_x,const int &_y,const int &_z, int & rpos,int &lpos) const
|
||||||
{
|
{
|
||||||
|
|
@ -1374,6 +1358,6 @@ class VolumeIterator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -22,17 +22,33 @@
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#ifndef __VOXEL_H__
|
#ifndef __VOXEL_H__
|
||||||
#define __VOXEL_H__
|
#define __VOXEL_H__
|
||||||
|
|
||||||
|
namespace vcg {
|
||||||
|
|
||||||
|
// 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!!!
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
template<class SCALAR_TYPE=float>
|
template<class SCALAR_TYPE=float>
|
||||||
class Voxel
|
class Voxel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef SCALAR_TYPE scalar;
|
typedef SCALAR_TYPE scalar;
|
||||||
|
|
||||||
Voxel(SCALAR_TYPE vv, bool bb, Point3<scalar> nn, short _cnt) {v=vv;b=bb;n=nn;cnt=_cnt;}
|
Voxel(SCALAR_TYPE vv, bool bb, Point3<scalar> nn, short _cnt) {v=vv;b=bb;n=nn;cnt=_cnt;}
|
||||||
Voxel(SCALAR_TYPE vv, Point3<scalar> nn, scalar qq) {v=vv;b=true;n=nn;cnt=0;q=qq;}
|
Voxel(SCALAR_TYPE vv, Point3<scalar> 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<scalar> &N() const { return n; }
|
const Point3<scalar> &N() const { return n; }
|
||||||
|
|
||||||
void SetN(const Point3<scalar> &nn) { n=nn; }
|
void SetN(const Point3<scalar> &nn) { n=nn; }
|
||||||
|
|
@ -60,9 +76,9 @@ class Voxel
|
||||||
|
|
||||||
inline Voxel & operator += ( Voxel const & vx)
|
inline Voxel & operator += ( Voxel const & vx)
|
||||||
{
|
{
|
||||||
|
assert(!b);
|
||||||
if(cnt==0)
|
if(cnt==0)
|
||||||
{
|
{
|
||||||
assert(!b);
|
|
||||||
v=vx.v;
|
v=vx.v;
|
||||||
q=vx.q;
|
q=vx.q;
|
||||||
n=vx.n;
|
n=vx.n;
|
||||||
|
|
@ -71,7 +87,6 @@ class Voxel
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(!b);
|
|
||||||
v+=vx.v;
|
v+=vx.v;
|
||||||
q+=vx.q;
|
q+=vx.q;
|
||||||
n+=vx.n;
|
n+=vx.n;
|
||||||
|
|
@ -115,7 +130,7 @@ class Voxel
|
||||||
q=VOX.q;
|
q=VOX.q;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool b;
|
bool b;
|
||||||
short cnt;
|
short cnt;
|
||||||
scalar v;
|
scalar v;
|
||||||
|
|
@ -191,5 +206,5 @@ public:
|
||||||
private:
|
private:
|
||||||
Point3f c;
|
Point3f c;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
namespace vcg {
|
namespace vcg {
|
||||||
namespace tri {
|
namespace tri {
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An ear is identified by TWO pos.
|
An ear is identified by TWO pos.
|
||||||
The Three vertexes of an Ear are:
|
The Three vertexes of an Ear are:
|
||||||
|
|
@ -46,22 +47,22 @@ namespace vcg {
|
||||||
e1 == e0.NextB();
|
e1 == e0.NextB();
|
||||||
e1.FlipV() == e0;
|
e1.FlipV() == e0;
|
||||||
|
|
||||||
Situazioni ear non manifold, e degeneri (buco triangolare)
|
*/
|
||||||
|
/**
|
||||||
T XXXXXXXXXXXXX A /XXXXX B en/XXXXX
|
* Basic class for representing an 'ear' in a hole.
|
||||||
/XXXXXXXXXXXXXXX /XXXXXX /XXXXXX
|
*
|
||||||
XXXXXXep==en XXX ep\ /en XXXX /e1 XXXX
|
* Require FF-adajcncy and edge-manifoldness around the mesh (at most two triangles per edge)
|
||||||
XXXXXX ----/| XX ------ ----/| XX ------ ----/|XXX
|
*
|
||||||
XXXXXX| /e1 XX XXXXXX| /e1 XX XXXXXX| o/e0 XX
|
* An ear is represented by two consecutive Pos e0,e1.
|
||||||
XXXXXX| /XXXXXX XXXXXX| /XXXXXX XXXXXX| /XXXXXX
|
* The vertex pointed by the first pos is the 'corner' of the ear
|
||||||
XXX e0|o/XXXXXXX XXX e0|o/XXXXXXX XXX ep| /XXXXXXX
|
*
|
||||||
XXX \|/XXXXXXXX XXX \|/XXXXXXXX XXX \|/XXXXXXXX
|
*
|
||||||
XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
|
|
||||||
*/
|
*/
|
||||||
template<class MESH> class TrivialEar
|
template<class MESH> class TrivialEar
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef typename MESH::FaceType FaceType;
|
typedef typename MESH::FaceType FaceType;
|
||||||
|
typedef typename MESH::VertexType VertexType;
|
||||||
typedef typename MESH::FacePointer FacePointer;
|
typedef typename MESH::FacePointer FacePointer;
|
||||||
typedef typename MESH::VertexPointer VertexPointer;
|
typedef typename MESH::VertexPointer VertexPointer;
|
||||||
typedef typename face::Pos<FaceType> PosType;
|
typedef typename face::Pos<FaceType> PosType;
|
||||||
|
|
@ -71,6 +72,7 @@ public:
|
||||||
PosType e0;
|
PosType e0;
|
||||||
PosType e1;
|
PosType e1;
|
||||||
CoordType n; // the normal of the face defined by the ear
|
CoordType n; // the normal of the face defined by the ear
|
||||||
|
|
||||||
const char * Dump() {return 0;}
|
const char * Dump() {return 0;}
|
||||||
// The following members are useful to consider the Ear as a generic <triangle>
|
// The following members are useful to consider the Ear as a generic <triangle>
|
||||||
// with p0 the 'center' of the ear.
|
// with p0 the 'center' of the ear.
|
||||||
|
|
@ -116,14 +118,50 @@ public:
|
||||||
virtual void ComputeQuality() { quality = QualityFace(*this) ; }
|
virtual void ComputeQuality() { quality = QualityFace(*this) ; }
|
||||||
bool IsUpToDate() {return ( e0.IsBorder() && e1.IsBorder());}
|
bool IsUpToDate() {return ( e0.IsBorder() && e1.IsBorder());}
|
||||||
// An ear is degenerated if both of its two endpoints are non manifold.
|
// 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;
|
return true;
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
bool IsConcave() const {return(angleRad > (float)M_PI);}
|
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
|
// 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.
|
// 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
|
// 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());
|
while(!pp.IsBorder());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @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:
|
||||||
|
|
||||||
virtual bool Close(PosType &np0, PosType &np1, FaceType * f)
|
* (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
|
// simple topological check
|
||||||
if(e0.f==e1.f) {
|
if(e0.f==e1.f) {
|
||||||
|
|
@ -150,9 +218,8 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//usato per generare una delle due nuove orecchie.
|
PosType ep=e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // ep previous
|
||||||
PosType ep=e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // he precedente a e0
|
PosType en=e1; en.NextB(); // en next
|
||||||
PosType en=e1; en.NextB(); // he successivo a e1
|
|
||||||
if(ep!=en)
|
if(ep!=en)
|
||||||
if(!CheckManifoldAfterEarClose()) return false;
|
if(!CheckManifoldAfterEarClose()) return false;
|
||||||
|
|
||||||
|
|
@ -165,7 +232,7 @@ public:
|
||||||
face::FFAttachManifold(f,1,e1.f,e1.z);
|
face::FFAttachManifold(f,1,e1.f,e1.z);
|
||||||
face::FFSetBorder(f,2);
|
face::FFSetBorder(f,2);
|
||||||
|
|
||||||
// caso ear degenere per buco triangolare
|
// First Special Case (T): Triangular hole
|
||||||
if(ep==en)
|
if(ep==en)
|
||||||
{
|
{
|
||||||
//printf("Closing the last triangle");
|
//printf("Closing the last triangle");
|
||||||
|
|
@ -173,30 +240,38 @@ public:
|
||||||
np0.SetNull();
|
np0.SetNull();
|
||||||
np1.SetNull();
|
np1.SetNull();
|
||||||
}
|
}
|
||||||
// Caso ear non manifold a
|
// Second Special Case (A): Non Manifold on ep
|
||||||
else if(ep.v==en.v)
|
else if(ep.v==en.v)
|
||||||
{
|
{
|
||||||
//printf("Ear Non manif A\n");
|
//printf("Ear Non manif A\n");
|
||||||
|
assert(ep.v->IsUserBit(NonManifoldBit()));
|
||||||
|
ep.v->ClearUserBit(NonManifoldBit());
|
||||||
PosType enold=en;
|
PosType enold=en;
|
||||||
en.NextB();
|
en.NextB();
|
||||||
face::FFAttachManifold(f,2,enold.f,enold.z);
|
face::FFAttachManifold(f,2,enold.f,enold.z);
|
||||||
np0=ep;
|
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)
|
else if(ep.VFlip()==e1.v)
|
||||||
{
|
{
|
||||||
|
assert(e1.v->IsUserBit(NonManifoldBit()));
|
||||||
|
e1.v->ClearUserBit(NonManifoldBit());
|
||||||
//printf("Ear Non manif B\n");
|
//printf("Ear Non manif B\n");
|
||||||
PosType epold=ep;
|
PosType epold=ep;
|
||||||
ep.FlipV(); ep.NextB(); ep.FlipV();
|
ep.FlipV(); ep.NextB(); ep.FlipV();
|
||||||
face::FFAttachManifold(f,2,epold.f,epold.z);
|
face::FFAttachManifold(f,2,epold.f,epold.z);
|
||||||
np0=ep; // assign the two new
|
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;
|
np0=ep;
|
||||||
|
if(np0.v->IsUserBit(NonManifoldBit())) np0.SetNull();
|
||||||
np1=PosType(f,2,e1.v);
|
np1=PosType(f,2,e1.v);
|
||||||
|
if(np1.v->IsUserBit(NonManifoldBit())) np1.SetNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -315,12 +390,12 @@ public:
|
||||||
}
|
}
|
||||||
}; // end class SelfIntersectionEar
|
}; // 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 MESH>
|
template <class MESH>
|
||||||
class Hole
|
class Hole
|
||||||
{
|
{
|
||||||
|
|
@ -386,103 +461,67 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class EdgeToBeAvoided
|
/** FillHoleEar
|
||||||
{
|
* Main Single Hole Filling Function
|
||||||
VertexPointer v0,v1;
|
* Given a specific hole (identified by the Info h) it fills it
|
||||||
EdgeToBeAvoided(VertexPointer _v0, VertexPointer _v1):v0(_v0),v1(_v1)
|
* It also update a vector of face pointers
|
||||||
{
|
* It uses a priority queue to choose the best ear to be closed
|
||||||
if(v0>v1) swap(v0,v1);
|
*/
|
||||||
}
|
|
||||||
bool operator < (const EdgeToBeAvoided &e)
|
|
||||||
{
|
|
||||||
if(this->v0!=e.v0) return this->v0<e.v0;
|
|
||||||
return this->v1<e.v1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/// Main Single Hole Filling Function
|
|
||||||
/// Given a specific hole (identified by the Info h) it fills it
|
|
||||||
/// It also update a vector of face pointers
|
|
||||||
/// It uses an heap to choose the best ear to be closed
|
|
||||||
|
|
||||||
template<class EAR>
|
template<class EAR>
|
||||||
static void FillHoleEar(MESH &m, // The mesh to be filled
|
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<FacePointer *> &facePointersToBeUpdated)
|
std::vector<FacePointer *> &facePointersToBeUpdated)
|
||||||
{
|
{
|
||||||
//Aggiungo le facce e aggiorno il puntatore alla faccia!
|
|
||||||
FaceIterator f = tri::Allocator<MESH>::AddFaces(m, h.size-2, facePointersToBeUpdated);
|
|
||||||
|
|
||||||
assert(h.p.f >= &*m.face.begin());
|
assert(tri::IsValidPointer(m,p.f));
|
||||||
assert(h.p.f <= &m.face.back());
|
assert(p.IsBorder());
|
||||||
assert(h.p.IsBorder());
|
int holeSize = EAR::InitNonManifoldBitOnHoleBoundary(p);
|
||||||
|
FaceIterator f = tri::Allocator<MESH>::AddFaces(m, holeSize-2, facePointersToBeUpdated);
|
||||||
|
|
||||||
std::vector< EAR > EarHeap;
|
std::priority_queue< EAR > EarHeap;
|
||||||
EarHeap.reserve(h.size);
|
PosType fp = p;
|
||||||
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;
|
|
||||||
do{
|
do{
|
||||||
EAR appEar = EAR(fp);
|
EAR appEar = EAR(fp);
|
||||||
EarHeap.push_back( appEar );
|
if(!fp.v->IsUserBit(EAR::NonManifoldBit()))
|
||||||
|
EarHeap.push( appEar );
|
||||||
//printf("Adding ear %s ",app.Dump());
|
//printf("Adding ear %s ",app.Dump());
|
||||||
fp.NextB();
|
fp.NextB();
|
||||||
assert(fp.IsBorder());
|
assert(fp.IsBorder());
|
||||||
}while(fp!=h.p);
|
}while(fp!=p);
|
||||||
|
|
||||||
int cnt=h.size;
|
// Main Ear closing Loop
|
||||||
|
while( holeSize > 2 && !EarHeap.empty() )
|
||||||
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() )
|
|
||||||
{
|
{
|
||||||
//printf("Front of the heap is %s", H.front().Dump());
|
EAR BestEar=EarHeap.top();
|
||||||
pop_heap(EarHeap.begin(), EarHeap.end()); // retrieve the MAXIMUM value and put in the back;
|
EarHeap.pop();
|
||||||
EAR BestEar=EarHeap.back();
|
|
||||||
EarHeap.pop_back();
|
|
||||||
|
|
||||||
if(BestEar.IsUpToDate() && !BestEar.IsDegen(nmBit))
|
if(BestEar.IsUpToDate() && !BestEar.IsDegen())
|
||||||
{
|
{
|
||||||
if((*f).HasPolyInfo()) (*f).Alloc(3);
|
if((*f).HasPolyInfo()) (*f).Alloc(3);
|
||||||
PosType ep0,ep1;
|
PosType ep0,ep1;
|
||||||
if(BestEar.Close(ep0,ep1,&*f))
|
if(BestEar.Close(ep0,ep1,&*f))
|
||||||
{
|
{
|
||||||
if(!ep0.IsNull()){
|
if(!ep0.IsNull()){
|
||||||
EarHeap.push_back(EAR(ep0));
|
assert(!ep0.v->IsUserBit(EAR::NonManifoldBit()));
|
||||||
push_heap( EarHeap.begin(), EarHeap.end());
|
EarHeap.push(EAR(ep0));
|
||||||
}
|
}
|
||||||
if(!ep1.IsNull()){
|
if(!ep1.IsNull()){
|
||||||
EarHeap.push_back(EAR(ep1));
|
assert(!ep1.v->IsUserBit(EAR::NonManifoldBit()));
|
||||||
push_heap( EarHeap.begin(), EarHeap.end());
|
EarHeap.push(EAR(ep1));
|
||||||
}
|
}
|
||||||
--cnt;
|
--holeSize;
|
||||||
++f;
|
++f;
|
||||||
}
|
}
|
||||||
}//is update()
|
}//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()){
|
while(f!=m.face.end()){
|
||||||
tri::Allocator<MESH>::DeleteFace(m,*f);
|
tri::Allocator<MESH>::DeleteFace(m,*f);
|
||||||
f++;
|
f++;
|
||||||
}
|
}
|
||||||
|
|
||||||
VertexType::DeleteBitFlag(nmBit); // non manifoldness bit
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class EAR>
|
template<class EAR>
|
||||||
|
|
@ -504,7 +543,7 @@ template<class EAR>
|
||||||
if(cb) (*cb)(indCb*10/vinfo.size(),"Closing Holes");
|
if(cb) (*cb)(indCb*10/vinfo.size(),"Closing Holes");
|
||||||
if((*ith).size < sizeHole){
|
if((*ith).size < sizeHole){
|
||||||
holeCnt++;
|
holeCnt++;
|
||||||
FillHoleEar< EAR >(m, *ith,facePtrToBeUpdated);
|
FillHoleEar< EAR >(m, (*ith).p,facePtrToBeUpdated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return holeCnt;
|
return holeCnt;
|
||||||
|
|
@ -555,7 +594,7 @@ template<class EAR>
|
||||||
for(fpi=EAR::AdjacencyRing().begin();fpi!=EAR::AdjacencyRing().end();++fpi)
|
for(fpi=EAR::AdjacencyRing().begin();fpi!=EAR::AdjacencyRing().end();++fpi)
|
||||||
facePtrToBeUpdated.push_back( &*fpi );
|
facePtrToBeUpdated.push_back( &*fpi );
|
||||||
|
|
||||||
FillHoleEar<EAR >(m, *ith,facePtrToBeUpdated);
|
FillHoleEar<EAR >(m, ith->p,facePtrToBeUpdated);
|
||||||
EAR::AdjacencyRing().clear();
|
EAR::AdjacencyRing().clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -871,7 +910,7 @@ template<class EAR>
|
||||||
}while(sp != fp);
|
}while(sp != fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
};//close class Hole
|
};// class Hole
|
||||||
|
|
||||||
} // end namespace tri
|
} // end namespace tri
|
||||||
} // end namespace vcg
|
} // end namespace vcg
|
||||||
|
|
|
||||||
|
|
@ -20,83 +20,11 @@
|
||||||
* for more details. *
|
* 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
|
#ifndef __VCGLIB_LOCALOPTIMIZATION
|
||||||
#define __VCGLIB_LOCALOPTIMIZATION
|
#define __VCGLIB_LOCALOPTIMIZATION
|
||||||
#include<vector>
|
#include <vcg/complex/complex.h>
|
||||||
#include<algorithm>
|
#include <time.h>
|
||||||
#include<time.h>
|
|
||||||
#include<math.h>
|
|
||||||
#include<vcg/complex/complex.h>
|
|
||||||
|
|
||||||
namespace vcg{
|
namespace vcg{
|
||||||
// Base class for Parameters
|
// Base class for Parameters
|
||||||
// all parameters must be derived from this.
|
// all parameters must be derived from this.
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ namespace tri{
|
||||||
static void Init(){}
|
static void Init(){}
|
||||||
static math::Quadric<double> &Qd(VERTEX_TYPE &v) {return v.Qd();}
|
static math::Quadric<double> &Qd(VERTEX_TYPE &v) {return v.Qd();}
|
||||||
static math::Quadric<double> &Qd(VERTEX_TYPE *v) {return v->Qd();}
|
static math::Quadric<double> &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 typename VERTEX_TYPE::ScalarType W(VERTEX_TYPE &/*v*/) {return 1.0;}
|
||||||
static void Merge(VERTEX_TYPE & /*v_dest*/, VERTEX_TYPE const & /*v_del*/){}
|
static void Merge(VERTEX_TYPE & /*v_dest*/, VERTEX_TYPE const & /*v_del*/){}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -284,7 +284,7 @@ public:
|
||||||
const char* Info(TRIMESH_TYPE &m)
|
const char* Info(TRIMESH_TYPE &m)
|
||||||
{
|
{
|
||||||
static char dump[60];
|
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;
|
return dump;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
} // end namespace tri
|
||||||
|
|
|
||||||
|
|
@ -666,7 +666,7 @@ public:
|
||||||
CoordType dirR=vcg::tri::CrossField<MeshType>::Rotate(f0,f1,dir0);
|
CoordType dirR=vcg::tri::CrossField<MeshType>::Rotate(f0,f1,dir0);
|
||||||
///then get the closest upf to K*PI/2 rotations
|
///then get the closest upf to K*PI/2 rotations
|
||||||
CoordType dir1=f1.cPD1();
|
CoordType dir1=f1.cPD1();
|
||||||
CoordType ret=vcg::tri::CrossField<MeshType>::K_PI(dirR,dir1,f1.cN());
|
CoordType ret=vcg::tri::CrossField<MeshType>::K_PI(dir1,dirR,f1.cN());
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,11 @@ private:
|
||||||
bool vectorOwner;
|
bool vectorOwner;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
std::vector<CoordType> &SampleVec()
|
||||||
|
{
|
||||||
|
return *sampleVec;
|
||||||
|
}
|
||||||
|
|
||||||
void AddVert(const VertexType &p)
|
void AddVert(const VertexType &p)
|
||||||
{
|
{
|
||||||
sampleVec->push_back(p.cP());
|
sampleVec->push_back(p.cP());
|
||||||
|
|
@ -839,11 +844,11 @@ static void EdgeMeshUniform(MeshType &m, VertexSampler &ps, float radius, bool c
|
||||||
/// \brief Sample all the border corner vertices
|
/// \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.
|
/// 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)
|
static void VertexBorderCorner(MeshType & m, VertexSampler &ps, float angleRad)
|
||||||
{
|
{
|
||||||
typename MeshType::template PerVertexAttributeHandle <float> angleSumH = tri::Allocator<MeshType>:: template GetPerVertexAttribute<float> (m);
|
typename MeshType::template PerVertexAttributeHandle<float> angleSumH = tri::Allocator<MeshType>:: template GetPerVertexAttribute<float> (m);
|
||||||
|
|
||||||
for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
|
for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
|
||||||
angleSumH[vi]=0;
|
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
|
/// This is the main function that is used to build a poisson distribuition
|
||||||
/// starting from a dense sample cloud.
|
/// starting from a dense sample cloud (the montecarloMesh) by 'pruning' it.
|
||||||
/// Trivial approach that puts all the samples in a hashed UG and randomly choose a sample
|
/// 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
|
/// 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,
|
static void PoissonDiskPruning(VertexSampler &ps, MeshType &montecarloMesh,
|
||||||
ScalarType diskRadius, PoissonDiskParam &pp)
|
ScalarType diskRadius, PoissonDiskParam &pp)
|
||||||
{
|
{
|
||||||
|
|
@ -2256,12 +2266,12 @@ void PoissonPruning(MeshType &m, // the mesh that has to be pruned
|
||||||
|
|
||||||
/// \brief Low level wrapper for Poisson Disk Pruning
|
/// \brief Low level wrapper for Poisson Disk Pruning
|
||||||
///
|
///
|
||||||
/// This function simply takes a mesh and a radius and returns a vector
|
/// This function simply takes a mesh containing a point cloud to be pruned and a radius
|
||||||
/// of vertex pointers listing the "surviving" points.
|
/// It returns a vector of CoordType listing the "surviving" points.
|
||||||
//
|
///
|
||||||
template <class MeshType>
|
template <class MeshType>
|
||||||
void PoissonPruning(MeshType &m, // the mesh that has to be pruned
|
void PoissonPruning(MeshType &m, // the mesh that has to be pruned
|
||||||
std::vector<Point3f> &poissonSamples, // the vector that will contain the chosen set of points
|
std::vector<typename MeshType::CoordType> &poissonSamples, // the vector that will contain the chosen set of points
|
||||||
float radius, unsigned int randSeed=0)
|
float radius, unsigned int randSeed=0)
|
||||||
{
|
{
|
||||||
std::vector<typename MeshType::VertexPointer> poissonSamplesVP;
|
std::vector<typename MeshType::VertexPointer> poissonSamplesVP;
|
||||||
|
|
|
||||||
|
|
@ -676,6 +676,8 @@ public:
|
||||||
UV.clear();
|
UV.clear();
|
||||||
Pmesh.Clear();
|
Pmesh.Clear();
|
||||||
|
|
||||||
|
vcg::tri::UpdateTopology<TriMesh>::FaceFace(Tmesh);
|
||||||
|
|
||||||
TestIsProper(Tmesh);
|
TestIsProper(Tmesh);
|
||||||
|
|
||||||
RoundInitial(Tmesh);
|
RoundInitial(Tmesh);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
/****************************************************************************
|
||||||
|
* VCGLib o o *
|
||||||
|
* Visual and Computer Graphics Library o o *
|
||||||
|
* _ O _ *
|
||||||
|
* Copyright(C) 2004-2016 \/)\/ *
|
||||||
|
* Visual Computing Lab /\/| *
|
||||||
|
* ISTI - Italian National Research Council | *
|
||||||
|
* \ *
|
||||||
|
* All rights reserved. *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||||
|
* for more details. *
|
||||||
|
* *
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef VCG__SKELETON_H
|
||||||
|
#define VCG__SKELETON_H
|
||||||
|
#include<vcg/complex/algorithms/voronoi_volume_sampling.h>
|
||||||
|
|
||||||
|
namespace vcg
|
||||||
|
{
|
||||||
|
namespace tri
|
||||||
|
{
|
||||||
|
|
||||||
|
template <class MeshType>
|
||||||
|
class SampledSkeleton
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename MeshType::ScalarType ScalarType;
|
||||||
|
typedef typename MeshType::BoxType BoxType;
|
||||||
|
typedef typename MeshType::VertexIterator VertexIterator;
|
||||||
|
typedef typename MeshType::VertexPointer VertexPointer;
|
||||||
|
typedef typename MeshType::CoordType CoordType;
|
||||||
|
typedef typename MeshType::FacePointer FacePointer;
|
||||||
|
typedef typename MeshType::FaceType FaceType;
|
||||||
|
typedef VoronoiVolumeSampling<MeshType> VoronoiVolumeSamplingType;
|
||||||
|
SampledSkeleton(VoronoiVolumeSamplingType &_vvs):vvs(_vvs){}
|
||||||
|
|
||||||
|
VoronoiVolumeSamplingType &vvs;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compute an evaulation of the thickness as distance from the medial axis.
|
||||||
|
* It starts from a montecarlo volume sampling and try to search for the samples that can be part of the medial axis.
|
||||||
|
* It use a sampled representation of the surface. A volume sample is considered part
|
||||||
|
* of the medial axis if there are at least two points that are (almost) the same minimal distance to that point.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void ThicknessEvaluator(float distThr, int smoothSize, int smoothIter, MeshType *skelM=0)
|
||||||
|
{
|
||||||
|
tri::UpdateQuality<MeshType>::VertexConstant(vvs.psd.poissonSurfaceMesh,0);
|
||||||
|
std::vector<VertexPointer> medialSrc(vvs.psd.poissonSurfaceMesh.vert.size(),0);
|
||||||
|
for(VertexIterator vi=vvs.montecarloVolumeMesh.vert.begin(); vi!=vvs.montecarloVolumeMesh.vert.end(); ++vi)
|
||||||
|
{
|
||||||
|
unsigned int ind;
|
||||||
|
ScalarType sqdist;
|
||||||
|
this->vvs.psd.surfTree->doQueryClosest(vi->P(),ind,sqdist);
|
||||||
|
VertexPointer vp = &vvs.psd.poissonSurfaceMesh.vert[ind];
|
||||||
|
ScalarType minDist = math::Sqrt(sqdist);
|
||||||
|
if(vp->Q() < minDist)
|
||||||
|
{
|
||||||
|
std::vector<unsigned int> indVec;
|
||||||
|
std::vector<ScalarType> sqDistVec;
|
||||||
|
|
||||||
|
this->vvs.psd.surfTree->doQueryDist( vi->P(), minDist*distThr,indVec,sqDistVec);
|
||||||
|
if(indVec.size()>1)
|
||||||
|
{
|
||||||
|
for(size_t i=0;i<indVec.size();++i)
|
||||||
|
{
|
||||||
|
VertexPointer vp = &vvs.psd.poissonSurfaceMesh.vert[indVec[i]];
|
||||||
|
//ScalarType dist = math::Sqrt(sqDistVec[i]);
|
||||||
|
if(vp->Q() < minDist) {
|
||||||
|
vp->Q()=minDist;
|
||||||
|
medialSrc[indVec[i]]=&*vi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now collect the vertexes of the volume mesh that are on the medial surface
|
||||||
|
if(skelM)
|
||||||
|
{
|
||||||
|
tri::UpdateFlags<MeshType>::VertexClearV(vvs.montecarloVolumeMesh);
|
||||||
|
for(size_t i=0;i<medialSrc.size();++i)
|
||||||
|
medialSrc[i]->SetV();
|
||||||
|
for(VertexIterator vi=vvs.montecarloVolumeMesh.vert.begin(); vi!=vvs.montecarloVolumeMesh.vert.end(); ++vi)
|
||||||
|
if(vi->IsV()) tri::Allocator<MeshType>::AddVertex(*skelM,vi->P());
|
||||||
|
printf("Generated a medial surf of %i vertexes\n",skelM->vn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tri::Smooth<MeshType>::PointCloudQualityMedian(vvs.psd.poissonSurfaceMesh);
|
||||||
|
tri::Smooth<MeshType>::PointCloudQualityAverage(vvs.psd.poissonSurfaceMesh,smoothSize,smoothIter);
|
||||||
|
tri::UpdateColor<MeshType>::PerVertexQualityRamp(vvs.psd.poissonSurfaceMesh);
|
||||||
|
tri::RedetailSampler<MeshType> rs;
|
||||||
|
rs.init(&vvs.psd.poissonSurfaceMesh);
|
||||||
|
rs.dist_upper_bound = vvs.psd.poissonSurfaceMesh.bbox.Diag()*0.05 ;
|
||||||
|
rs.qualityFlag = true;
|
||||||
|
tri::SurfaceSampling<MeshType, RedetailSampler<MeshType> >::VertexUniform(vvs.baseMesh, rs, vvs.baseMesh.vn, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RefineSkeletonVolume(MeshType &skelMesh)
|
||||||
|
{
|
||||||
|
CoordType closestP;
|
||||||
|
int trialNum=0;
|
||||||
|
for(int i=0;i<skelMesh.vn;++i)
|
||||||
|
{
|
||||||
|
CoordType point = math::GeneratePointInBox3Uniform(vvs.rng,vvs.baseMesh.bbox);
|
||||||
|
trialNum++;
|
||||||
|
ScalarType d = this->DistanceFromSurface(point, closestP);
|
||||||
|
if(d<0){
|
||||||
|
vcg::tri::Allocator<MeshType>::AddVertex(vvs.montecarloVolumeMesh,point);
|
||||||
|
vvs.montecarloVolumeMesh.vert.back().Q() = fabs(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}; // end class
|
||||||
|
|
||||||
|
|
||||||
|
} // end namespace vcg
|
||||||
|
} // end namespace vcg
|
||||||
|
#endif // VCG__SKELETON_H
|
||||||
|
|
@ -226,6 +226,7 @@ public:
|
||||||
//create the sphere
|
//create the sphere
|
||||||
vcg::tri::Sphere<TriMeshType>(*sphere,SubDirections);
|
vcg::tri::Sphere<TriMeshType>(*sphere,SubDirections);
|
||||||
vcg::tri::UpdateBounding<TriMeshType>::Box(*sphere);
|
vcg::tri::UpdateBounding<TriMeshType>::Box(*sphere);
|
||||||
|
sphere->face.EnableMark();
|
||||||
|
|
||||||
///initialize grid
|
///initialize grid
|
||||||
GridSph.Set(sphere->face.begin(),sphere->face.end());
|
GridSph.Set(sphere->face.begin(),sphere->face.end());
|
||||||
|
|
|
||||||
|
|
@ -368,7 +368,6 @@ Note: The faux bit is used to color polygonal faces uniformly
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Perlin Noise.
|
/*! \brief Perlin Noise.
|
||||||
\return the number of changed vertexes (the selected ones)
|
|
||||||
|
|
||||||
Simple Perlin noise. To make things weirder each color band can have its own offset and frequency.
|
Simple Perlin noise. To make things weirder each color band can have its own offset and frequency.
|
||||||
Period is expressed in absolute terms.
|
Period is expressed in absolute terms.
|
||||||
|
|
@ -396,6 +395,34 @@ static void PerVertexPerlinNoise(MeshType& m, CoordType period, CoordType offset
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! \brief Perlin Color mixing.
|
||||||
|
|
||||||
|
Simple Perlin color mixing. Color 1 and 2 are mixed according the perlin noise function, with period and offset.
|
||||||
|
*/
|
||||||
|
static void PerVertexPerlinColoring(MeshType& m, ScalarType period, CoordType offset = CoordType(0, 0, 0), Color4b color1 = Color4b::Black, Color4b color2 = Color4b::White, bool onSelected = false)
|
||||||
|
{
|
||||||
|
RequirePerVertexColor(m);
|
||||||
|
|
||||||
|
CoordType p;
|
||||||
|
|
||||||
|
for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
|
||||||
|
if (!(*vi).IsD())
|
||||||
|
if ((!onSelected) || ((*vi).IsS()))
|
||||||
|
{
|
||||||
|
// perlin noise is defined in 022
|
||||||
|
p = (vi->P() / period) + offset;
|
||||||
|
double factor = (math::Perlin::Noise(p[0], p[1], p[2]) + 1.0) / 2.0;
|
||||||
|
|
||||||
|
int rr = (color1[0] * factor) + (color2[0] * (1.0 - factor));
|
||||||
|
int gg = (color1[1] * factor) + (color2[1] * (1.0 - factor));
|
||||||
|
int bb = (color1[2] * factor) + (color2[2] * (1.0 - factor));
|
||||||
|
int aa = (color1[3] * factor) + (color2[3] * (1.0 - factor));
|
||||||
|
|
||||||
|
(*vi).C() = Color4b(rr, gg, bb, aa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*! \brief Simple Noise adding function.
|
/*! \brief Simple Noise adding function.
|
||||||
It simply add signed noise to the color of the mesh. The noise has uniform distribution and the amplitude is +/-2^(noisebits-1).
|
It simply add signed noise to the color of the mesh. The noise has uniform distribution and the amplitude is +/-2^(noisebits-1).
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,10 @@ static void FaceFromVertex( MeshType &m)
|
||||||
tri::RequirePerVertexQuality(m);
|
tri::RequirePerVertexQuality(m);
|
||||||
for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
|
for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
|
||||||
{
|
{
|
||||||
(*fi).Q() = ((*fi).V(0)->Q()+(*fi).V(1)->Q()+(*fi).V(2)->Q())/3.0f;
|
(*fi).Q() =0;
|
||||||
|
for (size_t i=0;i<(*fi).VN();i++)
|
||||||
|
(*fi).Q() += (*fi).V(i)->Q();
|
||||||
|
(*fi).Q()/=(ScalarType)(*fi).VN();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -441,9 +441,8 @@ static size_t FaceOutOfRangeEdge(MeshType &m, ScalarType MinEdgeThr, ScalarType
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief This function expand current selection to cover the whole connected component.
|
/// \brief This function expand current selection to cover the whole connected component.
|
||||||
static size_t FaceConnectedFF(MeshType &m, bool preserveSelection=false)
|
static size_t FaceConnectedFF(MeshType &m)
|
||||||
{
|
{
|
||||||
if(!preserveSelection) FaceClear(m);
|
|
||||||
// it also assumes that the FF adjacency is well computed.
|
// it also assumes that the FF adjacency is well computed.
|
||||||
RequireFFAdjacency(m);
|
RequireFFAdjacency(m);
|
||||||
UpdateFlags<MeshType>::FaceClearV(m);
|
UpdateFlags<MeshType>::FaceClearV(m);
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ static void WedgeTexFromVertexTex(ComputeMeshType &m)
|
||||||
{
|
{
|
||||||
(*fi).WT(i).U() = (*fi).V(i)->T().U();
|
(*fi).WT(i).U() = (*fi).V(i)->T().U();
|
||||||
(*fi).WT(i).V() = (*fi).V(i)->T().V();
|
(*fi).WT(i).V() = (*fi).V(i)->T().V();
|
||||||
|
(*fi).WT(i).N() = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ struct VoronoiProcessingParameter
|
||||||
bool relaxOnlyConstrainedFlag;
|
bool relaxOnlyConstrainedFlag;
|
||||||
|
|
||||||
bool preserveFixedSeed; /// If true the 'fixed' seeds are not moved during relaxation.
|
bool preserveFixedSeed; /// If true the 'fixed' seeds are not moved during relaxation.
|
||||||
/// \see FixVertexVector function to see how to fix a set of seeds.
|
/// \see MarkVertexVectorAsFixed function to see how to fix a set of seeds.
|
||||||
|
|
||||||
float refinementRatio; /// It defines how much the input mesh has to be refined in order to have a supporting
|
float refinementRatio; /// It defines how much the input mesh has to be refined in order to have a supporting
|
||||||
/// triangulation that is dense enough to well approximate the voronoi diagram.
|
/// triangulation that is dense enough to well approximate the voronoi diagram.
|
||||||
|
|
@ -1195,7 +1195,7 @@ static void PruneSeedByRegionArea(std::vector<VertexType *> &seedVec,
|
||||||
/// Vertex pointers must belong to the mesh.
|
/// Vertex pointers must belong to the mesh.
|
||||||
/// The framework use a boolean attribute called "fixed" to store this info.
|
/// The framework use a boolean attribute called "fixed" to store this info.
|
||||||
///
|
///
|
||||||
static void FixVertexVector(MeshType &m, std::vector<VertexType *> &vertToFixVec)
|
static void MarkVertexVectorAsFixed(MeshType &m, std::vector<VertexType *> &vertToFixVec)
|
||||||
{
|
{
|
||||||
typename MeshType::template PerVertexAttributeHandle<bool> fixed;
|
typename MeshType::template PerVertexAttributeHandle<bool> fixed;
|
||||||
fixed = tri::Allocator<MeshType>:: template GetPerVertexAttribute<bool> (m,"fixed");
|
fixed = tri::Allocator<MeshType>:: template GetPerVertexAttribute<bool> (m,"fixed");
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,103 @@ namespace vcg
|
||||||
namespace tri
|
namespace tri
|
||||||
{
|
{
|
||||||
|
|
||||||
|
template <class MeshType>
|
||||||
|
class PointSampledDistance
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename MeshType::ScalarType ScalarType;
|
||||||
|
typedef typename MeshType::BoxType BoxType;
|
||||||
|
typedef typename MeshType::VertexIterator VertexIterator;
|
||||||
|
typedef typename MeshType::VertexPointer VertexPointer;
|
||||||
|
typedef typename MeshType::CoordType CoordType;
|
||||||
|
typedef typename MeshType::FacePointer FacePointer;
|
||||||
|
typedef typename MeshType::FaceType FaceType;
|
||||||
|
typedef typename vcg::GridStaticPtr<typename MeshType::FaceType, ScalarType> GridType;
|
||||||
|
|
||||||
|
typedef SimpleVolume<SimpleVoxel<ScalarType> > VVSVolume;
|
||||||
|
typedef typename vcg::tri::TrivialWalker<MeshType,VVSVolume> VVSWalker;
|
||||||
|
typedef typename vcg::tri::MarchingCubes<MeshType, VVSWalker> VVSMarchingCubes;
|
||||||
|
|
||||||
|
PointSampledDistance(MeshType &_baseMesh)
|
||||||
|
:surfTree(0),baseMesh(_baseMesh) {}
|
||||||
|
typename KdTree<ScalarType>::PriorityQueue pq;
|
||||||
|
GridType surfGrid; // used for fast inside query
|
||||||
|
typedef FaceTmark<MeshType> MarkerFace;
|
||||||
|
MarkerFace mf;
|
||||||
|
vcg::face::PointDistanceBaseFunctor<ScalarType> PDistFunct;
|
||||||
|
KdTree<ScalarType> *surfTree; // used for fast inside query
|
||||||
|
MeshType &baseMesh;
|
||||||
|
MeshType poissonSurfaceMesh;
|
||||||
|
ScalarType poissonRadiusSurface;
|
||||||
|
|
||||||
|
void Init(ScalarType _poissonRadiusSurface=0)
|
||||||
|
{
|
||||||
|
MeshType montecarloSurfaceMesh;
|
||||||
|
if(_poissonRadiusSurface==0) poissonRadiusSurface = baseMesh.bbox.Diag()/50.0f;
|
||||||
|
else poissonRadiusSurface = _poissonRadiusSurface;
|
||||||
|
ScalarType meshArea = Stat<MeshType>::ComputeMeshArea(baseMesh);
|
||||||
|
int MontecarloSurfSampleNum = 10 * meshArea / (poissonRadiusSurface*poissonRadiusSurface);
|
||||||
|
tri::MeshSampler<MeshType> sampler(montecarloSurfaceMesh);
|
||||||
|
tri::SurfaceSampling<MeshType,tri::MeshSampler<MeshType> >::Montecarlo(baseMesh, sampler, MontecarloSurfSampleNum);
|
||||||
|
montecarloSurfaceMesh.bbox = baseMesh.bbox; // we want the same bounding box
|
||||||
|
poissonSurfaceMesh.Clear();
|
||||||
|
tri::MeshSampler<MeshType> mps(poissonSurfaceMesh);
|
||||||
|
typename tri::SurfaceSampling<MeshType,tri::MeshSampler<MeshType> >::PoissonDiskParam pp;
|
||||||
|
pp.geodesicDistanceFlag=false;
|
||||||
|
|
||||||
|
tri::SurfaceSampling<MeshType,tri::MeshSampler<MeshType> >::PoissonDiskPruning(mps, montecarloSurfaceMesh, poissonRadiusSurface,pp);
|
||||||
|
vcg::tri::UpdateBounding<MeshType>::Box(poissonSurfaceMesh);
|
||||||
|
|
||||||
|
printf("Surface Sampling radius %f - montecarlo %ivn - Poisson %ivn\n",poissonRadiusSurface,montecarloSurfaceMesh.vn,poissonSurfaceMesh.vn);
|
||||||
|
VertexConstDataWrapper<MeshType> ww(poissonSurfaceMesh);
|
||||||
|
if(surfTree) delete surfTree;
|
||||||
|
surfTree = new KdTree<ScalarType>(ww);
|
||||||
|
|
||||||
|
surfGrid.SetWithRadius(baseMesh.face.begin(),baseMesh.face.end(),poissonRadiusSurface);
|
||||||
|
mf.SetMesh(&baseMesh);
|
||||||
|
}
|
||||||
|
// Compute the signed distance from the surface exploting both a kdtree and a ugrid
|
||||||
|
// for a query point p first we use the kdtree with a good poisson sampling of the surface;
|
||||||
|
// to get the nearest point on the surface, then if the point is far from the surface we can use the point point distance, while if it is near (e.g. less than 3*poisson radius) we rely on point face distance with a grid.
|
||||||
|
ScalarType DistanceFromSurface(const CoordType &q, CoordType &closestP)
|
||||||
|
{
|
||||||
|
ScalarType squaredDist;
|
||||||
|
unsigned int ind;
|
||||||
|
surfTree->doQueryClosest(q,ind,squaredDist);
|
||||||
|
ScalarType dist = sqrt(squaredDist);
|
||||||
|
if( dist > 3.0f*poissonRadiusSurface)
|
||||||
|
{
|
||||||
|
// CoordType dir = surfTree->getNeighbor(0) - p;
|
||||||
|
CoordType dir = this->poissonSurfaceMesh.vert[ind].P() - q;
|
||||||
|
const CoordType &surfN = this->poissonSurfaceMesh.vert[ind].N();
|
||||||
|
if(dir* surfN > 0) dist= -dist;
|
||||||
|
closestP=this->poissonSurfaceMesh.vert[ind].P();
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScalarType _maxDist = this->poissonRadiusSurface*3.0f;
|
||||||
|
dist=_maxDist;
|
||||||
|
FacePointer f=surfGrid.GetClosest(PDistFunct,mf,q,_maxDist,dist,closestP);
|
||||||
|
assert(f);
|
||||||
|
assert (dist >=0);
|
||||||
|
CoordType dir = closestP - q;
|
||||||
|
if(dir*f->cN() > 0) dist = -dist;
|
||||||
|
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Compute a well distributed set of samples (seeds) inside a watertight mesh.
|
||||||
|
*
|
||||||
|
* The main idea is that we have start from a poisson disk distribution and we improve it using Lloyd relaxation.
|
||||||
|
* To make things simpler and more controllable we estabilish since the beginning a Domain where we can choose the points.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template< class MeshType>
|
template< class MeshType>
|
||||||
class VoronoiVolumeSampling
|
class VoronoiVolumeSampling
|
||||||
{
|
{
|
||||||
|
|
@ -69,33 +166,26 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
VoronoiVolumeSampling(MeshType &_baseMesh)
|
VoronoiVolumeSampling(MeshType &_baseMesh)
|
||||||
:surfTree(0),seedTree(0),baseMesh(_baseMesh),cb(0),restrictedRelaxationFlag(false)
|
:seedTree(0),baseMesh(_baseMesh),cb(0),restrictedRelaxationFlag(false),psd(_baseMesh)
|
||||||
{
|
{
|
||||||
tri::RequirePerFaceMark(baseMesh);
|
tri::RequirePerFaceMark(baseMesh);
|
||||||
tri::UpdateBounding<MeshType>::Box(baseMesh);
|
tri::UpdateBounding<MeshType>::Box(baseMesh);
|
||||||
tri::UpdateNormal<MeshType>::PerFaceNormalized(baseMesh);
|
tri::UpdateNormal<MeshType>::PerFaceNormalized(baseMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
KdTree<ScalarType> *surfTree; // used for fast inside query
|
|
||||||
KdTree<ScalarType> *seedTree; // used to accumulate barycenter in relaxation
|
KdTree<ScalarType> *seedTree; // used to accumulate barycenter in relaxation
|
||||||
KdTree<ScalarType> *seedDomainTree; // used to accumulate barycenter in relaxation
|
KdTree<ScalarType> *seedDomainTree; // used to accumulate barycenter in relaxation
|
||||||
|
|
||||||
typename KdTree<ScalarType>::PriorityQueue pq;
|
typename KdTree<ScalarType>::PriorityQueue pq;
|
||||||
GridType surfGrid; // used for fast inside query
|
|
||||||
typedef FaceTmark<MeshType> MarkerFace;
|
|
||||||
MarkerFace mf;
|
|
||||||
vcg::face::PointDistanceBaseFunctor<ScalarType> PDistFunct;
|
|
||||||
|
|
||||||
MeshType &baseMesh;
|
|
||||||
|
MeshType &baseMesh; // The base mesh for which we compute all
|
||||||
MeshType seedMesh;
|
MeshType seedMesh;
|
||||||
MeshType poissonSurfaceMesh;
|
MeshType montecarloVolumeMesh; // we use this mesh as volume evaluator and to choose
|
||||||
ScalarType poissonRadiusSurface;
|
|
||||||
MeshType montecarloVolumeMesh; // we use this mesh as volume evaluator
|
|
||||||
MeshType seedDomainMesh; // where we choose the seeds (by default is the montecarlo volume mesh)
|
MeshType seedDomainMesh; // where we choose the seeds (by default is the montecarlo volume mesh)
|
||||||
vcg::CallBackPos *cb;
|
vcg::CallBackPos *cb;
|
||||||
math::MarsenneTwisterRNG rng;
|
math::MarsenneTwisterRNG rng;
|
||||||
bool restrictedRelaxationFlag;
|
bool restrictedRelaxationFlag;
|
||||||
|
PointSampledDistance<MeshType> psd;
|
||||||
|
|
||||||
// Build up the needed structure for efficient point in mesh search.
|
// Build up the needed structure for efficient point in mesh search.
|
||||||
// It uses a poisson disk sampling of the surface plus a
|
// It uses a poisson disk sampling of the surface plus a
|
||||||
|
|
@ -103,62 +193,11 @@ public:
|
||||||
// It initializes the surfGrid, surfTree and poissonSurfaceMesh members
|
// It initializes the surfGrid, surfTree and poissonSurfaceMesh members
|
||||||
void Init(ScalarType _poissonRadiusSurface=0)
|
void Init(ScalarType _poissonRadiusSurface=0)
|
||||||
{
|
{
|
||||||
MeshType montecarloSurfaceMesh;
|
psd.Init(_poissonRadiusSurface);
|
||||||
|
|
||||||
if(_poissonRadiusSurface==0) poissonRadiusSurface = baseMesh.bbox.Diag()/50.0f;
|
|
||||||
else poissonRadiusSurface = _poissonRadiusSurface;
|
|
||||||
ScalarType meshArea = Stat<MeshType>::ComputeMeshArea(baseMesh);
|
|
||||||
int MontecarloSurfSampleNum = 10 * meshArea / (poissonRadiusSurface*poissonRadiusSurface);
|
|
||||||
tri::MeshSampler<MeshType> sampler(montecarloSurfaceMesh);
|
|
||||||
tri::SurfaceSampling<MeshType,tri::MeshSampler<MeshType> >::SamplingRandomGenerator()=rng;
|
tri::SurfaceSampling<MeshType,tri::MeshSampler<MeshType> >::SamplingRandomGenerator()=rng;
|
||||||
tri::SurfaceSampling<MeshType,tri::MeshSampler<MeshType> >::Montecarlo(baseMesh, sampler, MontecarloSurfSampleNum);
|
|
||||||
montecarloSurfaceMesh.bbox = baseMesh.bbox; // we want the same bounding box
|
|
||||||
poissonSurfaceMesh.Clear();
|
|
||||||
tri::MeshSampler<MeshType> mps(poissonSurfaceMesh);
|
|
||||||
typename tri::SurfaceSampling<MeshType,tri::MeshSampler<MeshType> >::PoissonDiskParam pp;
|
|
||||||
pp.geodesicDistanceFlag=false;
|
|
||||||
|
|
||||||
tri::SurfaceSampling<MeshType,tri::MeshSampler<MeshType> >::PoissonDiskPruning(mps, montecarloSurfaceMesh, poissonRadiusSurface,pp);
|
|
||||||
vcg::tri::UpdateBounding<MeshType>::Box(poissonSurfaceMesh);
|
|
||||||
|
|
||||||
printf("Surface Sampling radius %f - montecarlo %ivn - Poisson %ivn\n",poissonRadiusSurface,montecarloSurfaceMesh.vn,poissonSurfaceMesh.vn);
|
|
||||||
VertexConstDataWrapper<MeshType> ww(poissonSurfaceMesh);
|
|
||||||
if(surfTree) delete surfTree;
|
|
||||||
surfTree = new KdTree<ScalarType>(ww);
|
|
||||||
|
|
||||||
surfGrid.SetWithRadius(baseMesh.face.begin(),baseMesh.face.end(),poissonRadiusSurface);
|
|
||||||
mf.SetMesh(&baseMesh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the signed distance from the surface exploting both a kdtree and a ugrid
|
|
||||||
// for a query point p first we use the kdtree with a good poisson sampling of the surface;
|
|
||||||
// to get the nearest point on the surface, then if the point is far from the surface we can use the point point distance, while if it is near (e.g. less than 3*poisson radius) we rely on point face distance with a grid.
|
|
||||||
ScalarType DistanceFromSurface(const CoordType &q, CoordType &closestP)
|
|
||||||
{
|
|
||||||
ScalarType squaredDist;
|
|
||||||
unsigned int ind;
|
|
||||||
surfTree->doQueryClosest(q,ind,squaredDist);
|
|
||||||
ScalarType dist = sqrt(squaredDist);
|
|
||||||
if( dist > 3.0f*poissonRadiusSurface)
|
|
||||||
{
|
|
||||||
// CoordType dir = surfTree->getNeighbor(0) - p;
|
|
||||||
CoordType dir = this->poissonSurfaceMesh.vert[ind].P() - q;
|
|
||||||
const CoordType &surfN = this->poissonSurfaceMesh.vert[ind].N();
|
|
||||||
if(dir* surfN > 0) dist= -dist;
|
|
||||||
closestP=this->poissonSurfaceMesh.vert[ind].P();
|
|
||||||
return dist;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScalarType _maxDist = this->poissonRadiusSurface*3.0f;
|
|
||||||
dist=_maxDist;
|
|
||||||
FacePointer f=surfGrid.GetClosest(PDistFunct,mf,q,_maxDist,dist,closestP);
|
|
||||||
assert(f);
|
|
||||||
assert (dist >=0);
|
|
||||||
CoordType dir = closestP - q;
|
|
||||||
if(dir*f->cN() > 0) dist = -dist;
|
|
||||||
|
|
||||||
return dist;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ScalarType DistanceFromVoronoiSeed(const CoordType &p_point)
|
ScalarType DistanceFromVoronoiSeed(const CoordType &p_point)
|
||||||
|
|
@ -389,7 +428,7 @@ void QuadricRelaxVoronoiSamples(int relaxStep)
|
||||||
ScalarType ImplicitFunction(const CoordType &p, const Param &pp)
|
ScalarType ImplicitFunction(const CoordType &p, const Param &pp)
|
||||||
{
|
{
|
||||||
CoordType closest;
|
CoordType closest;
|
||||||
ScalarType surfDist = this->DistanceFromSurface(p,closest);
|
ScalarType surfDist = this->psd.DistanceFromSurface(p,closest);
|
||||||
|
|
||||||
ScalarType elemDist;
|
ScalarType elemDist;
|
||||||
switch(pp.elemType)
|
switch(pp.elemType)
|
||||||
|
|
@ -543,86 +582,16 @@ void OptimizeIsosurf(MeshType &m, const Param &pp)
|
||||||
printf("Optimize Isosurf performed %i edge flip in %5.2f s\n",flipCnt,float(t1-t0)/CLOCKS_PER_SEC);
|
printf("Optimize Isosurf performed %i edge flip in %5.2f s\n",flipCnt,float(t1-t0)/CLOCKS_PER_SEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Given a surface sampling it adds to the montecarloVolumeMesh, a number of near surface samples.
|
||||||
|
* For each surface it try to add a sample generated as a point in the half ball of <radius> centered on the sample.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
void RefineMontecarloVolumeSamplingNearSurface(MeshType &surfaceSamplingMesh, ScalarType radius, int perSampleNum)
|
||||||
* @brief Compute an evaulation of the thickness as distance from the medial axis.
|
{
|
||||||
* It starts from a montecarlo volume sampling and try to search for the samples that can be part of the medial axis.
|
|
||||||
* It use a sampled representation of the surface. A volume sample is considered part
|
|
||||||
* of the medial axis if there are at least two points that are (almost) the same minimal distance to that point.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void ThicknessEvaluator(float distThr, int smoothSize, int smoothIter, MeshType *skelM=0)
|
|
||||||
{
|
|
||||||
tri::UpdateQuality<MeshType>::VertexConstant(poissonSurfaceMesh,0);
|
|
||||||
std::vector<VertexPointer> medialSrc(poissonSurfaceMesh.vert.size(),0);
|
|
||||||
for(VertexIterator vi=montecarloVolumeMesh.vert.begin(); vi!=montecarloVolumeMesh.vert.end(); ++vi)
|
|
||||||
{
|
|
||||||
unsigned int ind;
|
|
||||||
ScalarType sqdist;
|
|
||||||
this->surfTree->doQueryClosest(vi->P(),ind,sqdist);
|
|
||||||
VertexPointer vp = &poissonSurfaceMesh.vert[ind];
|
|
||||||
ScalarType minDist = math::Sqrt(sqdist);
|
|
||||||
if(vp->Q() < minDist)
|
|
||||||
{
|
|
||||||
std::vector<unsigned int> indVec;
|
|
||||||
std::vector<ScalarType> sqDistVec;
|
|
||||||
|
|
||||||
this->surfTree->doQueryDist( vi->P(), minDist*distThr,indVec,sqDistVec);
|
}
|
||||||
if(indVec.size()>1)
|
|
||||||
{
|
|
||||||
for(size_t i=0;i<indVec.size();++i)
|
|
||||||
{
|
|
||||||
VertexPointer vp = &poissonSurfaceMesh.vert[indVec[i]];
|
|
||||||
//ScalarType dist = math::Sqrt(sqDistVec[i]);
|
|
||||||
if(vp->Q() < minDist) {
|
|
||||||
vp->Q()=minDist;
|
|
||||||
medialSrc[indVec[i]]=&*vi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Now collect the vertexes of the volume mesh that are on the medial surface
|
|
||||||
if(skelM)
|
|
||||||
{
|
|
||||||
tri::UpdateFlags<MeshType>::VertexClearV(montecarloVolumeMesh);
|
|
||||||
for(size_t i=0;i<medialSrc.size();++i)
|
|
||||||
medialSrc[i]->SetV();
|
|
||||||
for(VertexIterator vi=montecarloVolumeMesh.vert.begin(); vi!=montecarloVolumeMesh.vert.end(); ++vi)
|
|
||||||
if(vi->IsV()) tri::Allocator<MeshType>::AddVertex(*skelM,vi->P());
|
|
||||||
printf("Generated a medial surf of %i vertexes\n",skelM->vn);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void BuildMontecarloVolumeSampling(int montecarloSampleNum)
|
||||||
tri::Smooth<MeshType>::PointCloudQualityMedian(poissonSurfaceMesh);
|
|
||||||
tri::Smooth<MeshType>::PointCloudQualityAverage(poissonSurfaceMesh,smoothSize,smoothIter);
|
|
||||||
tri::UpdateColor<MeshType>::PerVertexQualityRamp(poissonSurfaceMesh);
|
|
||||||
tri::RedetailSampler<MeshType> rs;
|
|
||||||
rs.init(&poissonSurfaceMesh);
|
|
||||||
rs.dist_upper_bound = poissonSurfaceMesh.bbox.Diag()*0.05 ;
|
|
||||||
rs.qualityFlag = true;
|
|
||||||
tri::SurfaceSampling<MeshType, RedetailSampler<MeshType> >::VertexUniform(baseMesh, rs, baseMesh.vn, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RefineSkeletonVolume(MeshType &skelMesh)
|
|
||||||
{
|
|
||||||
CoordType closestP;
|
|
||||||
int trialNum=0;
|
|
||||||
for(int i=0;i<skelMesh.vn;++i)
|
|
||||||
{
|
|
||||||
CoordType point = math::GeneratePointInBox3Uniform(rng,baseMesh.bbox);
|
|
||||||
trialNum++;
|
|
||||||
ScalarType d = this->DistanceFromSurface(point, closestP);
|
|
||||||
if(d<0){
|
|
||||||
vcg::tri::Allocator<MeshType>::AddVertex(montecarloVolumeMesh,point);
|
|
||||||
montecarloVolumeMesh.vert.back().Q() = fabs(d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void BuildMontecarloSampling(int montecarloSampleNum)
|
|
||||||
{
|
{
|
||||||
montecarloVolumeMesh.Clear();
|
montecarloVolumeMesh.Clear();
|
||||||
|
|
||||||
|
|
@ -632,7 +601,7 @@ void OptimizeIsosurf(MeshType &m, const Param &pp)
|
||||||
{
|
{
|
||||||
CoordType point = math::GeneratePointInBox3Uniform(rng,baseMesh.bbox);
|
CoordType point = math::GeneratePointInBox3Uniform(rng,baseMesh.bbox);
|
||||||
trialNum++;
|
trialNum++;
|
||||||
ScalarType d = this->DistanceFromSurface(point,closest);
|
ScalarType d = this->psd.DistanceFromSurface(point,closest);
|
||||||
if(d<0){
|
if(d<0){
|
||||||
vcg::tri::Allocator<MeshType>::AddVertex(montecarloVolumeMesh,point);
|
vcg::tri::Allocator<MeshType>::AddVertex(montecarloVolumeMesh,point);
|
||||||
montecarloVolumeMesh.vert.back().Q() = fabs(d);
|
montecarloVolumeMesh.vert.back().Q() = fabs(d);
|
||||||
|
|
@ -647,26 +616,23 @@ void OptimizeIsosurf(MeshType &m, const Param &pp)
|
||||||
/*
|
/*
|
||||||
* Function: BuildVolumeSampling
|
* Function: BuildVolumeSampling
|
||||||
* ----------------------------
|
* ----------------------------
|
||||||
* Build a Poisson-Disk Point cloud that cover all the space of the original mesh m
|
* Build and prepare the seed set.
|
||||||
|
* This is the starting point for the subsequent relaxation calls.
|
||||||
|
* You can insert some initial seeds into the seed set and they will be preserved
|
||||||
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void BuildVolumeSampling(int montecarloSampleNum, int poissonSampleNum, ScalarType &poissonRadius, int randSeed)
|
void BuildVolumeSampling(int montecarloSampleNum, ScalarType &poissonRadius, int randSeed)
|
||||||
{
|
{
|
||||||
if(montecarloSampleNum >0)
|
if(montecarloSampleNum >0)
|
||||||
this->BuildMontecarloSampling(montecarloSampleNum);
|
this->BuildMontecarloVolumeSampling(montecarloSampleNum);
|
||||||
if(seedDomainMesh.vn == 0)
|
if(this->seedDomainMesh.vn == 0)
|
||||||
tri::Append<MeshType,MeshType>::MeshCopy(seedDomainMesh,montecarloVolumeMesh);
|
tri::Append<MeshType,MeshType>::MeshCopy(seedDomainMesh,montecarloVolumeMesh);
|
||||||
|
|
||||||
vector<VertexPointer> pruningVec;
|
std::vector<CoordType> seedPts;
|
||||||
if(poissonRadius ==0 && poissonSampleNum!=0)
|
tri::PoissonPruning(seedDomainMesh,seedPts,poissonRadius,randSeed);
|
||||||
tri::PoissonPruningExact(seedDomainMesh,pruningVec,poissonRadius,poissonSampleNum,0.04,10,randSeed);
|
|
||||||
else
|
|
||||||
tri::PoissonPruning(seedDomainMesh,pruningVec,poissonRadius,randSeed);
|
|
||||||
|
|
||||||
std::vector<CoordType> seedPts(pruningVec.size());
|
|
||||||
for(size_t i=0;i<pruningVec.size();++i)
|
|
||||||
seedPts[i]=pruningVec[i]->P();
|
|
||||||
tri::BuildMeshFromCoordVector(this->seedMesh,seedPts);
|
tri::BuildMeshFromCoordVector(this->seedMesh,seedPts);
|
||||||
|
|
||||||
// Kdtree must be rebuilt at the end of each step;
|
// Kdtree must be rebuilt at the end of each step;
|
||||||
VertexConstDataWrapper<MeshType> vdw(seedMesh);
|
VertexConstDataWrapper<MeshType> vdw(seedMesh);
|
||||||
if(seedTree) delete seedTree;
|
if(seedTree) delete seedTree;
|
||||||
|
|
|
||||||
|
|
@ -52,13 +52,13 @@ template<class MeshType>
|
||||||
size_t Index(MeshType &m, const typename MeshType::HEdgeType* h) {return h-&*m.hedge.begin();}
|
size_t Index(MeshType &m, const typename MeshType::HEdgeType* h) {return h-&*m.hedge.begin();}
|
||||||
|
|
||||||
template<class MeshType>
|
template<class MeshType>
|
||||||
bool IsValidPointer( MeshType & m, const typename MeshType::VertexType *vp) { return ( (vp >= &*m.vert.begin()) && ( vp < &*m.vert.end()) ); }
|
bool IsValidPointer( MeshType & m, const typename MeshType::VertexType *vp) { return ( m.vert.size() > 0 && (vp >= &*m.vert.begin()) && (vp <= &m.vert.back()) ); }
|
||||||
template<class MeshType>
|
template<class MeshType>
|
||||||
bool IsValidPointer( MeshType & m, const typename MeshType::EdgeType *ep) { return ( (ep >= &*m.edge.begin()) && ( ep < &*m.edge.end()) ); }
|
bool IsValidPointer(MeshType & m, const typename MeshType::EdgeType *ep) { return ( m.edge.size() > 0 && (ep >= &*m.edge.begin()) && (ep <= &m.edge.back())); }
|
||||||
template<class MeshType>
|
template<class MeshType>
|
||||||
bool IsValidPointer( MeshType & m, const typename MeshType::FaceType *fp) { return ( (fp >= &*m.face.begin()) && ( fp < &*m.face.end()) ); }
|
bool IsValidPointer(MeshType & m, const typename MeshType::FaceType *fp) { return ( m.face.size() > 0 && (fp >= &*m.face.begin()) && (fp <= &m.face.back())); }
|
||||||
template<class MeshType>
|
template<class MeshType>
|
||||||
bool IsValidPointer( MeshType & m, const typename MeshType::HEdgeType *hp) { return ( (hp >= &*m.hedge.begin())&& ( hp < &*m.hedge.end()) ); }
|
bool IsValidPointer(MeshType & m, const typename MeshType::HEdgeType *hp) { return ( m.hedge.size() > 0 && (hp >= &*m.hedge.begin()) && (hp <= &m.hedge.back())); }
|
||||||
|
|
||||||
template <class MeshType, class ATTR_CONT>
|
template <class MeshType, class ATTR_CONT>
|
||||||
void ReorderAttribute(ATTR_CONT &c, std::vector<size_t> & newVertIndex, MeshType & /* m */){
|
void ReorderAttribute(ATTR_CONT &c, std::vector<size_t> & newVertIndex, MeshType & /* m */){
|
||||||
|
|
@ -1516,13 +1516,18 @@ public:
|
||||||
return;}
|
return;}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DeletePerMeshAttribute( MeshType & m, std::string name){
|
// Generic DeleteAttribute.
|
||||||
|
// It must not crash if you try to delete a non existing attribute,
|
||||||
|
// because you do not have a way of asking for a handle of an attribute for which you do not know the type.
|
||||||
|
static bool DeletePerMeshAttribute( MeshType & m, std::string name){
|
||||||
AttrIterator i;
|
AttrIterator i;
|
||||||
PointerToAttribute h1; h1._name = name;
|
PointerToAttribute h1; h1._name = name;
|
||||||
i = m.mesh_attr.find(h1);
|
i = m.mesh_attr.find(h1);
|
||||||
assert(i!=m.mesh_attr.end());
|
if (i==m.mesh_attr.end())
|
||||||
|
return false;
|
||||||
delete ((SimpleTempDataBase *)(*i)._handle);
|
delete ((SimpleTempDataBase *)(*i)._handle);
|
||||||
m.mesh_attr.erase(i);
|
m.mesh_attr.erase(i);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ATTR_TYPE>
|
template <class ATTR_TYPE>
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ Edited Comments and GPL license
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <cmath>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
@ -196,7 +197,7 @@ template<class T> int IsNAN(T t) { return _isnan(t) || (!_finite(t)); }
|
||||||
#elif defined(__MINGW32__) // GCC
|
#elif defined(__MINGW32__) // GCC
|
||||||
template<class T> int IsNAN(T t) { return std::isnan(t) || std::isinf(t); }
|
template<class T> int IsNAN(T t) { return std::isnan(t) || std::isinf(t); }
|
||||||
#elif defined(__GNUC__) // GCC
|
#elif defined(__GNUC__) // GCC
|
||||||
template<class T> int IsNAN(T t) { return isnan(t) || isinf(t); }
|
template<class T> int IsNAN(T t) { return std::isnan(t) || std::isinf(t); }
|
||||||
#else // generic
|
#else // generic
|
||||||
|
|
||||||
template<class T> int IsNAN(T t)
|
template<class T> int IsNAN(T t)
|
||||||
|
|
|
||||||
|
|
@ -138,12 +138,18 @@ public:
|
||||||
void operator*=( const T k );
|
void operator*=( const T k );
|
||||||
|
|
||||||
template <class Matrix44Type>
|
template <class Matrix44Type>
|
||||||
void ToMatrix(Matrix44Type & m) const {for(int i = 0; i < 16; i++) m.V()[i]=V()[i];}
|
void ToMatrix(Matrix44Type & m) const
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
m.V()[i]= V()[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ToEulerAngles(T &alpha, T &beta, T &gamma);
|
void ToEulerAngles(T &alpha, T &beta, T &gamma);
|
||||||
|
|
||||||
template <class Matrix44Type>
|
template <class Matrix44Type>
|
||||||
void FromMatrix(const Matrix44Type & m){for(int i = 0; i < 16; i++) V()[i]=m.V()[i];}
|
void FromMatrix(const Matrix44Type & m){for(int i = 0; i < 16; i++) V()[i]=T(m.V()[i]);}
|
||||||
|
|
||||||
template <class EigenMatrix44Type>
|
template <class EigenMatrix44Type>
|
||||||
void ToEigenMatrix(EigenMatrix44Type & m) const {
|
void ToEigenMatrix(EigenMatrix44Type & m) const {
|
||||||
|
|
|
||||||
|
|
@ -412,18 +412,6 @@ public:
|
||||||
return (((double)generate()) + 0.5)*(1.0/4294967296.0);
|
return (((double)generate()) + 0.5)*(1.0/4294967296.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a random triple of baricentric coords
|
|
||||||
template <class PointType>
|
|
||||||
void generateBarycentric(PointType &p){
|
|
||||||
p[1] = this->generate01();
|
|
||||||
p[2] = this->generate01();
|
|
||||||
|
|
||||||
if(p[1] + p[2] > 1.0){
|
|
||||||
p[1] = 1.0 - p[1];
|
|
||||||
p[2] = 1.0 - p[2];
|
|
||||||
}
|
|
||||||
p[0]=1.0-(p[1] + p[2]);
|
|
||||||
}
|
|
||||||
}; // end class MarsenneTwisterRNG
|
}; // end class MarsenneTwisterRNG
|
||||||
|
|
||||||
/* Returns a value with normal distribution with mean m, standard deviation s
|
/* Returns a value with normal distribution with mean m, standard deviation s
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ public:
|
||||||
RotoType rot; // rotation
|
RotoType rot; // rotation
|
||||||
Point3<S> tra; // viewpoint
|
Point3<S> tra; // viewpoint
|
||||||
public:
|
public:
|
||||||
ReferenceFrame(){}
|
ReferenceFrame():rot(),tra(){}
|
||||||
|
|
||||||
void SetIdentity(){ rot.SetIdentity(); tra = Point3<S>(0.0,0.0,0.0);}
|
void SetIdentity(){ rot.SetIdentity(); tra = Point3<S>(0.0,0.0,0.0);}
|
||||||
void SetTra(const Point3<S> & tr) {tra = tr;}
|
void SetTra(const Point3<S> & tr) {tra = tr;}
|
||||||
|
|
@ -87,18 +87,21 @@ public:
|
||||||
Camera<S> Intrinsics; // the camera that made the shot
|
Camera<S> Intrinsics; // the camera that made the shot
|
||||||
ReferenceFrame<S,RotationType> Extrinsics; // the position and orientation of the camera
|
ReferenceFrame<S,RotationType> Extrinsics; // the position and orientation of the camera
|
||||||
Shot(const Camera<S> &i, const ReferenceFrame<S,RotationType> &e)
|
Shot(const Camera<S> &i, const ReferenceFrame<S,RotationType> &e)
|
||||||
|
:Intrinsics(),Extrinsics()
|
||||||
{
|
{
|
||||||
Intrinsics = i;
|
Intrinsics = i;
|
||||||
Extrinsics = e;
|
Extrinsics = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
Shot(const Camera<S> &c)
|
Shot(const Camera<S> &c)
|
||||||
|
:Intrinsics(),Extrinsics()
|
||||||
{
|
{
|
||||||
Intrinsics = c;
|
Intrinsics = c;
|
||||||
Extrinsics.SetIdentity();
|
Extrinsics.SetIdentity();
|
||||||
}
|
}
|
||||||
|
|
||||||
Shot()
|
Shot()
|
||||||
|
:Intrinsics(),Extrinsics()
|
||||||
{
|
{
|
||||||
Extrinsics.SetIdentity();
|
Extrinsics.SetIdentity();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ inline bool IsEdgeBorder(EdgeType const & e, const int j )
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class VertexType>
|
template <class VertexType>
|
||||||
void VVStarVE(VertexType* vp, std::vector<VertexType *> &starVec)
|
void VVStarVE(const VertexType* vp, std::vector<VertexType *> &starVec)
|
||||||
{
|
{
|
||||||
starVec.clear();
|
starVec.clear();
|
||||||
edge::VEIterator<typename VertexType::EdgeType> vei(vp);
|
edge::VEIterator<typename VertexType::EdgeType> vei(vp);
|
||||||
|
|
|
||||||
|
|
@ -321,8 +321,8 @@ void FFAttach(FaceType * &f, int z1, FaceType *&f2, int z2)
|
||||||
template <class FaceType>
|
template <class FaceType>
|
||||||
void FFAttachManifold(FaceType * &f1, int z1, FaceType *&f2, int z2)
|
void FFAttachManifold(FaceType * &f1, int z1, FaceType *&f2, int z2)
|
||||||
{
|
{
|
||||||
assert(IsBorder<FaceType>(*f1,z1));
|
assert(IsBorder<FaceType>(*f1,z1) || f1->FFp(z1)==0);
|
||||||
assert(IsBorder<FaceType>(*f2,z2));
|
assert(IsBorder<FaceType>(*f2,z2) || f2->FFp(z2)==0);
|
||||||
assert(f1->V0(z1) == f2->V0(z2) || f1->V0(z1) == f2->V1(z2));
|
assert(f1->V0(z1) == f2->V0(z2) || f1->V0(z1) == f2->V1(z2));
|
||||||
assert(f1->V1(z1) == f2->V0(z2) || f1->V1(z1) == f2->V1(z2));
|
assert(f1->V1(z1) == f2->V0(z2) || f1->V1(z1) == f2->V1(z2));
|
||||||
f1->FFp(z1) = f2;
|
f1->FFp(z1) = f2;
|
||||||
|
|
@ -566,10 +566,10 @@ bool CheckFlipEdgeNormal(FaceType &f, const int z, const float angleRad)
|
||||||
|
|
||||||
assert((NewDiag1 != NewDiag0) && (NewDiag1 != OldDiag0) && (NewDiag1 != OldDiag1));
|
assert((NewDiag1 != NewDiag0) && (NewDiag1 != OldDiag0) && (NewDiag1 != OldDiag1));
|
||||||
|
|
||||||
CoordType oldN0 = NormalizedNormal( NewDiag0->cP(),OldDiag0->cP(),OldDiag1->cP());
|
CoordType oldN0 = Normal( NewDiag0->cP(),OldDiag0->cP(),OldDiag1->cP()).Normalize();
|
||||||
CoordType oldN1 = NormalizedNormal( NewDiag1->cP(),OldDiag1->cP(),OldDiag0->cP());
|
CoordType oldN1 = Normal( NewDiag1->cP(),OldDiag1->cP(),OldDiag0->cP()).Normalize();
|
||||||
CoordType newN0 = NormalizedNormal( OldDiag0->cP(),NewDiag1->cP(),NewDiag0->cP());
|
CoordType newN0 = Normal( OldDiag0->cP(),NewDiag1->cP(),NewDiag0->cP()).Normalize();
|
||||||
CoordType newN1 = NormalizedNormal( OldDiag1->cP(),NewDiag0->cP(),NewDiag1->cP());
|
CoordType newN1 = Normal( OldDiag1->cP(),NewDiag0->cP(),NewDiag1->cP()).Normalize();
|
||||||
if(AngleN(oldN0,newN0) > angleRad) return false;
|
if(AngleN(oldN0,newN0) > angleRad) return false;
|
||||||
if(AngleN(oldN0,newN1) > angleRad) return false;
|
if(AngleN(oldN0,newN1) > angleRad) return false;
|
||||||
if(AngleN(oldN1,newN0) > angleRad) return false;
|
if(AngleN(oldN1,newN0) > angleRad) return false;
|
||||||
|
|
@ -629,13 +629,28 @@ bool CheckFlipEdge(FaceType &f, int z)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Flip the z-th edge of the face f.
|
* Flip the z-th edge of the face f.
|
||||||
* Check for topological correctness first using <CODE>CheckFlipFace()</CODE>.
|
* Check for topological correctness first using <CODE>CheckFlipEdge()</CODE>.
|
||||||
* \param f pointer to the face
|
* \param f pointer to the face
|
||||||
* \param z the edge index
|
* \param z the edge index
|
||||||
*
|
*
|
||||||
* Note: For <em>edge flip</em> we intend the swap of the diagonal of the rectangle
|
* Note: For <em>edge flip</em> we intend the swap of the diagonal of the quadrilater
|
||||||
* formed by the face \a f and the face adjacent to the specified edge.
|
* formed by the face \a f and the face adjacent to the specified edge.
|
||||||
|
*
|
||||||
|
* 0__________ 2 0__________2
|
||||||
|
* -> 1|\ | | /|1
|
||||||
|
* | \ g | | g / |
|
||||||
|
* | \ | |w / |
|
||||||
|
* | f z\w | | / f z|
|
||||||
|
* | \ | | / |
|
||||||
|
* |__________\|1 <- 1|/__________|
|
||||||
|
* 2 0 2 0
|
||||||
|
*
|
||||||
|
* Note that, after an operation FlipEdge(f,z)
|
||||||
|
* to topologically revert it should be sufficient to do FlipEdge(f,z+1)
|
||||||
|
* (even if the mesh is actually different: f and g will be swapped)
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template <class FaceType>
|
template <class FaceType>
|
||||||
void FlipEdge(FaceType &f, const int z)
|
void FlipEdge(FaceType &f, const int z)
|
||||||
{
|
{
|
||||||
|
|
@ -644,14 +659,14 @@ void FlipEdge(FaceType &f, const int z)
|
||||||
assert( !IsBorder(f,z) );
|
assert( !IsBorder(f,z) );
|
||||||
assert( face::IsManifold<FaceType>(f, z));
|
assert( face::IsManifold<FaceType>(f, z));
|
||||||
|
|
||||||
FaceType *g = f.FFp(z);
|
FaceType *g = f.FFp(z); // The other face
|
||||||
int w = f.FFi(z);
|
int w = f.FFi(z); // and other side
|
||||||
|
|
||||||
assert( g->V(w) == f.V1(z) );
|
assert( g->V0(w) == f.V1(z) );
|
||||||
assert( g->V1(w)== f.V(z) );
|
assert( g->V1(w) == f.V0(z) );
|
||||||
assert( g->V2(w)!= f.V(z) );
|
assert( g->V2(w) != f.V0(z) );
|
||||||
assert( g->V2(w)!= f.V1(z) );
|
assert( g->V2(w) != f.V1(z) );
|
||||||
assert( g->V2(w)!= f.V2(z) );
|
assert( g->V2(w) != f.V2(z) );
|
||||||
|
|
||||||
f.V1(z) = g->V2(w);
|
f.V1(z) = g->V2(w);
|
||||||
g->V1(w) = f.V2(z);
|
g->V1(w) = f.V2(z);
|
||||||
|
|
@ -685,6 +700,7 @@ void FlipEdge(FaceType &f, const int z)
|
||||||
g->FFp(w)->FFp( g->FFi(w) ) = g;
|
g->FFp(w)->FFp( g->FFi(w) ) = g;
|
||||||
g->FFp(w)->FFi( g->FFi(w) ) = w;
|
g->FFp(w)->FFi( g->FFi(w) ) = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class FaceType>
|
template <class FaceType>
|
||||||
|
|
|
||||||
|
|
@ -435,8 +435,17 @@ public:
|
||||||
|
|
||||||
ScalarTypeCur &Kh(){ assert((*this).Base().CurvatureEnabled); return (*this).Base().CuV[(*this).Index()][0]; }
|
ScalarTypeCur &Kh(){ assert((*this).Base().CurvatureEnabled); return (*this).Base().CuV[(*this).Index()][0]; }
|
||||||
ScalarTypeCur &Kg(){ assert((*this).Base().CurvatureEnabled); return (*this).Base().CuV[(*this).Index()][1]; }
|
ScalarTypeCur &Kg(){ assert((*this).Base().CurvatureEnabled); return (*this).Base().CuV[(*this).Index()][1]; }
|
||||||
ScalarTypeCur cKh() const { assert((*this).Base().CurvatureEnabled); return (*this).Base().CuV[(*this).Index()][0]; }
|
ScalarTypeCur cKh() const
|
||||||
ScalarTypeCur cKg() const { assert((*this).Base().CurvatureEnabled); return (*this).Base().CuV[(*this).Index()][1]; }
|
{
|
||||||
|
assert((*this).Base().CurvatureEnabled);
|
||||||
|
return (*this).Base().CuV[(*this).Index()][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
ScalarTypeCur cKg() const
|
||||||
|
{
|
||||||
|
assert((*this).Base().CurvatureEnabled);
|
||||||
|
return (*this).Base().CuV[(*this).Index()][1];
|
||||||
|
}
|
||||||
|
|
||||||
template <class RightVertexType>
|
template <class RightVertexType>
|
||||||
void ImportData(const RightVertexType & rightV){
|
void ImportData(const RightVertexType & rightV){
|
||||||
|
|
@ -448,7 +457,11 @@ public:
|
||||||
TT::ImportData(rightV);
|
TT::ImportData(rightV);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool IsCurvatureEnabled( ) const { return this->Base().IsCurvatureDirEnabled(); }
|
inline bool IsCurvatureEnabled( ) const
|
||||||
|
{
|
||||||
|
return this->Base().IsCurvatureEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
static bool HasCurvature() { return true; }
|
static bool HasCurvature() { return true; }
|
||||||
static bool HasCurvatureOcf() { return true; }
|
static bool HasCurvatureOcf() { return true; }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -72,15 +72,15 @@ public:
|
||||||
{
|
{
|
||||||
return min!=p.min || max!=p.max;
|
return min!=p.min || max!=p.max;
|
||||||
}
|
}
|
||||||
/** Varia le dimensioni del bounding box scalandole rispetto al parametro scalare.
|
/** Offset of a vector (s,s,s)
|
||||||
@param s Valore scalare che indica di quanto deve variare il bounding box
|
|
||||||
*/
|
*/
|
||||||
void Offset( const BoxScalarType s )
|
void Offset( const BoxScalarType s )
|
||||||
{
|
{
|
||||||
Offset( Point3<BoxScalarType> (s,s,s));
|
Offset( Point3<BoxScalarType> (s,s,s));
|
||||||
}
|
}
|
||||||
/** Varia le dimensioni del bounding box del valore fornito attraverso il parametro.
|
/** Offset the two corner of the box of a vector delta.
|
||||||
@param delta Point in 3D space
|
* adding delta to max and -delta to min.
|
||||||
|
@param delta offset vector
|
||||||
*/
|
*/
|
||||||
void Offset( const Point3<BoxScalarType> & delta )
|
void Offset( const Point3<BoxScalarType> & delta )
|
||||||
{
|
{
|
||||||
|
|
@ -92,6 +92,7 @@ public:
|
||||||
{
|
{
|
||||||
min = max = p;
|
min = max = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the bounding box to a null value
|
/// Set the bounding box to a null value
|
||||||
void SetNull()
|
void SetNull()
|
||||||
{
|
{
|
||||||
|
|
@ -99,8 +100,8 @@ public:
|
||||||
min.Y()= 1; max.Y()= -1;
|
min.Y()= 1; max.Y()= -1;
|
||||||
min.Z()= 1; max.Z()= -1;
|
min.Z()= 1; max.Z()= -1;
|
||||||
}
|
}
|
||||||
/** Function to add two bounding box
|
/** Modify the current bbox to contain also the passed box.
|
||||||
@param b Il bounding box che si vuole aggiungere
|
* Adding a null bounding box does nothing
|
||||||
*/
|
*/
|
||||||
void Add( Box3<BoxScalarType> const & b )
|
void Add( Box3<BoxScalarType> const & b )
|
||||||
{
|
{
|
||||||
|
|
@ -117,9 +118,7 @@ public:
|
||||||
if(max.Z() < b.max.Z()) max.Z() = b.max.Z();
|
if(max.Z() < b.max.Z()) max.Z() = b.max.Z();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** Funzione per aggiungere un punto al bounding box. Il bounding box viene modificato se il punto
|
/** Modify the current bbox to contain also the passed point
|
||||||
cade fuori da esso.
|
|
||||||
@param p The point 3D
|
|
||||||
*/
|
*/
|
||||||
void Add( const Point3<BoxScalarType> & p )
|
void Add( const Point3<BoxScalarType> & p )
|
||||||
{
|
{
|
||||||
|
|
@ -136,9 +135,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Function to add a sphere (a point + radius) to a bbox
|
/** Modify the current bbox to contain also the passed sphere
|
||||||
@param p The point 3D
|
|
||||||
@param radius the radius of the sphere centered on p
|
|
||||||
*/
|
*/
|
||||||
void Add( const Point3<BoxScalarType> & p, const BoxScalarType radius )
|
void Add( const Point3<BoxScalarType> & p, const BoxScalarType radius )
|
||||||
{
|
{
|
||||||
|
|
@ -154,9 +151,12 @@ void Add( const Point3<BoxScalarType> & p, const BoxScalarType radius )
|
||||||
max.Z() = std::max(max.Z(),p.Z()+radius);
|
max.Z() = std::max(max.Z(),p.Z()+radius);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Aggiunge ad un box un altro box trasformato secondo la matrice m
|
/** Modify the current bbox to contain also the box b trasformed according to the matrix m
|
||||||
|
*/
|
||||||
void Add( const Matrix44<BoxScalarType> &m, const Box3<BoxScalarType> & b )
|
void Add( const Matrix44<BoxScalarType> &m, const Box3<BoxScalarType> & b )
|
||||||
{
|
{
|
||||||
|
if(b.IsNull()) return; // Adding a null bbox should do nothing
|
||||||
|
|
||||||
const Point3<BoxScalarType> &mn= b.min;
|
const Point3<BoxScalarType> &mn= b.min;
|
||||||
const Point3<BoxScalarType> &mx= b.max;
|
const Point3<BoxScalarType> &mx= b.max;
|
||||||
Add(m*(Point3<BoxScalarType>(mn[0],mn[1],mn[2])));
|
Add(m*(Point3<BoxScalarType>(mn[0],mn[1],mn[2])));
|
||||||
|
|
@ -191,9 +191,7 @@ void Add( const Point3<BoxScalarType> & p, const BoxScalarType radius )
|
||||||
min += p;
|
min += p;
|
||||||
max += p;
|
max += p;
|
||||||
}
|
}
|
||||||
/** Verifica se un punto appartiene ad un bounding box.
|
/** true if the point belong to the closed box
|
||||||
@param p The point 3D
|
|
||||||
@return True se p appartiene al bounding box, false altrimenti
|
|
||||||
*/
|
*/
|
||||||
bool IsIn( Point3<BoxScalarType> const & p ) const
|
bool IsIn( Point3<BoxScalarType> const & p ) const
|
||||||
{
|
{
|
||||||
|
|
@ -203,9 +201,8 @@ void Add( const Point3<BoxScalarType> & p, const BoxScalarType radius )
|
||||||
min.Z() <= p.Z() && p.Z() <= max.Z()
|
min.Z() <= p.Z() && p.Z() <= max.Z()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/** Verifica se un punto appartiene ad un bounding box aperto sul max.
|
/** true if the point belong to the open box (open on the max side)
|
||||||
@param p The point 3D
|
* e.g. if p in [min,max)
|
||||||
@return True se p appartiene al bounding box, false altrimenti
|
|
||||||
*/
|
*/
|
||||||
bool IsInEx( Point3<BoxScalarType> const & p ) const
|
bool IsInEx( Point3<BoxScalarType> const & p ) const
|
||||||
{
|
{
|
||||||
|
|
@ -234,15 +231,14 @@ void Add( const Point3<BoxScalarType> & p, const BoxScalarType radius )
|
||||||
b.min.Y()<max.Y() && b.max.Y()>min.Y() &&
|
b.min.Y()<max.Y() && b.max.Y()>min.Y() &&
|
||||||
b.min.Z()<max.Z() && b.max.Z()>min.Z() ;
|
b.min.Z()<max.Z() && b.max.Z()>min.Z() ;
|
||||||
}
|
}
|
||||||
/** Controlla se il bounding box e' nullo.
|
/**
|
||||||
@return True se il bounding box e' nullo, false altrimenti
|
return true if the box is null (e.g. invalid or not initialized);
|
||||||
*/
|
*/
|
||||||
bool IsNull() const { return min.X()>max.X() || min.Y()>max.Y() || min.Z()>max.Z(); }
|
bool IsNull() const { return min.X()>max.X() || min.Y()>max.Y() || min.Z()>max.Z(); }
|
||||||
/** Controlla se il bounding box e' vuoto.
|
/** return true if the box is empty (e.g. if min == max)
|
||||||
@return True se il bounding box e' vuoto, false altrimenti
|
|
||||||
*/
|
*/
|
||||||
bool IsEmpty() const { return min==max; }
|
bool IsEmpty() const { return min==max; }
|
||||||
/// Restituisce la lunghezza della diagonale del bounding box.
|
/// Return the lenght of the diagonal of the box .
|
||||||
BoxScalarType Diag() const
|
BoxScalarType Diag() const
|
||||||
{
|
{
|
||||||
return Distance(min,max);
|
return Distance(min,max);
|
||||||
|
|
@ -252,7 +248,7 @@ void Add( const Point3<BoxScalarType> & p, const BoxScalarType radius )
|
||||||
{
|
{
|
||||||
return SquaredDistance(min,max);
|
return SquaredDistance(min,max);
|
||||||
}
|
}
|
||||||
/// Calcola il centro del bounding box.
|
/// Return the center of the box.
|
||||||
Point3<BoxScalarType> Center() const
|
Point3<BoxScalarType> Center() const
|
||||||
{
|
{
|
||||||
return (min+max)/2;
|
return (min+max)/2;
|
||||||
|
|
@ -277,7 +273,7 @@ void Add( const Point3<BoxScalarType> & p, const BoxScalarType radius )
|
||||||
(p[2]-min[2])/(max[2]-min[2])
|
(p[2]-min[2])/(max[2]-min[2])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/// Calcola il volume del bounding box.
|
/// Return the volume of the box.
|
||||||
BoxScalarType Volume() const
|
BoxScalarType Volume() const
|
||||||
{
|
{
|
||||||
return (max.X()-min.X())*(max.Y()-min.Y())*(max.Z()-min.Z());
|
return (max.X()-min.X())*(max.Y()-min.Y())*(max.Z()-min.Z());
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,8 @@ public:
|
||||||
(*this)[3]=255;
|
(*this)[3]=255;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
float dummy;
|
||||||
|
h = modff(h,&dummy);
|
||||||
if(h==1.0) h = 0.0;
|
if(h==1.0) h = 0.0;
|
||||||
|
|
||||||
int i = int( floor(h*6.0) );
|
int i = int( floor(h*6.0) );
|
||||||
|
|
@ -279,6 +281,15 @@ inline void Color4<float>::Import(const Color4<unsigned char> &b)
|
||||||
(*this)[3]=b[3]/255.0f;
|
(*this)[3]=b[3]/255.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <> template <>
|
||||||
|
inline void Color4<double>::Import(const Color4<unsigned char> &b)
|
||||||
|
{
|
||||||
|
(*this)[0]=b[0]/255.0;
|
||||||
|
(*this)[1]=b[1]/255.0;
|
||||||
|
(*this)[2]=b[2]/255.0;
|
||||||
|
(*this)[3]=b[3]/255.0;
|
||||||
|
}
|
||||||
|
|
||||||
template <> template <>
|
template <> template <>
|
||||||
inline void Color4<unsigned char>::Import(const Color4<float> &b)
|
inline void Color4<unsigned char>::Import(const Color4<float> &b)
|
||||||
{
|
{
|
||||||
|
|
@ -297,6 +308,15 @@ inline void Color4<unsigned char>::Import(const Point4<float> &b)
|
||||||
(*this)[3]=(unsigned char)(b[3]*255.0f);
|
(*this)[3]=(unsigned char)(b[3]*255.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <> template <>
|
||||||
|
inline void Color4<unsigned char>::Import(const Point4<double> &b)
|
||||||
|
{
|
||||||
|
(*this)[0]=(unsigned char)(b[0]*255.0);
|
||||||
|
(*this)[1]=(unsigned char)(b[1]*255.0);
|
||||||
|
(*this)[2]=(unsigned char)(b[2]*255.0);
|
||||||
|
(*this)[3]=(unsigned char)(b[3]*255.0);
|
||||||
|
}
|
||||||
|
|
||||||
template <> template <>
|
template <> template <>
|
||||||
inline Color4<unsigned char> Color4<unsigned char>::Construct( const Color4<float> & b )
|
inline Color4<unsigned char> Color4<unsigned char>::Construct( const Color4<float> & b )
|
||||||
{
|
{
|
||||||
|
|
@ -317,6 +337,16 @@ inline Color4<float> Color4<float>::Construct( const Color4<unsigned char> & b )
|
||||||
(float)(b[3])/255.0f);
|
(float)(b[3])/255.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <> template <>
|
||||||
|
inline Color4<double> Color4<double>::Construct( const Color4<unsigned char> & b )
|
||||||
|
{
|
||||||
|
return Color4<double>(
|
||||||
|
(double)(b[0])/255.0,
|
||||||
|
(double)(b[1])/255.0,
|
||||||
|
(double)(b[2])/255.0,
|
||||||
|
(double)(b[3])/255.0);
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline Color4<unsigned char>::Color4(Color4<unsigned char>::ColorConstant cc)
|
inline Color4<unsigned char>::Color4(Color4<unsigned char>::ColorConstant cc)
|
||||||
{
|
{
|
||||||
|
|
@ -329,6 +359,12 @@ inline Color4<float>::Color4(Color4<float>::ColorConstant cc)
|
||||||
Import(Color4<unsigned char>((Color4<unsigned char>::ColorConstant)cc));
|
Import(Color4<unsigned char>((Color4<unsigned char>::ColorConstant)cc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline Color4<double>::Color4(Color4<double>::ColorConstant cc)
|
||||||
|
{
|
||||||
|
Import(Color4<unsigned char>((Color4<unsigned char>::ColorConstant)cc));
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline Color4<unsigned char>::Color4(unsigned int cc)
|
inline Color4<unsigned char>::Color4(unsigned int cc)
|
||||||
{
|
{
|
||||||
|
|
@ -341,6 +377,12 @@ inline Color4<float>::Color4(unsigned int cc)
|
||||||
Import(Color4<unsigned char>(cc));
|
Import(Color4<unsigned char>(cc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline Color4<double>::Color4(unsigned int cc)
|
||||||
|
{
|
||||||
|
Import(Color4<unsigned char>(cc));
|
||||||
|
}
|
||||||
|
|
||||||
inline Color4<float> Clamp(Color4<float> &c)
|
inline Color4<float> Clamp(Color4<float> &c)
|
||||||
{
|
{
|
||||||
c[0]=math::Clamp(c[0],0.0f,1.0f);
|
c[0]=math::Clamp(c[0],0.0f,1.0f);
|
||||||
|
|
@ -350,6 +392,15 @@ inline Color4<float> Clamp(Color4<float> &c)
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Color4<double> Clamp(Color4<double> &c)
|
||||||
|
{
|
||||||
|
c[0]=math::Clamp(c[0],0.0,1.0);
|
||||||
|
c[1]=math::Clamp(c[1],0.0,1.0);
|
||||||
|
c[2]=math::Clamp(c[2],0.0,1.0);
|
||||||
|
c[3]=math::Clamp(c[3],0.0,1.0);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline Color4<unsigned char> Color4<unsigned char>::operator + ( const Color4<unsigned char> & p) const
|
inline Color4<unsigned char> Color4<unsigned char>::operator + ( const Color4<unsigned char> & p) const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -145,9 +145,9 @@ public:
|
||||||
_v[1] = nv[1];
|
_v[1] = nv[1];
|
||||||
_v[2] = nv[2];
|
_v[2] = nv[2];
|
||||||
}
|
}
|
||||||
inline Point3 & operator =( Point3 const & p )
|
inline Point3 & operator =(Point3 const & p)
|
||||||
{
|
{
|
||||||
_v[0]= p._v[0]; _v[1]= p._v[1]; _v[2]= p._v[2];
|
_v[0] = p._v[0]; _v[1] = p._v[1]; _v[2] = p._v[2];
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
inline void SetZero()
|
inline void SetZero()
|
||||||
|
|
|
||||||
|
|
@ -61,8 +61,8 @@ namespace vcg {
|
||||||
class VectorConstDataWrapper :public ConstDataWrapper<typename StdVectorType::value_type>
|
class VectorConstDataWrapper :public ConstDataWrapper<typename StdVectorType::value_type>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
inline VectorConstDataWrapper(StdVectorType &vec):
|
inline VectorConstDataWrapper(StdVectorType &vec) :
|
||||||
ConstDataWrapper<typename StdVectorType::value_type> ( &(vec[0]), vec.size(), sizeof(typename StdVectorType::value_type))
|
ConstDataWrapper<typename StdVectorType::value_type>(&(vec[0]), vec.size(), sizeof(typename StdVectorType::value_type))
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -70,8 +70,8 @@ namespace vcg {
|
||||||
class VertexConstDataWrapper :public ConstDataWrapper<typename MeshType::CoordType>
|
class VertexConstDataWrapper :public ConstDataWrapper<typename MeshType::CoordType>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
inline VertexConstDataWrapper(MeshType &m):
|
inline VertexConstDataWrapper(MeshType &m) :
|
||||||
ConstDataWrapper<typename MeshType::CoordType> ( &(m.vert[0].P()), m.vert.size(), sizeof(typename MeshType::VertexType))
|
ConstDataWrapper<typename MeshType::CoordType>(&(m.vert[0].P()), m.vert.size(), sizeof(typename MeshType::VertexType))
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -96,9 +96,9 @@ namespace vcg {
|
||||||
//standard node
|
//standard node
|
||||||
struct {
|
struct {
|
||||||
Scalar splitValue;
|
Scalar splitValue;
|
||||||
unsigned int firstChildId:24;
|
unsigned int firstChildId : 24;
|
||||||
unsigned int dim:2;
|
unsigned int dim : 2;
|
||||||
unsigned int leaf:1;
|
unsigned int leaf : 1;
|
||||||
};
|
};
|
||||||
//leaf
|
//leaf
|
||||||
struct {
|
struct {
|
||||||
|
|
@ -112,10 +112,12 @@ namespace vcg {
|
||||||
// return the protected members which store the nodes and the points list
|
// return the protected members which store the nodes and the points list
|
||||||
inline const NodeList& _getNodes(void) { return mNodes; }
|
inline const NodeList& _getNodes(void) { return mNodes; }
|
||||||
inline const std::vector<VectorType>& _getPoints(void) { return mPoints; }
|
inline const std::vector<VectorType>& _getPoints(void) { return mPoints; }
|
||||||
|
inline unsigned int _getNumLevel(void) { return numLevel; }
|
||||||
|
inline const AxisAlignedBoxType& _getAABBox(void) { return mAABB; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
KdTree(const ConstDataWrapper<VectorType>& points, unsigned int nofPointsPerCell = 16, unsigned int maxDepth = 64);
|
KdTree(const ConstDataWrapper<VectorType>& points, unsigned int nofPointsPerCell = 16, unsigned int maxDepth = 64, bool balanced = false);
|
||||||
|
|
||||||
~KdTree();
|
~KdTree();
|
||||||
|
|
||||||
|
|
@ -140,7 +142,7 @@ namespace vcg {
|
||||||
// and returns the index of the first element of the second subset
|
// and returns the index of the first element of the second subset
|
||||||
unsigned int split(int start, int end, unsigned int dim, float splitValue);
|
unsigned int split(int start, int end, unsigned int dim, float splitValue);
|
||||||
|
|
||||||
int createTree(unsigned int nodeId, unsigned int start, unsigned int end, unsigned int level, unsigned int targetCellsize, unsigned int targetMaxDepth);
|
int createTree(unsigned int nodeId, unsigned int start, unsigned int end, unsigned int level);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
@ -148,28 +150,35 @@ namespace vcg {
|
||||||
NodeList mNodes; //kd-tree nodes
|
NodeList mNodes; //kd-tree nodes
|
||||||
std::vector<VectorType> mPoints; //points read from the input DataWrapper
|
std::vector<VectorType> mPoints; //points read from the input DataWrapper
|
||||||
std::vector<unsigned int> mIndices; //points indices
|
std::vector<unsigned int> mIndices; //points indices
|
||||||
|
unsigned int targetCellSize; //min number of point in a leaf
|
||||||
|
unsigned int targetMaxDepth; //max tree depth
|
||||||
|
unsigned int numLevel; //actual tree depth
|
||||||
|
bool isBalanced; //true if the tree is balanced
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename Scalar>
|
template<typename Scalar>
|
||||||
KdTree<Scalar>::KdTree(const ConstDataWrapper<VectorType>& points, unsigned int nofPointsPerCell, unsigned int maxDepth)
|
KdTree<Scalar>::KdTree(const ConstDataWrapper<VectorType>& points, unsigned int nofPointsPerCell, unsigned int maxDepth, bool balanced)
|
||||||
: mPoints(points.size()), mIndices(points.size())
|
: mPoints(points.size()), mIndices(points.size())
|
||||||
{
|
{
|
||||||
// compute the AABB of the input
|
// compute the AABB of the input
|
||||||
mPoints[0] = points[0];
|
mPoints[0] = points[0];
|
||||||
mAABB.Set(mPoints[0]);
|
mAABB.Set(mPoints[0]);
|
||||||
for (unsigned int i=1 ; i<mPoints.size() ; ++i)
|
for (unsigned int i = 1; i < mPoints.size(); ++i)
|
||||||
{
|
{
|
||||||
mPoints[i] = points[i];
|
mPoints[i] = points[i];
|
||||||
mIndices[i] = i;
|
mIndices[i] = i;
|
||||||
mAABB.Add(mPoints[i]);
|
mAABB.Add(mPoints[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
mNodes.reserve(4*mPoints.size()/nofPointsPerCell);
|
targetMaxDepth = maxDepth;
|
||||||
|
targetCellSize = nofPointsPerCell;
|
||||||
|
isBalanced = balanced;
|
||||||
|
//mNodes.reserve(4 * mPoints.size() / nofPointsPerCell);
|
||||||
//first node inserted (no leaf). The others are made by the createTree function (recursively)
|
//first node inserted (no leaf). The others are made by the createTree function (recursively)
|
||||||
mNodes.resize(1);
|
mNodes.resize(1);
|
||||||
mNodes.back().leaf = 0;
|
mNodes.back().leaf = 0;
|
||||||
/*int numLevel = */
|
numLevel = createTree(0, 0, mPoints.size(), 1);
|
||||||
createTree(0, 0, mPoints.size(), 1, nofPointsPerCell, maxDepth);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Scalar>
|
template<typename Scalar>
|
||||||
|
|
@ -200,7 +209,7 @@ namespace vcg {
|
||||||
mNeighborQueue.setMaxSize(k);
|
mNeighborQueue.setMaxSize(k);
|
||||||
mNeighborQueue.init();
|
mNeighborQueue.init();
|
||||||
|
|
||||||
QueryNode mNodeStack[64];
|
std::vector<QueryNode> mNodeStack(numLevel + 1);
|
||||||
mNodeStack[0].nodeId = 0;
|
mNodeStack[0].nodeId = 0;
|
||||||
mNodeStack[0].sq = 0.f;
|
mNodeStack[0].sq = 0.f;
|
||||||
unsigned int count = 1;
|
unsigned int count = 1;
|
||||||
|
|
@ -208,7 +217,7 @@ namespace vcg {
|
||||||
while (count)
|
while (count)
|
||||||
{
|
{
|
||||||
//we select the last node (AABB) inserted in the stack
|
//we select the last node (AABB) inserted in the stack
|
||||||
QueryNode& qnode = mNodeStack[count-1];
|
QueryNode& qnode = mNodeStack[count - 1];
|
||||||
|
|
||||||
//while going down the tree qnode.nodeId is the nearest sub-tree, otherwise,
|
//while going down the tree qnode.nodeId is the nearest sub-tree, otherwise,
|
||||||
//in backtracking, qnode.nodeId is the other sub-tree that will be visited iff
|
//in backtracking, qnode.nodeId is the other sub-tree that will be visited iff
|
||||||
|
|
@ -224,9 +233,9 @@ namespace vcg {
|
||||||
--count; //pop of the leaf
|
--count; //pop of the leaf
|
||||||
|
|
||||||
//end is the index of the last element of the leaf in mPoints
|
//end is the index of the last element of the leaf in mPoints
|
||||||
unsigned int end = node.start+node.size;
|
unsigned int end = node.start + node.size;
|
||||||
//adding the element of the leaf to the heap
|
//adding the element of the leaf to the heap
|
||||||
for (unsigned int i=node.start ; i<end ; ++i)
|
for (unsigned int i = node.start; i < end; ++i)
|
||||||
mNeighborQueue.insert(mIndices[i], vcg::SquaredNorm(queryPoint - mPoints[i]));
|
mNeighborQueue.insert(mIndices[i], vcg::SquaredNorm(queryPoint - mPoints[i]));
|
||||||
}
|
}
|
||||||
//otherwise, if we're not on a leaf
|
//otherwise, if we're not on a leaf
|
||||||
|
|
@ -240,12 +249,12 @@ namespace vcg {
|
||||||
{
|
{
|
||||||
mNodeStack[count].nodeId = node.firstChildId;
|
mNodeStack[count].nodeId = node.firstChildId;
|
||||||
//in the father's nodeId we save the index of the other sub-tree (for backtracking)
|
//in the father's nodeId we save the index of the other sub-tree (for backtracking)
|
||||||
qnode.nodeId = node.firstChildId+1;
|
qnode.nodeId = node.firstChildId + 1;
|
||||||
}
|
}
|
||||||
//right sub-tree (same as above)
|
//right sub-tree (same as above)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mNodeStack[count].nodeId = node.firstChildId+1;
|
mNodeStack[count].nodeId = node.firstChildId + 1;
|
||||||
qnode.nodeId = node.firstChildId;
|
qnode.nodeId = node.firstChildId;
|
||||||
}
|
}
|
||||||
//distance is inherited from the father (while descending the tree it's equal to 0)
|
//distance is inherited from the father (while descending the tree it's equal to 0)
|
||||||
|
|
@ -272,7 +281,7 @@ namespace vcg {
|
||||||
template<typename Scalar>
|
template<typename Scalar>
|
||||||
void KdTree<Scalar>::doQueryDist(const VectorType& queryPoint, float dist, std::vector<unsigned int>& points, std::vector<Scalar>& sqrareDists)
|
void KdTree<Scalar>::doQueryDist(const VectorType& queryPoint, float dist, std::vector<unsigned int>& points, std::vector<Scalar>& sqrareDists)
|
||||||
{
|
{
|
||||||
QueryNode mNodeStack[64];
|
std::vector<QueryNode> mNodeStack(numLevel + 1);
|
||||||
mNodeStack[0].nodeId = 0;
|
mNodeStack[0].nodeId = 0;
|
||||||
mNodeStack[0].sq = 0.f;
|
mNodeStack[0].sq = 0.f;
|
||||||
unsigned int count = 1;
|
unsigned int count = 1;
|
||||||
|
|
@ -280,7 +289,7 @@ namespace vcg {
|
||||||
float sqrareDist = dist*dist;
|
float sqrareDist = dist*dist;
|
||||||
while (count)
|
while (count)
|
||||||
{
|
{
|
||||||
QueryNode& qnode = mNodeStack[count-1];
|
QueryNode& qnode = mNodeStack[count - 1];
|
||||||
Node & node = mNodes[qnode.nodeId];
|
Node & node = mNodes[qnode.nodeId];
|
||||||
|
|
||||||
if (qnode.sq < sqrareDist)
|
if (qnode.sq < sqrareDist)
|
||||||
|
|
@ -288,8 +297,8 @@ namespace vcg {
|
||||||
if (node.leaf)
|
if (node.leaf)
|
||||||
{
|
{
|
||||||
--count; // pop
|
--count; // pop
|
||||||
unsigned int end = node.start+node.size;
|
unsigned int end = node.start + node.size;
|
||||||
for (unsigned int i=node.start ; i<end ; ++i)
|
for (unsigned int i = node.start; i < end; ++i)
|
||||||
{
|
{
|
||||||
float pointSquareDist = vcg::SquaredNorm(queryPoint - mPoints[i]);
|
float pointSquareDist = vcg::SquaredNorm(queryPoint - mPoints[i]);
|
||||||
if (pointSquareDist < sqrareDist)
|
if (pointSquareDist < sqrareDist)
|
||||||
|
|
@ -306,11 +315,11 @@ namespace vcg {
|
||||||
if (new_off < 0.)
|
if (new_off < 0.)
|
||||||
{
|
{
|
||||||
mNodeStack[count].nodeId = node.firstChildId;
|
mNodeStack[count].nodeId = node.firstChildId;
|
||||||
qnode.nodeId = node.firstChildId+1;
|
qnode.nodeId = node.firstChildId + 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mNodeStack[count].nodeId = node.firstChildId+1;
|
mNodeStack[count].nodeId = node.firstChildId + 1;
|
||||||
qnode.nodeId = node.firstChildId;
|
qnode.nodeId = node.firstChildId;
|
||||||
}
|
}
|
||||||
mNodeStack[count].sq = qnode.sq;
|
mNodeStack[count].sq = qnode.sq;
|
||||||
|
|
@ -335,7 +344,7 @@ namespace vcg {
|
||||||
template<typename Scalar>
|
template<typename Scalar>
|
||||||
void KdTree<Scalar>::doQueryClosest(const VectorType& queryPoint, unsigned int& index, Scalar& dist)
|
void KdTree<Scalar>::doQueryClosest(const VectorType& queryPoint, unsigned int& index, Scalar& dist)
|
||||||
{
|
{
|
||||||
QueryNode mNodeStack[64];
|
std::vector<QueryNode> mNodeStack(numLevel + 1);
|
||||||
mNodeStack[0].nodeId = 0;
|
mNodeStack[0].nodeId = 0;
|
||||||
mNodeStack[0].sq = 0.f;
|
mNodeStack[0].sq = 0.f;
|
||||||
unsigned int count = 1;
|
unsigned int count = 1;
|
||||||
|
|
@ -346,7 +355,7 @@ namespace vcg {
|
||||||
|
|
||||||
while (count)
|
while (count)
|
||||||
{
|
{
|
||||||
QueryNode& qnode = mNodeStack[count-1];
|
QueryNode& qnode = mNodeStack[count - 1];
|
||||||
Node & node = mNodes[qnode.nodeId];
|
Node & node = mNodes[qnode.nodeId];
|
||||||
|
|
||||||
if (qnode.sq < minDist)
|
if (qnode.sq < minDist)
|
||||||
|
|
@ -354,8 +363,8 @@ namespace vcg {
|
||||||
if (node.leaf)
|
if (node.leaf)
|
||||||
{
|
{
|
||||||
--count; // pop
|
--count; // pop
|
||||||
unsigned int end = node.start+node.size;
|
unsigned int end = node.start + node.size;
|
||||||
for (unsigned int i=node.start ; i<end ; ++i)
|
for (unsigned int i = node.start; i < end; ++i)
|
||||||
{
|
{
|
||||||
float pointSquareDist = vcg::SquaredNorm(queryPoint - mPoints[i]);
|
float pointSquareDist = vcg::SquaredNorm(queryPoint - mPoints[i]);
|
||||||
if (pointSquareDist < minDist)
|
if (pointSquareDist < minDist)
|
||||||
|
|
@ -372,11 +381,11 @@ namespace vcg {
|
||||||
if (new_off < 0.)
|
if (new_off < 0.)
|
||||||
{
|
{
|
||||||
mNodeStack[count].nodeId = node.firstChildId;
|
mNodeStack[count].nodeId = node.firstChildId;
|
||||||
qnode.nodeId = node.firstChildId+1;
|
qnode.nodeId = node.firstChildId + 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mNodeStack[count].nodeId = node.firstChildId+1;
|
mNodeStack[count].nodeId = node.firstChildId + 1;
|
||||||
qnode.nodeId = node.firstChildId;
|
qnode.nodeId = node.firstChildId;
|
||||||
}
|
}
|
||||||
mNodeStack[count].sq = qnode.sq;
|
mNodeStack[count].sq = qnode.sq;
|
||||||
|
|
@ -404,8 +413,8 @@ namespace vcg {
|
||||||
template<typename Scalar>
|
template<typename Scalar>
|
||||||
unsigned int KdTree<Scalar>::split(int start, int end, unsigned int dim, float splitValue)
|
unsigned int KdTree<Scalar>::split(int start, int end, unsigned int dim, float splitValue)
|
||||||
{
|
{
|
||||||
int l(start), r(end-1);
|
int l(start), r(end - 1);
|
||||||
for ( ; l<r ; ++l, --r)
|
for (; l < r; ++l, --r)
|
||||||
{
|
{
|
||||||
while (l < end && mPoints[l][dim] < splitValue)
|
while (l < end && mPoints[l][dim] < splitValue)
|
||||||
l++;
|
l++;
|
||||||
|
|
@ -413,11 +422,11 @@ namespace vcg {
|
||||||
r--;
|
r--;
|
||||||
if (l > r)
|
if (l > r)
|
||||||
break;
|
break;
|
||||||
std::swap(mPoints[l],mPoints[r]);
|
std::swap(mPoints[l], mPoints[r]);
|
||||||
std::swap(mIndices[l],mIndices[r]);
|
std::swap(mIndices[l], mIndices[r]);
|
||||||
}
|
}
|
||||||
//returns the index of the first element on the second part
|
//returns the index of the first element on the second part
|
||||||
return (mPoints[l][dim] < splitValue ? l+1 : l);
|
return (mPoints[l][dim] < splitValue ? l + 1 : l);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** recursively builds the kdtree
|
/** recursively builds the kdtree
|
||||||
|
|
@ -438,7 +447,7 @@ namespace vcg {
|
||||||
* is more expensive than the gain it provides and the memory consumption is x4 higher !
|
* is more expensive than the gain it provides and the memory consumption is x4 higher !
|
||||||
*/
|
*/
|
||||||
template<typename Scalar>
|
template<typename Scalar>
|
||||||
int KdTree<Scalar>::createTree(unsigned int nodeId, unsigned int start, unsigned int end, unsigned int level, unsigned int targetCellSize, unsigned int targetMaxDepth)
|
int KdTree<Scalar>::createTree(unsigned int nodeId, unsigned int start, unsigned int end, unsigned int level)
|
||||||
{
|
{
|
||||||
//select the first node
|
//select the first node
|
||||||
Node& node = mNodes[nodeId];
|
Node& node = mNodes[nodeId];
|
||||||
|
|
@ -446,7 +455,7 @@ namespace vcg {
|
||||||
|
|
||||||
//putting all the points in the bounding box
|
//putting all the points in the bounding box
|
||||||
aabb.Set(mPoints[start]);
|
aabb.Set(mPoints[start]);
|
||||||
for (unsigned int i=start+1 ; i<end ; ++i)
|
for (unsigned int i = start + 1; i < end; ++i)
|
||||||
aabb.Add(mPoints[i]);
|
aabb.Add(mPoints[i]);
|
||||||
|
|
||||||
//bounding box diagonal
|
//bounding box diagonal
|
||||||
|
|
@ -460,22 +469,29 @@ namespace vcg {
|
||||||
dim = diag.Y() > diag.Z() ? 1 : 2;
|
dim = diag.Y() > diag.Z() ? 1 : 2;
|
||||||
|
|
||||||
node.dim = dim;
|
node.dim = dim;
|
||||||
//we divide the bounding box in 2 partitions, considering the average of the "dim" dimension
|
if (isBalanced) //we divide the points using the median value along the "dim" dimension
|
||||||
|
{
|
||||||
|
std::vector<Scalar> tempVector;
|
||||||
|
for (unsigned int i = start + 1; i < end; ++i)
|
||||||
|
tempVector.push_back(mPoints[i][dim]);
|
||||||
|
std::sort(tempVector.begin(), tempVector.end());
|
||||||
|
node.splitValue = (tempVector[tempVector.size() / 2.0] + tempVector[tempVector.size() / 2.0 + 1]) / 2.0;
|
||||||
|
}
|
||||||
|
else //we divide the bounding box in 2 partitions, considering the average of the "dim" dimension
|
||||||
node.splitValue = Scalar(0.5*(aabb.max[dim] + aabb.min[dim]));
|
node.splitValue = Scalar(0.5*(aabb.max[dim] + aabb.min[dim]));
|
||||||
|
|
||||||
//midId is the index of the first element in the second partition
|
//midId is the index of the first element in the second partition
|
||||||
unsigned int midId = split(start, end, dim, node.splitValue);
|
unsigned int midId = split(start, end, dim, node.splitValue);
|
||||||
|
|
||||||
|
|
||||||
node.firstChildId = mNodes.size();
|
node.firstChildId = mNodes.size();
|
||||||
mNodes.resize(mNodes.size()+2);
|
mNodes.resize(mNodes.size() + 2);
|
||||||
|
bool flag = (midId == start) || (midId == end);
|
||||||
int leftLevel, rightLevel;
|
int leftLevel, rightLevel;
|
||||||
|
|
||||||
{
|
{
|
||||||
// left child
|
// left child
|
||||||
unsigned int childId = mNodes[nodeId].firstChildId;
|
unsigned int childId = mNodes[nodeId].firstChildId;
|
||||||
Node& child = mNodes[childId];
|
Node& child = mNodes[childId];
|
||||||
if (midId - start <= targetCellSize || level>=targetMaxDepth)
|
if (flag || (midId - start) <= targetCellSize || level >= targetMaxDepth)
|
||||||
{
|
{
|
||||||
child.leaf = 1;
|
child.leaf = 1;
|
||||||
child.start = start;
|
child.start = start;
|
||||||
|
|
@ -485,15 +501,15 @@ namespace vcg {
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
child.leaf = 0;
|
child.leaf = 0;
|
||||||
leftLevel = createTree(childId, start, midId, level+1, targetCellSize, targetMaxDepth);
|
leftLevel = createTree(childId, start, midId, level + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// right child
|
// right child
|
||||||
unsigned int childId = mNodes[nodeId].firstChildId+1;
|
unsigned int childId = mNodes[nodeId].firstChildId + 1;
|
||||||
Node& child = mNodes[childId];
|
Node& child = mNodes[childId];
|
||||||
if (end - midId <= targetCellSize || level>=targetMaxDepth)
|
if (flag || (end - midId) <= targetCellSize || level >= targetMaxDepth)
|
||||||
{
|
{
|
||||||
child.leaf = 1;
|
child.leaf = 1;
|
||||||
child.start = midId;
|
child.start = midId;
|
||||||
|
|
@ -503,13 +519,14 @@ namespace vcg {
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
child.leaf = 0;
|
child.leaf = 0;
|
||||||
rightLevel = createTree(childId, midId, end, level+1, targetCellSize, targetMaxDepth);
|
rightLevel = createTree(childId, midId, end, level + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (leftLevel > rightLevel)
|
if (leftLevel > rightLevel)
|
||||||
return leftLevel;
|
return leftLevel;
|
||||||
return rightLevel;
|
return rightLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,300 @@
|
||||||
|
/****************************************************************************
|
||||||
|
* VCGLib o o *
|
||||||
|
* Visual and Computer Graphics Library o o *
|
||||||
|
* _ O _ *
|
||||||
|
* Copyright(C) 2004-2016 \/)\/ *
|
||||||
|
* Visual Computing Lab /\/| *
|
||||||
|
* ISTI - Italian National Research Council | *
|
||||||
|
* \ *
|
||||||
|
* All rights reserved. *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||||
|
* for more details. *
|
||||||
|
* *
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef KDTREE_FACE_H
|
||||||
|
#define KDTREE_FACE_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <vcg/space/distance3.h>
|
||||||
|
|
||||||
|
namespace vcg {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class allows to create a Kd-Tree thought to perform the neighbour query using the mesh faces (closest search).
|
||||||
|
* The class implemetantion is thread-safe.
|
||||||
|
*/
|
||||||
|
template<class MeshType>
|
||||||
|
class KdTreeFace
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef typename MeshType::ScalarType Scalar;
|
||||||
|
typedef typename MeshType::CoordType VectorType;
|
||||||
|
typedef typename MeshType::BoxType AxisAlignedBoxType;
|
||||||
|
typedef typename MeshType::FacePointer FacePointer;
|
||||||
|
|
||||||
|
class Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Scalar splitValue;
|
||||||
|
unsigned int firstChildId : 24;
|
||||||
|
unsigned int dim : 2;
|
||||||
|
unsigned int leaf : 1;
|
||||||
|
AxisAlignedBoxType aabb;
|
||||||
|
std::vector<FacePointer> list;
|
||||||
|
};
|
||||||
|
typedef std::vector<Node> NodeListPointer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
KdTreeFace(MeshType& mesh, unsigned int maxObjPerCell = 64, unsigned int maxDepth = 64) : epsilon(std::numeric_limits<Scalar>::epsilon())
|
||||||
|
{
|
||||||
|
targetCellSize = maxObjPerCell;
|
||||||
|
targetMaxDepth = maxDepth;
|
||||||
|
mNodes.resize(1);
|
||||||
|
Node& node = mNodes.back();
|
||||||
|
node.leaf = 0;
|
||||||
|
node.aabb = mesh.bbox;
|
||||||
|
node.aabb.Offset(VectorType(epsilon, epsilon, epsilon));
|
||||||
|
for (int i = 0; i < mesh.face.size(); i++)
|
||||||
|
node.list.push_back(&mesh.face[i]);
|
||||||
|
numLevel = createTree(0, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
~KdTreeFace()
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <class ObjectMarker> FacePointer doQueryClosest(const VectorType& queryPoint, VectorType& narestPoint, Scalar& dist, ObjectMarker& marker, Scalar maxDist = std::numeric_limits<Scalar>::max())
|
||||||
|
{
|
||||||
|
if (maxDist < std::numeric_limits<Scalar>::max() && !mNodes[0].aabb.IsIn(queryPoint) && vcg::PointFilledBoxDistance(queryPoint, mNodes[0].aabb) >= maxDist)
|
||||||
|
{
|
||||||
|
dist = maxDist;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
std::vector<QueryNode> mNodeStack(numLevel + 1);
|
||||||
|
mNodeStack[0].nodeId = 0;
|
||||||
|
mNodeStack[0].sq = 0.f;
|
||||||
|
unsigned int count = 1;
|
||||||
|
|
||||||
|
Scalar minDist = maxDist;
|
||||||
|
VectorType p;
|
||||||
|
FacePointer face = NULL;
|
||||||
|
while (count)
|
||||||
|
{
|
||||||
|
QueryNode& qnode = mNodeStack[count - 1];
|
||||||
|
Node& node = mNodes[qnode.nodeId];
|
||||||
|
|
||||||
|
if (qnode.sq < minDist)
|
||||||
|
{
|
||||||
|
if (node.leaf)
|
||||||
|
{
|
||||||
|
--count; // pop
|
||||||
|
for (int i = 0; i < node.list.size(); i++)
|
||||||
|
{
|
||||||
|
if (!marker.IsMarked(node.list[i]))
|
||||||
|
{
|
||||||
|
marker.Mark(node.list[i]);
|
||||||
|
Scalar tempDist = minDist;
|
||||||
|
VectorType tempP;
|
||||||
|
if (vcg::face::PointDistanceBase(*node.list[i], queryPoint, tempDist, tempP))
|
||||||
|
{
|
||||||
|
if (tempDist < minDist)
|
||||||
|
{
|
||||||
|
minDist = tempDist;
|
||||||
|
p = tempP;
|
||||||
|
face = node.list[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// replace the stack top by the farthest and push the closest
|
||||||
|
float new_off = queryPoint[node.dim] - node.splitValue;
|
||||||
|
float abs_off = abs(new_off);
|
||||||
|
if (abs_off < minDist)
|
||||||
|
{
|
||||||
|
if (new_off < 0.)
|
||||||
|
{
|
||||||
|
mNodeStack[count].nodeId = node.firstChildId;
|
||||||
|
qnode.nodeId = node.firstChildId + 1;
|
||||||
|
new_off = vcg::PointFilledBoxDistance(queryPoint, mNodes[node.firstChildId + 1].aabb);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mNodeStack[count].nodeId = node.firstChildId + 1;
|
||||||
|
qnode.nodeId = node.firstChildId;
|
||||||
|
new_off = vcg::PointFilledBoxDistance(queryPoint, mNodes[node.firstChildId].aabb);
|
||||||
|
}
|
||||||
|
mNodeStack[count].sq = qnode.sq;
|
||||||
|
qnode.sq = new_off;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (new_off < 0.)
|
||||||
|
qnode.nodeId = node.firstChildId;
|
||||||
|
else
|
||||||
|
qnode.nodeId = node.firstChildId + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// pop
|
||||||
|
--count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dist = minDist;
|
||||||
|
narestPoint = p;
|
||||||
|
return face;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// element of the stack
|
||||||
|
struct QueryNode
|
||||||
|
{
|
||||||
|
QueryNode() {}
|
||||||
|
QueryNode(unsigned int id) : nodeId(id) {}
|
||||||
|
unsigned int nodeId; // id of the next node
|
||||||
|
Scalar sq; // distance to the next node
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int createTree(unsigned int nodeId, unsigned int level)
|
||||||
|
{
|
||||||
|
Node& node = mNodes[nodeId];
|
||||||
|
VectorType diag = node.aabb.max - node.aabb.min;
|
||||||
|
unsigned int dim;
|
||||||
|
if (diag.X() > diag.Y())
|
||||||
|
dim = diag.X() > diag.Z() ? 0 : 2;
|
||||||
|
else
|
||||||
|
dim = diag.Y() > diag.Z() ? 1 : 2;
|
||||||
|
|
||||||
|
node.splitValue = Scalar(0.5*(node.aabb.max[dim] + node.aabb.min[dim]));
|
||||||
|
node.dim = dim;
|
||||||
|
|
||||||
|
AxisAlignedBoxType leftBox, rightBox;
|
||||||
|
leftBox.Add(node.aabb.min);
|
||||||
|
rightBox.Add(node.aabb.max);
|
||||||
|
if (node.dim == 0)
|
||||||
|
{
|
||||||
|
leftBox.Add(VectorType(node.splitValue, node.aabb.max[1], node.aabb.max[2]));
|
||||||
|
rightBox.Add(VectorType(node.splitValue, node.aabb.min[1], node.aabb.min[2]));
|
||||||
|
}
|
||||||
|
else if (node.dim == 1)
|
||||||
|
{
|
||||||
|
leftBox.Add(VectorType(node.aabb.max[0], node.splitValue, node.aabb.max[2]));
|
||||||
|
rightBox.Add(VectorType(node.aabb.min[0], node.splitValue, node.aabb.min[2]));
|
||||||
|
}
|
||||||
|
else if (node.dim == 2)
|
||||||
|
{
|
||||||
|
leftBox.Add(VectorType(node.aabb.max[0], node.aabb.max[1], node.splitValue));
|
||||||
|
rightBox.Add(VectorType(node.aabb.min[0], node.aabb.min[1], node.splitValue));
|
||||||
|
}
|
||||||
|
leftBox.Offset(VectorType(epsilon, epsilon, epsilon));
|
||||||
|
rightBox.Offset(VectorType(epsilon, epsilon, epsilon));
|
||||||
|
|
||||||
|
node.firstChildId = mNodes.size();
|
||||||
|
int firstChildId = node.firstChildId;
|
||||||
|
mNodes.resize(mNodes.size() + 2);
|
||||||
|
Node& parent = mNodes[nodeId];
|
||||||
|
Node& leftChild = mNodes[firstChildId];
|
||||||
|
Node& rightChild = mNodes[firstChildId + 1];
|
||||||
|
leftChild.aabb.SetNull();
|
||||||
|
rightChild.aabb.SetNull();
|
||||||
|
|
||||||
|
for (int i = 0; i < parent.list.size(); i++)
|
||||||
|
{
|
||||||
|
unsigned int state = 0;
|
||||||
|
FacePointer fp = parent.list[i];
|
||||||
|
for (int j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
if (fp->P(j)[dim] < parent.splitValue)
|
||||||
|
state |= (1 << 0);
|
||||||
|
else if (fp->P(j)[dim] > parent.splitValue)
|
||||||
|
state |= (1 << 1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state |= (1 << 0);
|
||||||
|
state |= (1 << 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state & (1 << 0))
|
||||||
|
{
|
||||||
|
leftChild.list.push_back(fp);
|
||||||
|
leftChild.aabb.Add(fp->P(0));
|
||||||
|
leftChild.aabb.Add(fp->P(1));
|
||||||
|
leftChild.aabb.Add(fp->P(2));
|
||||||
|
}
|
||||||
|
if (state & (1 << 1))
|
||||||
|
{
|
||||||
|
rightChild.list.push_back(fp);
|
||||||
|
rightChild.aabb.Add(fp->P(0));
|
||||||
|
rightChild.aabb.Add(fp->P(1));
|
||||||
|
rightChild.aabb.Add(fp->P(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent.list.clear();
|
||||||
|
leftChild.aabb.Intersect(leftBox);
|
||||||
|
rightChild.aabb.Intersect(rightBox);
|
||||||
|
|
||||||
|
int leftLevel, rightLevel;
|
||||||
|
{
|
||||||
|
if (leftChild.list.size() <= targetCellSize || level >= targetMaxDepth)
|
||||||
|
{
|
||||||
|
leftChild.leaf = 1;
|
||||||
|
leftLevel = level;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
leftChild.leaf = 0;
|
||||||
|
leftLevel = createTree(firstChildId, level + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Node& rightChild = mNodes[firstChildId + 1];
|
||||||
|
if (rightChild.list.size() <= targetCellSize || level >= targetMaxDepth)
|
||||||
|
{
|
||||||
|
rightChild.leaf = 1;
|
||||||
|
rightLevel = level;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rightChild.leaf = 0;
|
||||||
|
rightLevel = createTree(firstChildId + 1, level + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (leftLevel > rightLevel)
|
||||||
|
return leftLevel;
|
||||||
|
return rightLevel;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
NodeListPointer mNodes; //kd-tree nodes
|
||||||
|
unsigned int numLevel;
|
||||||
|
const Scalar epsilon;
|
||||||
|
unsigned int targetCellSize;
|
||||||
|
unsigned int targetMaxDepth;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -240,6 +240,148 @@ static bool PackOccupancyMulti(const std::vector<Box2x > & rectVec, /// the se
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This is the low level function that packs a set of int rects onto a grid.
|
||||||
|
|
||||||
|
Based on the criptic code written by Claudio Rocchini
|
||||||
|
|
||||||
|
Greedy algorithm.
|
||||||
|
Sort the rect according their height (larger first)
|
||||||
|
and then place them in the position that minimize the area of the bbox of all the placed rectangles
|
||||||
|
|
||||||
|
To efficiently skip occupied areas it fills the grid with the id of the already placed rectangles.
|
||||||
|
*/
|
||||||
|
static bool PackInt(const std::vector<vcg::Point2i> & sizes, // the sizes of the rect to be packed
|
||||||
|
const vcg::Point2i & max_size, // the size of the container
|
||||||
|
std::vector<vcg::Point2i> & posiz, // the found positionsof each rect
|
||||||
|
vcg::Point2i & global_size) // the size of smallest rect covering all the packed rect
|
||||||
|
{
|
||||||
|
int n = (int)(sizes.size());
|
||||||
|
assert(n>0 && max_size[0]>0 && max_size[1]>0);
|
||||||
|
|
||||||
|
int gridSize = max_size[0] * max_size[1]; // Size dell griglia
|
||||||
|
int i, j, x, y;
|
||||||
|
|
||||||
|
posiz.resize(n, Point2i(-1, -1));
|
||||||
|
std::vector<int> grid(gridSize, 0); // Creazione griglia
|
||||||
|
|
||||||
|
#define Grid(q,w) (grid[(q)+(w)*max_size[0]])
|
||||||
|
|
||||||
|
// Build a permutation that keeps the reordiering of the sizes vector according to their width
|
||||||
|
std::vector<int> perm(n);
|
||||||
|
for (i = 0; i<n; i++) perm[i] = i;
|
||||||
|
ComparisonFunctor cmp(sizes);
|
||||||
|
sort(perm.begin(), perm.end(), cmp);
|
||||||
|
|
||||||
|
if (sizes[perm[0]][0]>max_size[0] || sizes[perm[0]][1]>max_size[1])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Posiziono il primo
|
||||||
|
j = perm[0];
|
||||||
|
global_size = sizes[j];
|
||||||
|
posiz[j] = Point2i(0, 0);
|
||||||
|
|
||||||
|
// Fill the grid with the id(+1) of the first
|
||||||
|
for (y = 0; y<global_size[1]; y++)
|
||||||
|
for (x = 0; x<global_size[0]; x++)
|
||||||
|
{
|
||||||
|
assert(x >= 0 && x<max_size[0]);
|
||||||
|
assert(y >= 0 && y<max_size[1]);
|
||||||
|
grid[x + y*max_size[0]] = j + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Posiziono tutti gli altri
|
||||||
|
for (i = 1; i<n; ++i)
|
||||||
|
{
|
||||||
|
j = perm[i];
|
||||||
|
assert(j >= 0 && j<n);
|
||||||
|
assert(posiz[j][0] == -1);
|
||||||
|
|
||||||
|
int bestx, besty, bestsx, bestsy, bestArea;
|
||||||
|
|
||||||
|
bestArea = -1;
|
||||||
|
|
||||||
|
int sx = sizes[j][0]; // Pe comodita' mi copio la dimensione
|
||||||
|
int sy = sizes[j][1];
|
||||||
|
assert(sx>0 && sy>0);
|
||||||
|
|
||||||
|
// Calcolo la posizione limite
|
||||||
|
int lx = std::min(global_size[0], max_size[0] - sx);
|
||||||
|
int ly = std::min(global_size[1], max_size[1] - sy);
|
||||||
|
|
||||||
|
assert(lx>0 && ly>0);
|
||||||
|
|
||||||
|
int finterior = 0;
|
||||||
|
|
||||||
|
for (y = 0; y <= ly; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x <= lx;)
|
||||||
|
{
|
||||||
|
int px;
|
||||||
|
int c = Grid(x, y + sy - 1);
|
||||||
|
// Intersection check
|
||||||
|
if (!c) c = Grid(x + sx - 1, y + sy - 1);
|
||||||
|
if (!c)
|
||||||
|
{
|
||||||
|
for (px = x; px<x + sx; px++)
|
||||||
|
{
|
||||||
|
c = Grid(px, y);
|
||||||
|
if (c) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c) // Salto il rettangolo
|
||||||
|
{
|
||||||
|
--c; // we store id+1...
|
||||||
|
assert(c >= 0 && c<n);
|
||||||
|
assert(posiz[c][0] != -1);
|
||||||
|
x = posiz[c][0] + sizes[c][0];
|
||||||
|
}
|
||||||
|
else // x,y are an admissible position where we can put the rectangle
|
||||||
|
{
|
||||||
|
int nsx = std::max(global_size[0], x + sx);
|
||||||
|
int nsy = std::max(global_size[1], y + sy);
|
||||||
|
int area = nsx*nsy;
|
||||||
|
|
||||||
|
if (bestArea == -1 || bestArea>area)
|
||||||
|
{
|
||||||
|
bestx = x;
|
||||||
|
besty = y;
|
||||||
|
bestsx = nsx;
|
||||||
|
bestsy = nsy;
|
||||||
|
bestArea = area;
|
||||||
|
if (bestsx == global_size[0] && bestsy == global_size[1])
|
||||||
|
finterior = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (finterior) break;
|
||||||
|
}
|
||||||
|
if (finterior) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestArea == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
posiz[j][0] = bestx;
|
||||||
|
posiz[j][1] = besty;
|
||||||
|
global_size[0] = bestsx;
|
||||||
|
global_size[1] = bestsy;
|
||||||
|
for (y = posiz[j][1]; y<posiz[j][1] + sy; y++)
|
||||||
|
for (x = posiz[j][0]; x<posiz[j][0] + sx; x++)
|
||||||
|
{
|
||||||
|
assert(x >= 0 && x<max_size[0]);
|
||||||
|
assert(y >= 0 && y<max_size[1]);
|
||||||
|
grid[x + y*max_size[0]] = j + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef Grid
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -260,148 +402,6 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* This is the low level function that packs a set of int rects onto a grid.
|
|
||||||
|
|
||||||
Based on the criptic code written by Claudio Rocchini
|
|
||||||
|
|
||||||
Greedy algorithm.
|
|
||||||
Sort the rect according their height (larger first)
|
|
||||||
and then place them in the position that minimize the area of the bbox of all the placed rectangles
|
|
||||||
|
|
||||||
To efficiently skip occupied areas it fills the grid with the id of the already placed rectangles.
|
|
||||||
*/
|
|
||||||
static bool PackInt(const std::vector<vcg::Point2i> & sizes, // the sizes of the rect to be packed
|
|
||||||
const vcg::Point2i & max_size, // the size of the container
|
|
||||||
std::vector<vcg::Point2i> & posiz, // the found positionsof each rect
|
|
||||||
vcg::Point2i & global_size) // the size of smallest rect covering all the packed rect
|
|
||||||
{
|
|
||||||
int n = (int)(sizes.size());
|
|
||||||
assert(n>0 && max_size[0]>0 && max_size[1]>0);
|
|
||||||
|
|
||||||
int gridSize = max_size[0]*max_size[1]; // Size dell griglia
|
|
||||||
int i,j,x,y;
|
|
||||||
|
|
||||||
posiz.resize(n,Point2i(-1,-1));
|
|
||||||
std::vector<int> grid(gridSize,0); // Creazione griglia
|
|
||||||
|
|
||||||
#define Grid(q,w) (grid[(q)+(w)*max_size[0]])
|
|
||||||
|
|
||||||
// Build a permutation that keeps the reordiering of the sizes vector according to their width
|
|
||||||
std::vector<int> perm(n);
|
|
||||||
for(i=0;i<n;i++) perm[i] = i;
|
|
||||||
ComparisonFunctor cmp(sizes);
|
|
||||||
sort(perm.begin(),perm.end(),cmp);
|
|
||||||
|
|
||||||
if(sizes[perm[0]][0]>max_size[0] || sizes[perm[0]][1]>max_size[1] )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Posiziono il primo
|
|
||||||
j = perm[0];
|
|
||||||
global_size = sizes[j];
|
|
||||||
posiz[j] = Point2i(0,0);
|
|
||||||
|
|
||||||
// Fill the grid with the id(+1) of the first
|
|
||||||
for(y=0;y<global_size[1];y++)
|
|
||||||
for(x=0;x<global_size[0];x++)
|
|
||||||
{
|
|
||||||
assert(x>=0 && x<max_size[0]);
|
|
||||||
assert(y>=0 && y<max_size[1]);
|
|
||||||
grid[x+y*max_size[0]] = j+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Posiziono tutti gli altri
|
|
||||||
for(i=1;i<n;++i)
|
|
||||||
{
|
|
||||||
j = perm[i];
|
|
||||||
assert(j>=0 && j<n);
|
|
||||||
assert(posiz[j][0]==-1);
|
|
||||||
|
|
||||||
int bestx,besty,bestsx,bestsy,bestArea;
|
|
||||||
|
|
||||||
bestArea = -1;
|
|
||||||
|
|
||||||
int sx = sizes[j][0]; // Pe comodita' mi copio la dimensione
|
|
||||||
int sy = sizes[j][1];
|
|
||||||
assert(sx>0 && sy>0);
|
|
||||||
|
|
||||||
// Calcolo la posizione limite
|
|
||||||
int lx = std::min(global_size[0],max_size[0]-sx);
|
|
||||||
int ly = std::min(global_size[1],max_size[1]-sy);
|
|
||||||
|
|
||||||
assert(lx>0 && ly>0);
|
|
||||||
|
|
||||||
int finterior = 0;
|
|
||||||
|
|
||||||
for(y=0;y<=ly;y++)
|
|
||||||
{
|
|
||||||
for(x=0;x<=lx;)
|
|
||||||
{
|
|
||||||
int px;
|
|
||||||
int c = Grid(x,y+sy-1);
|
|
||||||
// Intersection check
|
|
||||||
if(!c) c = Grid(x+sx-1,y+sy-1);
|
|
||||||
if(!c)
|
|
||||||
{
|
|
||||||
for(px=x;px<x+sx;px++)
|
|
||||||
{
|
|
||||||
c = Grid(px,y);
|
|
||||||
if(c) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(c) // Salto il rettangolo
|
|
||||||
{
|
|
||||||
--c; // we store id+1...
|
|
||||||
assert(c>=0 && c<n);
|
|
||||||
assert(posiz[c][0]!=-1);
|
|
||||||
x = posiz[c][0] + sizes[c][0];
|
|
||||||
}
|
|
||||||
else // x,y are an admissible position where we can put the rectangle
|
|
||||||
{
|
|
||||||
int nsx = std::max(global_size[0],x+sx);
|
|
||||||
int nsy = std::max(global_size[1],y+sy);
|
|
||||||
int area = nsx*nsy;
|
|
||||||
|
|
||||||
if(bestArea==-1 || bestArea>area)
|
|
||||||
{
|
|
||||||
bestx = x;
|
|
||||||
besty = y;
|
|
||||||
bestsx = nsx;
|
|
||||||
bestsy = nsy;
|
|
||||||
bestArea = area;
|
|
||||||
if( bestsx==global_size[0] && bestsy==global_size[1] )
|
|
||||||
finterior = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(finterior) break;
|
|
||||||
}
|
|
||||||
if( finterior ) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(bestArea==-1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
posiz[j][0] = bestx;
|
|
||||||
posiz[j][1] = besty;
|
|
||||||
global_size[0] = bestsx;
|
|
||||||
global_size[1] = bestsy;
|
|
||||||
for(y=posiz[j][1];y<posiz[j][1]+sy;y++)
|
|
||||||
for(x=posiz[j][0];x<posiz[j][0]+sx;x++)
|
|
||||||
{
|
|
||||||
assert(x>=0 && x<max_size[0]);
|
|
||||||
assert(y>=0 && y<max_size[1]);
|
|
||||||
grid[x+y*max_size[0]] = j+1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef Grid
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Versione multitexture
|
// Versione multitexture
|
||||||
static bool PackIntMulti( const std::vector<Point2i> & sizes,
|
static bool PackIntMulti( const std::vector<Point2i> & sizes,
|
||||||
const int ntexture,
|
const int ntexture,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
* VCGLib o o *
|
* VCGLib o o *
|
||||||
* Visual and Computer Graphics Library o o *
|
* Visual and Computer Graphics Library o o *
|
||||||
* _ O _ *
|
* _ O _ *
|
||||||
* Copyright(C) 2004-2016 \/)\/ *
|
* Copyright(C) 2004 \/)\/ *
|
||||||
* Visual Computing Lab /\/| *
|
* Visual Computing Lab /\/| *
|
||||||
* ISTI - Italian National Research Council | *
|
* ISTI - Italian National Research Council | *
|
||||||
* \ *
|
* \ *
|
||||||
|
|
@ -119,9 +119,9 @@ namespace vcg
|
||||||
class RenderingAtts
|
class RenderingAtts
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RenderingAtts()
|
RenderingAtts(bool defaultvalue = false)
|
||||||
{
|
{
|
||||||
reset();
|
reset(defaultvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderingAtts(const RenderingAtts<ATT_NAMES_DERIVED_CLASS>& att)
|
RenderingAtts(const RenderingAtts<ATT_NAMES_DERIVED_CLASS>& att)
|
||||||
|
|
@ -174,12 +174,12 @@ namespace vcg
|
||||||
return _atts[ind];
|
return _atts[ind];
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset()
|
void reset(bool defaultvalue = false)
|
||||||
{
|
{
|
||||||
//delete[] _atts;
|
//delete[] _atts;
|
||||||
//_atts = new bool[ATT_NAMES_DERIVED_CLASS::enumArity()];
|
//_atts = new bool[ATT_NAMES_DERIVED_CLASS::enumArity()];
|
||||||
for(unsigned int ii = 0;ii < ATT_NAMES_DERIVED_CLASS::enumArity();++ii)
|
for(unsigned int ii = 0;ii < ATT_NAMES_DERIVED_CLASS::enumArity();++ii)
|
||||||
_atts[ii] = false;
|
_atts[ii] = defaultvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RenderingAtts<ATT_NAMES_DERIVED_CLASS> unionSet(const RenderingAtts<ATT_NAMES_DERIVED_CLASS>& a,const RenderingAtts<ATT_NAMES_DERIVED_CLASS>& b)
|
static RenderingAtts<ATT_NAMES_DERIVED_CLASS> unionSet(const RenderingAtts<ATT_NAMES_DERIVED_CLASS>& a,const RenderingAtts<ATT_NAMES_DERIVED_CLASS>& b)
|
||||||
|
|
@ -288,6 +288,7 @@ namespace vcg
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct INT_ATT_NAMES : public ATT_NAMES
|
struct INT_ATT_NAMES : public ATT_NAMES
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,6 @@ namespace vcg
|
||||||
bool _perwire_mesh_color_enabled;
|
bool _perwire_mesh_color_enabled;
|
||||||
bool _persolid_mesh_color_enabled;
|
bool _persolid_mesh_color_enabled;
|
||||||
|
|
||||||
Color4b _permesh_color;
|
|
||||||
|
|
||||||
bool _perpoint_noshading;
|
bool _perpoint_noshading;
|
||||||
bool _perwire_noshading;
|
bool _perwire_noshading;
|
||||||
bool _persolid_noshading;
|
bool _persolid_noshading;
|
||||||
|
|
@ -77,21 +75,21 @@ namespace vcg
|
||||||
RenderingModalityGLOptions()
|
RenderingModalityGLOptions()
|
||||||
{
|
{
|
||||||
_perbbox_enabled = false;
|
_perbbox_enabled = false;
|
||||||
|
|
||||||
_perbbox_fixed_color_enabled = true;
|
_perbbox_fixed_color_enabled = true;
|
||||||
_perpoint_fixed_color_enabled = false;
|
_perpoint_fixed_color_enabled = false;
|
||||||
_perwire_fixed_color_enabled = true;
|
_perwire_fixed_color_enabled = true;
|
||||||
|
_persolid_fixed_color_enabled = true;
|
||||||
|
|
||||||
_perbbox_fixed_color = Color4b(Color4b::White);
|
_perbbox_fixed_color = vcg::Color4b(Color4b::White);
|
||||||
_perpoint_fixed_color = Color4b(Color4b::White);
|
_perpoint_fixed_color = vcg::Color4b(Color4b::White);
|
||||||
_perwire_fixed_color = Color4b(Color4b::DarkGray);
|
_perwire_fixed_color = Color4b(Color4b::DarkGray);
|
||||||
_persolid_fixed_color = Color4b(Color4b::White);
|
_persolid_fixed_color = vcg::Color4b(Color4b::White);
|
||||||
|
|
||||||
_persolid_fixed_color_enabled = false;
|
|
||||||
_perbbox_mesh_color_enabled = false;
|
_perbbox_mesh_color_enabled = false;
|
||||||
_perpoint_mesh_color_enabled = false;
|
_perpoint_mesh_color_enabled = false;
|
||||||
_perwire_mesh_color_enabled = false;
|
_perwire_mesh_color_enabled = false;
|
||||||
|
_persolid_mesh_color_enabled = false;
|
||||||
_permesh_color = Color4b(Color4d::Magenta);
|
|
||||||
|
|
||||||
_perpoint_dot_enabled = false;
|
_perpoint_dot_enabled = false;
|
||||||
|
|
||||||
|
|
@ -136,8 +134,6 @@ namespace vcg
|
||||||
_perwire_fixed_color_enabled = opts._perwire_fixed_color_enabled;
|
_perwire_fixed_color_enabled = opts._perwire_fixed_color_enabled;
|
||||||
_persolid_fixed_color_enabled = opts._persolid_fixed_color_enabled;
|
_persolid_fixed_color_enabled = opts._persolid_fixed_color_enabled;
|
||||||
|
|
||||||
_permesh_color = opts._permesh_color;
|
|
||||||
|
|
||||||
_perbbox_mesh_color_enabled = opts._perbbox_mesh_color_enabled;
|
_perbbox_mesh_color_enabled = opts._perbbox_mesh_color_enabled;
|
||||||
_perpoint_mesh_color_enabled = opts._perpoint_mesh_color_enabled;
|
_perpoint_mesh_color_enabled = opts._perpoint_mesh_color_enabled;
|
||||||
_perwire_mesh_color_enabled = opts._perwire_mesh_color_enabled;
|
_perwire_mesh_color_enabled = opts._perwire_mesh_color_enabled;
|
||||||
|
|
@ -292,7 +288,7 @@ namespace vcg
|
||||||
/*************************************************************************************************************************************************************************/
|
/*************************************************************************************************************************************************************************/
|
||||||
|
|
||||||
NotThreadSafeGLMeshAttributesMultiViewerBOManager(/*const*/ MESH_TYPE& mesh,MemoryInfo& meminfo, size_t perbatchprimitives)
|
NotThreadSafeGLMeshAttributesMultiViewerBOManager(/*const*/ MESH_TYPE& mesh,MemoryInfo& meminfo, size_t perbatchprimitives)
|
||||||
:_mesh(mesh),_gpumeminfo(meminfo),_bo(INT_ATT_NAMES::enumArity(),NULL),_currallocatedboatt(),_perbatchprim(perbatchprimitives),_chunkmap(),_borendering(false),_edge(),_meshverticeswhenedgeindiceswerecomputed(0),_meshtriangleswhenedgeindiceswerecomputed(0),_tr(),_debugmode(false),_loginfo(),_meaningfulattsperprimitive(PR_ARITY,InternalRendAtts()),_tmpbuffer(0)
|
:_mesh(mesh),_gpumeminfo(meminfo),_bo(INT_ATT_NAMES::enumArity(),NULL),_currallocatedboatt(),_perbatchprim(perbatchprimitives),_chunkmap(),_borendering(false),_edge(),_meshverticeswhenedgeindiceswerecomputed(0),_meshtriangleswhenedgeindiceswerecomputed(0),_tr(),_debugmode(false),_loginfo(),_meaningfulattsperprimitive(PR_ARITY,InternalRendAtts())
|
||||||
{
|
{
|
||||||
_tr.SetIdentity();
|
_tr.SetIdentity();
|
||||||
_bo[INT_ATT_NAMES::ATT_VERTPOSITION] = new GLBufferObject(3,GL_FLOAT,GL_VERTEX_ARRAY,GL_ARRAY_BUFFER);
|
_bo[INT_ATT_NAMES::ATT_VERTPOSITION] = new GLBufferObject(3,GL_FLOAT,GL_VERTEX_ARRAY,GL_ARRAY_BUFFER);
|
||||||
|
|
@ -353,6 +349,16 @@ namespace vcg
|
||||||
_perviewreqatts[viewid] = copydt;
|
_perviewreqatts[viewid] = copydt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setPerAllViewsInfo(const PVData& data)
|
||||||
|
{
|
||||||
|
///cleanup stage...if an attribute impossible for a primitive modality is still here (it should not be...) we change the required atts into the view
|
||||||
|
PVData copydt(data);
|
||||||
|
for (PRIMITIVE_MODALITY pm = PRIMITIVE_MODALITY(0); pm < PR_ARITY; pm = next(pm))
|
||||||
|
copydt._intatts[pm] = InternalRendAtts::intersectionSet(copydt._intatts[size_t(pm)], _meaningfulattsperprimitive[size_t(pm)]);
|
||||||
|
for (typename ViewsMap::iterator it = _perviewreqatts.begin(); it != _perviewreqatts.end(); ++it)
|
||||||
|
it->second = copydt;
|
||||||
|
}
|
||||||
|
|
||||||
bool removeView(UNIQUE_VIEW_ID_TYPE viewid)
|
bool removeView(UNIQUE_VIEW_ID_TYPE viewid)
|
||||||
{
|
{
|
||||||
typename ViewsMap::iterator it = _perviewreqatts.find(viewid);
|
typename ViewsMap::iterator it = _perviewreqatts.find(viewid);
|
||||||
|
|
@ -375,57 +381,35 @@ namespace vcg
|
||||||
|
|
||||||
const PVData& dt = it->second;
|
const PVData& dt = it->second;
|
||||||
//const InternalRendAtts& atts = it->second._intatts;
|
//const InternalRendAtts& atts = it->second._intatts;
|
||||||
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
drawFun(dt, textid);
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
glPushMatrix();
|
|
||||||
glMultMatrix(_tr);
|
|
||||||
|
|
||||||
if ((dt._glopts != NULL) && (dt._glopts->_perbbox_enabled))
|
|
||||||
drawBBox(dt._glopts);
|
|
||||||
|
|
||||||
if (dt.isPrimitiveActive(PR_SOLID))
|
|
||||||
{
|
|
||||||
bool somethingmore = dt.isPrimitiveActive(PR_WIREFRAME_EDGES) || dt.isPrimitiveActive(PR_WIREFRAME_TRIANGLES) || dt.isPrimitiveActive(PR_POINTS);
|
|
||||||
if (somethingmore)
|
|
||||||
{
|
|
||||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
|
||||||
glPolygonOffset(1.0, 1);
|
|
||||||
}
|
|
||||||
drawFilledTriangles(dt._intatts[size_t(PR_SOLID)],dt._glopts,textid);
|
|
||||||
if (somethingmore)
|
|
||||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dt.isPrimitiveActive(PR_WIREFRAME_EDGES) || dt.isPrimitiveActive(PR_WIREFRAME_TRIANGLES))
|
|
||||||
{
|
|
||||||
//InternalRendAtts tmpatts = atts;
|
|
||||||
bool pointstoo = dt.isPrimitiveActive(PR_POINTS);
|
|
||||||
|
|
||||||
if (pointstoo)
|
void drawAllocatedAttributesSubset(UNIQUE_VIEW_ID_TYPE viewid,const PVData& dt, const std::vector<GLuint>& textid = std::vector<GLuint>()) const
|
||||||
{
|
{
|
||||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
typename ViewsMap::const_iterator it = _perviewreqatts.find(viewid);
|
||||||
glPolygonOffset(1.0, 1);
|
if (it == _perviewreqatts.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
PVData tmp = dt;
|
||||||
|
|
||||||
|
if (!(_currallocatedboatt[INT_ATT_NAMES::ATT_VERTPOSITION]))
|
||||||
|
{
|
||||||
|
for (PRIMITIVE_MODALITY pm = PRIMITIVE_MODALITY(0); pm < PR_ARITY; pm = next(pm))
|
||||||
|
{
|
||||||
|
tmp._pmmask[size_t(pm)] = 0;
|
||||||
|
tmp._intatts[size_t(pm)] = InternalRendAtts();
|
||||||
}
|
}
|
||||||
bool solidtoo = dt.isPrimitiveActive(PR_SOLID);
|
|
||||||
|
|
||||||
if (dt.isPrimitiveActive(PR_WIREFRAME_TRIANGLES))
|
|
||||||
{
|
|
||||||
drawWiredTriangles(dt._intatts[size_t(PR_WIREFRAME_TRIANGLES)],dt._glopts,textid);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (dt.isPrimitiveActive(PR_WIREFRAME_EDGES))
|
for (PRIMITIVE_MODALITY pm = PRIMITIVE_MODALITY(0); pm < PR_ARITY; pm = next(pm))
|
||||||
drawEdges(dt._intatts[size_t(PR_WIREFRAME_EDGES)],dt._glopts);
|
{
|
||||||
|
tmp._intatts[size_t(pm)] = InternalRendAtts::intersectionSet(tmp._intatts[size_t(pm)],_meaningfulattsperprimitive[size_t(pm)]);
|
||||||
|
tmp._intatts[size_t(pm)] = InternalRendAtts::intersectionSet(tmp._intatts[size_t(pm)],_currallocatedboatt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pointstoo || solidtoo)
|
|
||||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
|
||||||
}
|
}
|
||||||
if (dt.isPrimitiveActive(PR_POINTS))
|
drawFun(dt, textid);
|
||||||
drawPoints(dt._intatts[size_t(PR_POINTS)],it->second._glopts);
|
|
||||||
|
|
||||||
glPopMatrix();
|
|
||||||
glPopAttrib();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isBORenderingAvailable() const
|
bool isBORenderingAvailable() const
|
||||||
|
|
@ -531,9 +515,9 @@ namespace vcg
|
||||||
case(INT_ATT_NAMES::ATT_WEDGETEXTURE):
|
case(INT_ATT_NAMES::ATT_WEDGETEXTURE):
|
||||||
return vcg::tri::HasPerWedgeTexCoord(_mesh);
|
return vcg::tri::HasPerWedgeTexCoord(_mesh);
|
||||||
case(INT_ATT_NAMES::ATT_VERTINDICES):
|
case(INT_ATT_NAMES::ATT_VERTINDICES):
|
||||||
return true;
|
return (_mesh.VN() != 0) && (_mesh.FN() != 0);
|
||||||
case(INT_ATT_NAMES::ATT_EDGEINDICES):
|
case(INT_ATT_NAMES::ATT_EDGEINDICES):
|
||||||
return vcg::tri::HasPerVertexFlags(_mesh);
|
return vcg::tri::HasPerVertexFlags(_mesh) || ((_mesh.VN() != 0) && (_mesh.FN() == 0) && (_mesh.EN() == 0));
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -557,7 +541,7 @@ namespace vcg
|
||||||
{
|
{
|
||||||
//If a primitive_modality is not rendered (== no att_VERTPOSITION) all the referred attributes by this view can be eventually deallocated IF they are not used
|
//If a primitive_modality is not rendered (== no att_VERTPOSITION) all the referred attributes by this view can be eventually deallocated IF they are not used
|
||||||
//by some other rendered primitive
|
//by some other rendered primitive
|
||||||
//the vertindices is, as usual a diffrent case
|
//the vertindices is, as usual, a different case
|
||||||
if (it->second._intatts[size_t(pm)][INT_ATT_NAMES::ATT_VERTPOSITION])
|
if (it->second._intatts[size_t(pm)][INT_ATT_NAMES::ATT_VERTPOSITION])
|
||||||
meaningfulrequiredbyatleastoneview = InternalRendAtts::unionSet(meaningfulrequiredbyatleastoneview,it->second._intatts[size_t(pm)]);
|
meaningfulrequiredbyatleastoneview = InternalRendAtts::unionSet(meaningfulrequiredbyatleastoneview,it->second._intatts[size_t(pm)]);
|
||||||
else
|
else
|
||||||
|
|
@ -565,12 +549,16 @@ namespace vcg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool thereisreplicatedview = InternalRendAtts::replicatedPipelineNeeded(meaningfulrequiredbyatleastoneview);
|
bool thereisreplicatedview = InternalRendAtts::replicatedPipelineNeeded(meaningfulrequiredbyatleastoneview);
|
||||||
meaningfulrequiredbyatleastoneview[INT_ATT_NAMES::ATT_VERTINDICES] = !thereisreplicatedview;
|
meaningfulrequiredbyatleastoneview[INT_ATT_NAMES::ATT_VERTINDICES] &= !thereisreplicatedview;
|
||||||
|
|
||||||
InternalRendAtts reallyuseless = InternalRendAtts::complementSet(probabilyuseless,meaningfulrequiredbyatleastoneview);
|
InternalRendAtts reallyuseless = InternalRendAtts::complementSet(probabilyuseless,meaningfulrequiredbyatleastoneview);
|
||||||
|
|
||||||
bool switchreplicatedindexed = (!InternalRendAtts::replicatedPipelineNeeded(_currallocatedboatt) && thereisreplicatedview) || (InternalRendAtts::replicatedPipelineNeeded(_currallocatedboatt) && !thereisreplicatedview);
|
bool switchreplicatedindexed = (!InternalRendAtts::replicatedPipelineNeeded(_currallocatedboatt) && thereisreplicatedview) || (InternalRendAtts::replicatedPipelineNeeded(_currallocatedboatt) && !thereisreplicatedview);
|
||||||
|
|
||||||
|
/*in some way the vertices number changed. If i use the indexed pipeline i have to deallocate/allocate/update the vertex indices*/
|
||||||
|
bool numvertchanged = boExpectedSize(INT_ATT_NAMES::ATT_VERTPOSITION,thereisreplicatedview) != _bo[INT_ATT_NAMES::ATT_VERTPOSITION]->_size;
|
||||||
|
bool vertindforcedupdate = numvertchanged && meaningfulrequiredbyatleastoneview[INT_ATT_NAMES::ATT_VERTINDICES];
|
||||||
|
|
||||||
InternalRendAtts probablytoallocate = InternalRendAtts::complementSet(meaningfulrequiredbyatleastoneview,_currallocatedboatt);
|
InternalRendAtts probablytoallocate = InternalRendAtts::complementSet(meaningfulrequiredbyatleastoneview,_currallocatedboatt);
|
||||||
InternalRendAtts probablytodeallocate = InternalRendAtts::complementSet(_currallocatedboatt,meaningfulrequiredbyatleastoneview);
|
InternalRendAtts probablytodeallocate = InternalRendAtts::complementSet(_currallocatedboatt,meaningfulrequiredbyatleastoneview);
|
||||||
for(unsigned int ii = 0;ii < INT_ATT_NAMES::enumArity();++ii)
|
for(unsigned int ii = 0;ii < INT_ATT_NAMES::enumArity();++ii)
|
||||||
|
|
@ -588,8 +576,11 @@ namespace vcg
|
||||||
tobedeallocated[boname] = (notempty && !hasmeshattribute) ||
|
tobedeallocated[boname] = (notempty && !hasmeshattribute) ||
|
||||||
(notempty && probablytodeallocate[boname]) ||
|
(notempty && probablytodeallocate[boname]) ||
|
||||||
(notempty && reallyuseless[boname]) ||
|
(notempty && reallyuseless[boname]) ||
|
||||||
(notempty && (_bo[boname]->_size != sz) && meaningfulrequiredbyatleastoneview[boname]);
|
(notempty && (_bo[boname]->_size != sz) && meaningfulrequiredbyatleastoneview[boname]) ||
|
||||||
tobeallocated[boname] = (hasmeshattribute && (sz > 0) && (sz != _bo[boname]->_size) && meaningfulrequiredbyatleastoneview[boname]) || (hasmeshattribute && (sz > 0) && probablytoallocate[boname]);
|
(notempty && (boname == INT_ATT_NAMES::ATT_VERTINDICES) && (vertindforcedupdate));
|
||||||
|
tobeallocated[boname] = (hasmeshattribute && (sz > 0) && (sz != _bo[boname]->_size) && meaningfulrequiredbyatleastoneview[boname]) ||
|
||||||
|
(hasmeshattribute && (sz > 0) && probablytoallocate[boname]) ||
|
||||||
|
(hasmeshattribute && (boname == INT_ATT_NAMES::ATT_VERTINDICES) && (vertindforcedupdate));
|
||||||
tobeupdated[boname] = tobeallocated[boname] || (hasmeshattribute && (sz > 0) && !(isvalid) && meaningfulrequiredbyatleastoneview[boname]);
|
tobeupdated[boname] = tobeallocated[boname] || (hasmeshattribute && (sz > 0) && !(isvalid) && meaningfulrequiredbyatleastoneview[boname]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -654,22 +645,6 @@ namespace vcg
|
||||||
|
|
||||||
bool buffersMemoryManagementFunction(const InternalRendAtts& tobeallocated,const InternalRendAtts& tobedeallocated,const InternalRendAtts& tobeupdated)
|
bool buffersMemoryManagementFunction(const InternalRendAtts& tobeallocated,const InternalRendAtts& tobedeallocated,const InternalRendAtts& tobeupdated)
|
||||||
{
|
{
|
||||||
if (_tmpbuffer == 0)
|
|
||||||
{
|
|
||||||
GLfloat tmpdata[9] = {-0.5, -0.5, 0.5,
|
|
||||||
0.5, -0.5, 0.5,
|
|
||||||
-0.5, 0.5, 0.5} ;
|
|
||||||
glGenBuffers(1,&(_tmpbuffer));
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER,_tmpbuffer);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER,4 * 9,(GLvoid*) &(tmpdata[0]),GL_STATIC_DRAW);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER,0);
|
|
||||||
GLuint index[3] = {1,2,0};
|
|
||||||
glGenBuffers(1,&(_tmpind));
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,_tmpind);
|
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,3 * 4 ,(GLvoid*) &(index),GL_STATIC_DRAW);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//GLenum err = glGetError();
|
//GLenum err = glGetError();
|
||||||
bool replicated = isThereAReplicatedPipelineView();
|
bool replicated = isThereAReplicatedPipelineView();
|
||||||
std::ptrdiff_t newallocatedmem = bufferObjectsMemoryRequired(tobeallocated);
|
std::ptrdiff_t newallocatedmem = bufferObjectsMemoryRequired(tobeallocated);
|
||||||
|
|
@ -871,7 +846,6 @@ namespace vcg
|
||||||
|
|
||||||
if (attributestobeupdated[INT_ATT_NAMES::ATT_VERTINDICES])
|
if (attributestobeupdated[INT_ATT_NAMES::ATT_VERTINDICES])
|
||||||
{
|
{
|
||||||
size_t tsz = _bo[INT_ATT_NAMES::ATT_VERTINDICES]->_components * _bo[INT_ATT_NAMES::ATT_VERTINDICES]->getSizeOfGLType() * chunksize;
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bo[INT_ATT_NAMES::ATT_VERTINDICES]->_bohandle);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bo[INT_ATT_NAMES::ATT_VERTINDICES]->_bohandle);
|
||||||
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,chunkingpu * facechunk * _bo[INT_ATT_NAMES::ATT_VERTINDICES]->_components * _bo[INT_ATT_NAMES::ATT_VERTINDICES]->getSizeOfGLType(),_bo[INT_ATT_NAMES::ATT_VERTINDICES]->_components * _bo[INT_ATT_NAMES::ATT_VERTINDICES]->getSizeOfGLType() * chunksize,&ti[0]);
|
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,chunkingpu * facechunk * _bo[INT_ATT_NAMES::ATT_VERTINDICES]->_components * _bo[INT_ATT_NAMES::ATT_VERTINDICES]->getSizeOfGLType(),_bo[INT_ATT_NAMES::ATT_VERTINDICES]->_components * _bo[INT_ATT_NAMES::ATT_VERTINDICES]->getSizeOfGLType() * chunksize,&ti[0]);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
|
@ -905,6 +879,7 @@ namespace vcg
|
||||||
bool isthereaquadview = false;
|
bool isthereaquadview = false;
|
||||||
for(typename ViewsMap::const_iterator it = _perviewreqatts.begin();it != _perviewreqatts.end();++it)
|
for(typename ViewsMap::const_iterator it = _perviewreqatts.begin();it != _perviewreqatts.end();++it)
|
||||||
isthereaquadview = (it->second._intatts[size_t(PR_WIREFRAME_EDGES)][INT_ATT_NAMES::ATT_VERTPOSITION]) || isthereaquadview;
|
isthereaquadview = (it->second._intatts[size_t(PR_WIREFRAME_EDGES)][INT_ATT_NAMES::ATT_VERTPOSITION]) || isthereaquadview;
|
||||||
|
return isthereaquadview;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -983,13 +958,13 @@ namespace vcg
|
||||||
_texindnumtriangles.resize(_chunkmap.size());
|
_texindnumtriangles.resize(_chunkmap.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<size_t> vpatlas;
|
std::vector<GLuint> vpatlas;
|
||||||
if (attributestobeupdated[INT_ATT_NAMES::ATT_EDGEINDICES])
|
if (attributestobeupdated[INT_ATT_NAMES::ATT_EDGEINDICES])
|
||||||
vpatlas.resize(_mesh.VN(),UINT_MAX);
|
vpatlas.resize(_mesh.VN(),UINT_MAX);
|
||||||
|
|
||||||
int faceind = 0;
|
int faceind = 0;
|
||||||
size_t chunkindex = faceind;
|
size_t chunkindex = faceind;
|
||||||
size_t triangles = 0;
|
GLuint triangles = 0;
|
||||||
|
|
||||||
|
|
||||||
for(ChunkMap::const_iterator mit = _chunkmap.begin();mit != _chunkmap.end();++mit)
|
for(ChunkMap::const_iterator mit = _chunkmap.begin();mit != _chunkmap.end();++mit)
|
||||||
|
|
@ -1180,7 +1155,7 @@ namespace vcg
|
||||||
{
|
{
|
||||||
glDisableClientState(bobj->_clientstatetag);
|
glDisableClientState(bobj->_clientstatetag);
|
||||||
}
|
}
|
||||||
|
//glBufferData(bobj->_target, sizeof(vcg::Point3f)*_primitivebatch, 0, GL_DYNAMIC_DRAW);
|
||||||
glDeleteBuffers(1,&(bobj->_bohandle));
|
glDeleteBuffers(1,&(bobj->_bohandle));
|
||||||
glFlush();
|
glFlush();
|
||||||
glFinish();
|
glFinish();
|
||||||
|
|
@ -1282,6 +1257,70 @@ namespace vcg
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void drawFun(const PVData& dt, const std::vector<GLuint>& textid = std::vector<GLuint>()) const
|
||||||
|
{
|
||||||
|
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glPushMatrix();
|
||||||
|
glMultMatrix(_tr);
|
||||||
|
|
||||||
|
if ((dt._glopts != NULL) && (dt._glopts->_perbbox_enabled))
|
||||||
|
drawBBox(dt._glopts);
|
||||||
|
|
||||||
|
if (dt.isPrimitiveActive(PR_SOLID))
|
||||||
|
{
|
||||||
|
bool somethingmore = dt.isPrimitiveActive(PR_WIREFRAME_EDGES) || dt.isPrimitiveActive(PR_WIREFRAME_TRIANGLES) || dt.isPrimitiveActive(PR_POINTS);
|
||||||
|
if (somethingmore)
|
||||||
|
{
|
||||||
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||||
|
glPolygonOffset(1.0, 1);
|
||||||
|
}
|
||||||
|
drawFilledTriangles(dt._intatts[size_t(PR_SOLID)], dt._glopts, textid);
|
||||||
|
if (somethingmore)
|
||||||
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dt.isPrimitiveActive(PR_WIREFRAME_EDGES) || dt.isPrimitiveActive(PR_WIREFRAME_TRIANGLES))
|
||||||
|
{
|
||||||
|
//InternalRendAtts tmpatts = atts;
|
||||||
|
bool pointstoo = dt.isPrimitiveActive(PR_POINTS);
|
||||||
|
|
||||||
|
if (pointstoo)
|
||||||
|
{
|
||||||
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||||
|
glPolygonOffset(1.0, 1);
|
||||||
|
}
|
||||||
|
bool solidtoo = dt.isPrimitiveActive(PR_SOLID);
|
||||||
|
|
||||||
|
/*EDGE | TRI | DRAW
|
||||||
|
---------------------------------
|
||||||
|
TRUE TRUE EDGE
|
||||||
|
TRUE FALSE EDGE
|
||||||
|
FALSE TRUE TRI
|
||||||
|
FALSE FALSE NOTHING */
|
||||||
|
|
||||||
|
if (dt.isPrimitiveActive(PR_WIREFRAME_EDGES))
|
||||||
|
drawEdges(dt._intatts[size_t(PR_WIREFRAME_EDGES)], dt._glopts);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dt.isPrimitiveActive(PR_WIREFRAME_TRIANGLES))
|
||||||
|
{
|
||||||
|
drawWiredTriangles(dt._intatts[size_t(PR_WIREFRAME_TRIANGLES)], dt._glopts, textid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pointstoo || solidtoo)
|
||||||
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||||
|
}
|
||||||
|
if (dt.isPrimitiveActive(PR_POINTS))
|
||||||
|
drawPoints(dt._intatts[size_t(PR_POINTS)], dt._glopts,textid);
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
glPopAttrib();
|
||||||
|
glFlush();
|
||||||
|
glFinish();
|
||||||
|
}
|
||||||
|
|
||||||
void drawFilledTriangles(const InternalRendAtts& req,const GL_OPTIONS_DERIVED_TYPE* glopts,const std::vector<GLuint>& textureindex = std::vector<GLuint>()) const
|
void drawFilledTriangles(const InternalRendAtts& req,const GL_OPTIONS_DERIVED_TYPE* glopts,const std::vector<GLuint>& textureindex = std::vector<GLuint>()) const
|
||||||
{
|
{
|
||||||
if (_mesh.VN() == 0)
|
if (_mesh.VN() == 0)
|
||||||
|
|
@ -1291,13 +1330,13 @@ namespace vcg
|
||||||
|
|
||||||
bool isgloptsvalid = (glopts != NULL);
|
bool isgloptsvalid = (glopts != NULL);
|
||||||
|
|
||||||
|
if (isgloptsvalid && glopts->_persolid_noshading)
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
else
|
||||||
if ((!isgloptsvalid) || (req[INT_ATT_NAMES::ATT_VERTNORMAL]) || (req[INT_ATT_NAMES::ATT_FACENORMAL]))
|
if ((!isgloptsvalid) || (req[INT_ATT_NAMES::ATT_VERTNORMAL]) || (req[INT_ATT_NAMES::ATT_FACENORMAL]))
|
||||||
{
|
{
|
||||||
glEnable(GL_LIGHTING);
|
glEnable(GL_LIGHTING);
|
||||||
}
|
}
|
||||||
else if (isgloptsvalid && glopts->_persolid_noshading)
|
|
||||||
glDisable(GL_LIGHTING);
|
|
||||||
|
|
||||||
|
|
||||||
glEnable(GL_COLOR_MATERIAL);
|
glEnable(GL_COLOR_MATERIAL);
|
||||||
if ((isgloptsvalid) && (glopts->_persolid_fixed_color_enabled))
|
if ((isgloptsvalid) && (glopts->_persolid_fixed_color_enabled))
|
||||||
|
|
@ -1305,7 +1344,8 @@ namespace vcg
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((isgloptsvalid) && (glopts->_persolid_mesh_color_enabled))
|
if ((isgloptsvalid) && (glopts->_persolid_mesh_color_enabled))
|
||||||
glColor(glopts->_permesh_color);
|
glColor(_mesh.C());
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if ((req[INT_ATT_NAMES::ATT_VERTCOLOR]) || (req[INT_ATT_NAMES::ATT_FACECOLOR]))
|
if ((req[INT_ATT_NAMES::ATT_VERTCOLOR]) || (req[INT_ATT_NAMES::ATT_FACECOLOR]))
|
||||||
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
|
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
|
||||||
|
|
@ -1332,13 +1372,13 @@ namespace vcg
|
||||||
|
|
||||||
bool isgloptsvalid = (glopts != NULL);
|
bool isgloptsvalid = (glopts != NULL);
|
||||||
|
|
||||||
|
if (isgloptsvalid && glopts->_perwire_noshading)
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
else
|
||||||
if ((!isgloptsvalid) || (req[INT_ATT_NAMES::ATT_VERTNORMAL]))
|
if ((!isgloptsvalid) || (req[INT_ATT_NAMES::ATT_VERTNORMAL]))
|
||||||
{
|
{
|
||||||
glEnable(GL_LIGHTING);
|
glEnable(GL_LIGHTING);
|
||||||
}
|
}
|
||||||
else if (isgloptsvalid && glopts->_perwire_noshading)
|
|
||||||
glDisable(GL_LIGHTING);
|
|
||||||
|
|
||||||
|
|
||||||
glEnable(GL_COLOR_MATERIAL);
|
glEnable(GL_COLOR_MATERIAL);
|
||||||
if ((isgloptsvalid) && (glopts->_perwire_fixed_color_enabled))
|
if ((isgloptsvalid) && (glopts->_perwire_fixed_color_enabled))
|
||||||
|
|
@ -1346,7 +1386,8 @@ namespace vcg
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((isgloptsvalid) && (glopts->_perwire_mesh_color_enabled))
|
if ((isgloptsvalid) && (glopts->_perwire_mesh_color_enabled))
|
||||||
glColor(glopts->_permesh_color);
|
glColor(_mesh.C());
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (req[INT_ATT_NAMES::ATT_VERTCOLOR])
|
if (req[INT_ATT_NAMES::ATT_VERTCOLOR])
|
||||||
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
|
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
|
||||||
|
|
@ -1538,7 +1579,7 @@ namespace vcg
|
||||||
glEnd();
|
glEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawPoints(const InternalRendAtts& req,GL_OPTIONS_DERIVED_TYPE* glopts) const
|
void drawPoints(const InternalRendAtts& req,GL_OPTIONS_DERIVED_TYPE* glopts, const std::vector<GLuint>& textureindex = std::vector<GLuint>()) const
|
||||||
{
|
{
|
||||||
if (_mesh.VN() == 0)
|
if (_mesh.VN() == 0)
|
||||||
return;
|
return;
|
||||||
|
|
@ -1547,32 +1588,44 @@ namespace vcg
|
||||||
|
|
||||||
bool isgloptsvalid = (glopts != NULL);
|
bool isgloptsvalid = (glopts != NULL);
|
||||||
|
|
||||||
|
|
||||||
|
if ((isgloptsvalid && glopts->_perpoint_noshading) || (isgloptsvalid && glopts->_perpoint_dot_enabled))
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
else
|
||||||
if ((!isgloptsvalid) || req[INT_ATT_NAMES::ATT_VERTNORMAL])
|
if ((!isgloptsvalid) || req[INT_ATT_NAMES::ATT_VERTNORMAL])
|
||||||
{
|
{
|
||||||
glEnable(GL_LIGHTING);
|
glEnable(GL_LIGHTING);
|
||||||
}
|
}
|
||||||
else if (isgloptsvalid && glopts->_perpoint_noshading)
|
|
||||||
glDisable(GL_LIGHTING);
|
|
||||||
|
|
||||||
glEnable(GL_COLOR_MATERIAL);
|
glEnable(GL_COLOR_MATERIAL);
|
||||||
if ((isgloptsvalid) && ((glopts->_perpoint_fixed_color_enabled) || (glopts->_perpoint_mesh_color_enabled)))
|
if ((isgloptsvalid) && ((glopts->_perpoint_fixed_color_enabled) || (glopts->_perpoint_mesh_color_enabled))){
|
||||||
|
if (glopts->_perpoint_fixed_color_enabled)
|
||||||
glColor(glopts->_perpoint_fixed_color);
|
glColor(glopts->_perpoint_fixed_color);
|
||||||
|
else
|
||||||
|
glColor(_mesh.C());
|
||||||
|
}
|
||||||
|
|
||||||
if (req[INT_ATT_NAMES::ATT_VERTCOLOR])
|
if (req[INT_ATT_NAMES::ATT_VERTCOLOR])
|
||||||
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
|
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
|
||||||
|
|
||||||
|
|
||||||
if (req[INT_ATT_NAMES::ATT_VERTTEXTURE])
|
if (req[INT_ATT_NAMES::ATT_VERTTEXTURE])
|
||||||
|
{
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
if (textureindex.size() > 0)
|
||||||
|
glBindTexture(GL_TEXTURE_2D, textureindex[0]);
|
||||||
|
else
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
glDisable(GL_TEXTURE_2D);
|
glDisable(GL_TEXTURE_2D);
|
||||||
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bo[GLMeshAttributesInfo::ATT_VERTINDEX]->_bohandle);
|
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bo[GLMeshAttributesInfo::ATT_VERTINDEX]->_bohandle);
|
||||||
|
|
||||||
if (glopts != NULL)
|
if (glopts != NULL)
|
||||||
{
|
{
|
||||||
|
if (!glopts->_perpoint_dot_enabled)
|
||||||
glPointSize(glopts->_perpoint_pointsize);
|
glPointSize(glopts->_perpoint_pointsize);
|
||||||
if(glopts->_perpoint_pointsmooth_enabled)
|
if ((glopts->_perpoint_pointsmooth_enabled) || (glopts->_perpoint_dot_enabled))
|
||||||
glEnable(GL_POINT_SMOOTH);
|
glEnable(GL_POINT_SMOOTH);
|
||||||
else
|
else
|
||||||
glDisable(GL_POINT_SMOOTH);
|
glDisable(GL_POINT_SMOOTH);
|
||||||
|
|
@ -1596,11 +1649,31 @@ namespace vcg
|
||||||
pointsize = glopts->_perpoint_pointsize;
|
pointsize = glopts->_perpoint_pointsize;
|
||||||
glPointSize(pointsize);
|
glPointSize(pointsize);
|
||||||
}
|
}
|
||||||
|
if (glopts->_perpoint_dot_enabled)
|
||||||
|
{
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDepthRange(0.0, 0.9999);
|
||||||
|
glDepthFunc(GL_LEQUAL);
|
||||||
|
glPointSize(glopts->_perpoint_pointsize + 0.5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (isBORenderingAvailable())
|
if (isBORenderingAvailable())
|
||||||
drawPointsBO(req);
|
drawPointsBO(req);
|
||||||
else
|
else
|
||||||
drawPointsIM(req);
|
drawPointsIM(req);
|
||||||
|
|
||||||
|
if ((glopts != NULL) && (glopts->_perpoint_dot_enabled))
|
||||||
|
{
|
||||||
|
float psize = 0.0001f;
|
||||||
|
if ((glopts->_perpoint_pointsize - 1) > 0)
|
||||||
|
psize = (glopts->_perpoint_pointsize - 1);
|
||||||
|
glPointSize(psize);
|
||||||
|
if (isBORenderingAvailable())
|
||||||
|
drawPointsBO(req);
|
||||||
|
else
|
||||||
|
drawPointsIM(req);
|
||||||
|
}
|
||||||
glPopAttrib();
|
glPopAttrib();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1609,10 +1682,8 @@ namespace vcg
|
||||||
size_t pointsnum = _mesh.VN();
|
size_t pointsnum = _mesh.VN();
|
||||||
if (InternalRendAtts::replicatedPipelineNeeded(_currallocatedboatt))
|
if (InternalRendAtts::replicatedPipelineNeeded(_currallocatedboatt))
|
||||||
pointsnum = _mesh.FN() * 3;
|
pointsnum = _mesh.FN() * 3;
|
||||||
|
|
||||||
updateClientState(req);
|
updateClientState(req);
|
||||||
glDrawArrays(GL_POINTS,0,GLsizei(pointsnum));
|
glDrawArrays(GL_POINTS,0,GLsizei(pointsnum));
|
||||||
|
|
||||||
/*disable all client state buffers*/
|
/*disable all client state buffers*/
|
||||||
InternalRendAtts tmp;
|
InternalRendAtts tmp;
|
||||||
updateClientState(tmp);
|
updateClientState(tmp);
|
||||||
|
|
@ -1645,19 +1716,18 @@ namespace vcg
|
||||||
return;
|
return;
|
||||||
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
||||||
|
|
||||||
|
|
||||||
bool isgloptsvalid = (glopts != NULL);
|
bool isgloptsvalid = (glopts != NULL);
|
||||||
|
|
||||||
glEnable(GL_COLOR_MATERIAL);
|
glEnable(GL_COLOR_MATERIAL);
|
||||||
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
|
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
|
||||||
|
|
||||||
if ((!isgloptsvalid) || req[INT_ATT_NAMES::ATT_VERTNORMAL])
|
if (isgloptsvalid && glopts->_perwire_noshading)
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
else
|
||||||
|
if ((!isgloptsvalid) || (req[INT_ATT_NAMES::ATT_VERTNORMAL]))
|
||||||
{
|
{
|
||||||
glEnable(GL_LIGHTING);
|
glEnable(GL_LIGHTING);
|
||||||
}
|
}
|
||||||
else if (isgloptsvalid && glopts->_perwire_noshading)
|
|
||||||
glDisable(GL_LIGHTING);
|
|
||||||
|
|
||||||
|
|
||||||
bool colordefinedenabled = (isgloptsvalid) && ((glopts->_perwire_fixed_color_enabled) || (glopts->_perwire_mesh_color_enabled));
|
bool colordefinedenabled = (isgloptsvalid) && ((glopts->_perwire_fixed_color_enabled) || (glopts->_perwire_mesh_color_enabled));
|
||||||
|
|
||||||
|
|
@ -1665,7 +1735,12 @@ namespace vcg
|
||||||
{
|
{
|
||||||
vcg::Color4b tmpcol = vcg::Color4b(vcg::Color4b::DarkGray);
|
vcg::Color4b tmpcol = vcg::Color4b(vcg::Color4b::DarkGray);
|
||||||
if (colordefinedenabled)
|
if (colordefinedenabled)
|
||||||
|
{
|
||||||
|
if (glopts->_perwire_fixed_color_enabled)
|
||||||
tmpcol = glopts->_perwire_fixed_color;
|
tmpcol = glopts->_perwire_fixed_color;
|
||||||
|
else
|
||||||
|
tmpcol = _mesh.cC();
|
||||||
|
}
|
||||||
glColor(tmpcol);
|
glColor(tmpcol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1771,7 +1846,7 @@ namespace vcg
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((isgloptsvalid) && (glopts->_perbbox_mesh_color_enabled))
|
if ((isgloptsvalid) && (glopts->_perbbox_mesh_color_enabled))
|
||||||
glColor(glopts->_permesh_color);
|
glColor(_mesh.C());
|
||||||
else
|
else
|
||||||
glColor(vcg::Color4b(vcg::Color4b::White));
|
glColor(vcg::Color4b(vcg::Color4b::White));
|
||||||
}
|
}
|
||||||
|
|
@ -2096,8 +2171,8 @@ namespace vcg
|
||||||
assert(nz>=0);
|
assert(nz>=0);
|
||||||
assert(nz<pf->VN());
|
assert(nz<pf->VN());
|
||||||
|
|
||||||
_v[0] = size_t(vcg::tri::Index(m,pf->V(nz)));;
|
_v[0] = GLuint(vcg::tri::Index(m,pf->V(nz)));;
|
||||||
_v[1] = size_t(vcg::tri::Index(m,pf->V(pf->Next(nz))));
|
_v[1] = GLuint(vcg::tri::Index(m,pf->V(pf->Next(nz))));
|
||||||
assert(_v[0] != _v[1]); // The face pointed by 'f' is Degenerate (two coincident vertexes)
|
assert(_v[0] != _v[1]); // The face pointed by 'f' is Degenerate (two coincident vertexes)
|
||||||
|
|
||||||
if( _v[0] > _v[1] )
|
if( _v[0] > _v[1] )
|
||||||
|
|
@ -2249,8 +2324,6 @@ namespace vcg
|
||||||
DebugInfo _loginfo;
|
DebugInfo _loginfo;
|
||||||
|
|
||||||
std::vector<InternalRendAtts> _meaningfulattsperprimitive;
|
std::vector<InternalRendAtts> _meaningfulattsperprimitive;
|
||||||
GLuint _tmpbuffer;
|
|
||||||
GLuint _tmpind;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
/****************************************************************************
|
||||||
|
* VCGLib o o *
|
||||||
|
* Visual and Computer Graphics Library o o *
|
||||||
|
* _ O _ *
|
||||||
|
* Copyright(C) 2004-2016 \/)\/ *
|
||||||
|
* Visual Computing Lab /\/| *
|
||||||
|
* ISTI - Italian National Research Council | *
|
||||||
|
* \ *
|
||||||
|
* All rights reserved. *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||||
|
* for more details. *
|
||||||
|
* *
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __VCG_GL_TYPE_NAME
|
||||||
|
#define __VCG_GL_TYPE_NAME
|
||||||
|
|
||||||
|
namespace vcg
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
class GL_TYPE_NM
|
||||||
|
{public:
|
||||||
|
static GLenum SCALAR() { assert(0); return 0;}
|
||||||
|
};
|
||||||
|
template <> class GL_TYPE_NM<float>
|
||||||
|
{ public:
|
||||||
|
typedef GLfloat ScalarType;
|
||||||
|
static GLenum SCALAR() { return GL_FLOAT; }
|
||||||
|
};
|
||||||
|
template <> class GL_TYPE_NM<double>
|
||||||
|
{public:
|
||||||
|
typedef GLdouble ScalarType;
|
||||||
|
static GLenum SCALAR() { return GL_DOUBLE; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -26,6 +26,8 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include "gl_type_name.h"
|
||||||
|
|
||||||
namespace vcg{
|
namespace vcg{
|
||||||
|
|
||||||
template <class MESH_TYPE>
|
template <class MESH_TYPE>
|
||||||
|
|
@ -153,7 +155,7 @@ public:
|
||||||
|
|
||||||
Box3<ScalarType> reg =ComputeDCBox(x,y,width,height);
|
Box3<ScalarType> reg =ComputeDCBox(x,y,width,height);
|
||||||
|
|
||||||
if(M!=lastM || &m != lastm)
|
if ((M != lastM) || (&m != lastm) || (pVec.size() != m.VN()))
|
||||||
{
|
{
|
||||||
FillProjectedVector(m,pVec,M,viewportF);
|
FillProjectedVector(m,pVec,M,viewportF);
|
||||||
lastM = M;
|
lastM = M;
|
||||||
|
|
@ -182,21 +184,24 @@ public:
|
||||||
reg.Add(CoordType(x-width/ScalarType(2.0),y-height/ScalarType(2.0),ScalarType(-1.0)));
|
reg.Add(CoordType(x-width/ScalarType(2.0),y-height/ScalarType(2.0),ScalarType(-1.0)));
|
||||||
reg.Add(CoordType(x+width/ScalarType(2.0),y+height/ScalarType(2.0),ScalarType(1.0)));
|
reg.Add(CoordType(x+width/ScalarType(2.0),y+height/ScalarType(2.0),ScalarType(1.0)));
|
||||||
|
|
||||||
if(M!=lastM || &m != lastm)
|
if((M!=lastM) || (&m != lastm) || (pVec.size() != m.VN()))
|
||||||
{
|
{
|
||||||
FillProjectedVector(m,pVec,M,viewportF);
|
FillProjectedVector(m,pVec,M,viewportF);
|
||||||
lastM = M;
|
lastM = M;
|
||||||
lastm = &m;
|
lastm = &m;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(size_t i=0;i<m.face.size();++i) if(!m.face[i].IsD())
|
for (size_t i = 0; i < m.face.size(); ++i)
|
||||||
{
|
{
|
||||||
const CoordType &p0 = pVec[tri::Index(m,m.face[i].V(0))];
|
if (!m.face[i].IsD())
|
||||||
const CoordType &p1 = pVec[tri::Index(m,m.face[i].V(1))];
|
{
|
||||||
const CoordType &p2 = pVec[tri::Index(m,m.face[i].V(2))];
|
const CoordType &p0 = pVec[tri::Index(m, m.face[i].V(0))];
|
||||||
if( (p0[2]>-1.0f) && (p1[2]>-1.0f) && (p2[2]>-1.0f) && IntersectionTriangleBox(reg,p0,p1,p2))
|
const CoordType &p1 = pVec[tri::Index(m, m.face[i].V(1))];
|
||||||
|
const CoordType &p2 = pVec[tri::Index(m, m.face[i].V(2))];
|
||||||
|
if ((p0[2] > -1.0f) && (p1[2] > -1.0f) && (p2[2] > -1.0f) && IntersectionTriangleBox(reg, p0, p1, p2))
|
||||||
result.push_back(&m.face[i]);
|
result.push_back(&m.face[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return result.size();
|
return result.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,26 +34,10 @@
|
||||||
#include <wrap/gl/space.h>
|
#include <wrap/gl/space.h>
|
||||||
#include <wrap/gl/math.h>
|
#include <wrap/gl/math.h>
|
||||||
#include <vcg/space/color4.h>
|
#include <vcg/space/color4.h>
|
||||||
|
#include <wrap/gl/gl_type_name.h>
|
||||||
|
|
||||||
|
namespace vcg
|
||||||
namespace vcg {
|
{
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class GL_TYPE_NM
|
|
||||||
{public:
|
|
||||||
static GLenum SCALAR() { assert(0); return 0;}
|
|
||||||
};
|
|
||||||
template <> class GL_TYPE_NM<float>
|
|
||||||
{ public:
|
|
||||||
typedef GLfloat ScalarType;
|
|
||||||
static GLenum SCALAR() { return GL_FLOAT; }
|
|
||||||
};
|
|
||||||
template <> class GL_TYPE_NM<double>
|
|
||||||
{public:
|
|
||||||
typedef GLdouble ScalarType;
|
|
||||||
static GLenum SCALAR() { return GL_DOUBLE; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//template <> GL_TYPE::SCALAR<double>() { return GL_DOUBLE; }
|
//template <> GL_TYPE::SCALAR<double>() { return GL_DOUBLE; }
|
||||||
|
|
||||||
// classe base di glwrap usata solo per poter usare i vari drawmode, normalmode senza dover
|
// classe base di glwrap usata solo per poter usare i vari drawmode, normalmode senza dover
|
||||||
|
|
|
||||||
|
|
@ -146,36 +146,39 @@ void Rubberband::RenderLine(QGLWidget* gla, Point3f AA, Point3f BB)
|
||||||
glDisable(GL_LIGHTING);
|
glDisable(GL_LIGHTING);
|
||||||
glDisable(GL_TEXTURE_2D);
|
glDisable(GL_TEXTURE_2D);
|
||||||
glDepthMask(false);
|
glDepthMask(false);
|
||||||
glLineWidth(2.5);
|
|
||||||
glPointSize(6.0);
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
|
|
||||||
glEnable(GL_LINE_SMOOTH);
|
glEnable(GL_LINE_SMOOTH);
|
||||||
glEnable(GL_POINT_SMOOTH);
|
glEnable(GL_POINT_SMOOTH);
|
||||||
glColor(color);
|
glColor(color);
|
||||||
glLineWidth(2.0);
|
|
||||||
glPointSize(5.0);
|
|
||||||
glBegin(GL_LINES);
|
|
||||||
glVertex(AA);
|
|
||||||
glVertex(BB);
|
|
||||||
glEnd();
|
|
||||||
glBegin(GL_POINTS);
|
|
||||||
glVertex(AA);
|
|
||||||
glVertex(BB);
|
|
||||||
glEnd();
|
|
||||||
glDepthFunc(GL_GREATER);
|
|
||||||
glLineWidth(1.0f);
|
|
||||||
glPointSize(2.0f);
|
|
||||||
glBegin(GL_LINES);
|
|
||||||
glVertex(AA);
|
|
||||||
glVertex(BB);
|
|
||||||
glEnd();
|
|
||||||
glBegin(GL_POINTS);
|
|
||||||
glVertex(AA);
|
|
||||||
glVertex(BB);
|
|
||||||
glEnd();
|
|
||||||
glDepthFunc(GL_LESS);
|
|
||||||
|
|
||||||
|
// IN FRONT OF SURFACE
|
||||||
|
glDepthFunc(GL_LESS);
|
||||||
|
glLineWidth(2.5);
|
||||||
|
glPointSize(6.0);
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
glVertex(AA);
|
||||||
|
glVertex(BB);
|
||||||
|
glEnd();
|
||||||
|
glBegin(GL_POINTS);
|
||||||
|
glVertex(AA);
|
||||||
|
glVertex(BB);
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
// BEHIND SURFACE
|
||||||
|
glDepthFunc(GL_GREATER);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
|
||||||
|
glLineWidth(1.5f);
|
||||||
|
glPointSize(4.0f);
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
glVertex(AA);
|
||||||
|
glVertex(BB);
|
||||||
|
glEnd();
|
||||||
|
glBegin(GL_POINTS);
|
||||||
|
glVertex(AA);
|
||||||
|
glVertex(BB);
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
glDepthFunc(GL_LESS);
|
||||||
glPopAttrib();
|
glPopAttrib();
|
||||||
assert(!glGetError());
|
assert(!glGetError());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,8 @@ void PanMode::Apply (Trackball * tb, Point3f new_point)
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanMode::Draw(Trackball * tb){
|
void PanMode::Draw(Trackball * tb){
|
||||||
DrawSphereIcon(tb,true );
|
DrawSphereIcon(tb,true);
|
||||||
|
DrawSphereAxis(tb);
|
||||||
DrawUglyPanMode(tb);
|
DrawUglyPanMode(tb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ bool HitHyper (Point3f center, float radius, Point3f viewpoint, Plane3f viewplan
|
||||||
* in the simple ortho case, the hit point is just the value of
|
* in the simple ortho case, the hit point is just the value of
|
||||||
* y = 1/x * (r^2 /2 ) on the hitOnViewPlane
|
* y = 1/x * (r^2 /2 ) on the hitOnViewPlane
|
||||||
*/
|
*/
|
||||||
bool HitHyperOrtho(Point3f center, float radius, Point3f viewpoint, Plane3f viewplane,
|
bool HitHyperOrtho(Point3f center, float radius, Point3f /*viewpoint*/, Plane3f viewplane,
|
||||||
Point3f hitOnViewplane, Point3f & hit)
|
Point3f hitOnViewplane, Point3f & hit)
|
||||||
{
|
{
|
||||||
float xval = Distance (center, hitOnViewplane);
|
float xval = Distance (center, hitOnViewplane);
|
||||||
|
|
@ -714,8 +714,8 @@ void DrawSphereIcon (Trackball * tb, bool active, bool planeshandle=false)
|
||||||
glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, col);
|
glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, col);
|
||||||
DrawCircle(planeshandle);
|
DrawCircle(planeshandle);
|
||||||
|
|
||||||
glPopMatrix ();
|
glPopMatrix();
|
||||||
glPopAttrib ();
|
glPopAttrib();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEMPORARY drawing section
|
// TEMPORARY drawing section
|
||||||
|
|
@ -832,6 +832,66 @@ void DrawUglyScaleMode(Trackball * tb)
|
||||||
DrawUglyLetter(tb,ugly_s);
|
DrawUglyLetter(tb,ugly_s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief function to draw X,Y and Z axis in the trackball sphere.
|
||||||
|
|
||||||
|
Draws the three colored axis inside the trackball sphere. added to better see the trackball center when panning
|
||||||
|
|
||||||
|
@param tb the manipulator.
|
||||||
|
*/
|
||||||
|
void DrawSphereAxis(Trackball * tb)
|
||||||
|
{
|
||||||
|
glPushAttrib(GL_TRANSFORM_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_LINE_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT);
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glPushMatrix();
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
|
Point3f center = tb->center + tb->track.InverseMatrix()*Point3f(0, 0, 0);
|
||||||
|
glTranslate(center);
|
||||||
|
glScale(tb->radius / tb->track.sca);
|
||||||
|
|
||||||
|
float amb[4] = { .35f, .35f, .35f, 1.0f };
|
||||||
|
float col[4] = { .5f, .5f, .8f, 1.0f };
|
||||||
|
glEnable(GL_LINE_SMOOTH);
|
||||||
|
glLineWidth(DH.LineWidthMoving);
|
||||||
|
glDisable(GL_COLOR_MATERIAL); // has to be disabled, it is used by wrapper to draw meshes, and prevent direct material setting, used here
|
||||||
|
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
|
glEnable(GL_LIGHT0);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glColor(DH.color);
|
||||||
|
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, amb);
|
||||||
|
|
||||||
|
col[0] = 1.0f; col[1] = 0.0f; col[2] = 0.0f;
|
||||||
|
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
glNormal3d(-1.0, 0.0, 0.0);
|
||||||
|
glVertex3d(-1.2, 0.0, 0.0);
|
||||||
|
glNormal3d( 1.0, 0.0, 0.0);
|
||||||
|
glVertex3d( 1.2, 0.0, 0.0);
|
||||||
|
glEnd();
|
||||||
|
col[0] = 0.0f; col[1] = 1.0f; col[2] = 0.0f;
|
||||||
|
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
glNormal3d(0.0,-1.0, 0.0);
|
||||||
|
glVertex3d(0.0,-1.2, 0.0);
|
||||||
|
glNormal3d(0.0, 1.0, 0.0);
|
||||||
|
glVertex3d(0.0, 1.2, 0.0);
|
||||||
|
glEnd();
|
||||||
|
col[0] = 0.0f; col[1] = 0.0f; col[2] = 1.0f;
|
||||||
|
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
glNormal3d(0.0, 0.0,-1.0);
|
||||||
|
glVertex3d(0.0, 0.0,-1.2);
|
||||||
|
glNormal3d(0.0, 0.0, 1.0);
|
||||||
|
glVertex3d(0.0, 0.0, 1.2);
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
glPopAttrib();
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief AxisMode drawing function, member of the \e DrawUgly series.
|
@brief AxisMode drawing function, member of the \e DrawUgly series.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ namespace vcg {
|
||||||
typedef typename SaveMeshType::VertexIterator VertexIterator;
|
typedef typename SaveMeshType::VertexIterator VertexIterator;
|
||||||
typedef typename SaveMeshType::FaceIterator FaceIterator;
|
typedef typename SaveMeshType::FaceIterator FaceIterator;
|
||||||
|
|
||||||
static int Save(SaveMeshType &m, const char * filename, int mask=0 )
|
static int Save(SaveMeshType &m, const char * filename, int /*mask*/ )
|
||||||
{
|
{
|
||||||
QFile device(filename);
|
QFile device(filename);
|
||||||
if (!device.open(QFile::WriteOnly))
|
if (!device.open(QFile::WriteOnly))
|
||||||
|
|
|
||||||
|
|
@ -405,7 +405,7 @@ namespace vcg {
|
||||||
fprintf(fpout,"%.*g %.*g %.*g " ,DGT,vp->P()[0],DGT,vp->P()[1],DGT,vp->P()[2]);
|
fprintf(fpout,"%.*g %.*g %.*g " ,DGT,vp->P()[0],DGT,vp->P()[1],DGT,vp->P()[2]);
|
||||||
|
|
||||||
if( HasPerVertexNormal(m) && (pi.mask & Mask::IOM_VERTNORMAL) )
|
if( HasPerVertexNormal(m) && (pi.mask & Mask::IOM_VERTNORMAL) )
|
||||||
fprintf(fpout,"%.*g %.*g %.*g " ,DGT,vp->N()[0],DGT,vp->N()[1],DGT,vp->N()[2]);
|
fprintf(fpout,"%.*g %.*g %.*g " ,DGT,double(vp->N()[0]),DGT,double(vp->N()[1]),DGT,double(vp->N()[2]));
|
||||||
|
|
||||||
if( HasPerVertexFlags(m) && (pi.mask & Mask::IOM_VERTFLAGS))
|
if( HasPerVertexFlags(m) && (pi.mask & Mask::IOM_VERTFLAGS))
|
||||||
fprintf(fpout,"%d ",vp->Flags());
|
fprintf(fpout,"%d ",vp->Flags());
|
||||||
|
|
@ -559,7 +559,7 @@ namespace vcg {
|
||||||
else if( HasPerWedgeTexCoord(m) && (pi.mask & Mask::IOM_WEDGTEXCOORD) )
|
else if( HasPerWedgeTexCoord(m) && (pi.mask & Mask::IOM_WEDGTEXCOORD) )
|
||||||
{
|
{
|
||||||
fprintf(fpout,"%d ",fp->VN()*2);
|
fprintf(fpout,"%d ",fp->VN()*2);
|
||||||
for(int k=0;k<fp->VN()*2;++k)
|
for(int k=0;k<fp->VN();++k)
|
||||||
fprintf(fpout,"%f %f "
|
fprintf(fpout,"%f %f "
|
||||||
,fp->WT(k).u()
|
,fp->WT(k).u()
|
||||||
,fp->WT(k).v()
|
,fp->WT(k).v()
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,9 @@ return lastType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum ImporterError {
|
||||||
|
E_NOERROR =0 // No error =0 is the standard for ALL the imported files.
|
||||||
|
};
|
||||||
// simple aux function that returns true if a given file has a given extesnion
|
// simple aux function that returns true if a given file has a given extesnion
|
||||||
static bool FileExtension(std::string filename, std::string extension)
|
static bool FileExtension(std::string filename, std::string extension)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ namespace vcg
|
||||||
}
|
}
|
||||||
|
|
||||||
sa = line.split(' ');
|
sa = line.split(' ');
|
||||||
if (!sa.size()>=3)
|
if (!(sa.size()>=3))
|
||||||
{
|
{
|
||||||
std::cerr << "Error parsing vertex " << line.toLocal8Bit().data() << "\n";
|
std::cerr << "Error parsing vertex " << line.toLocal8Bit().data() << "\n";
|
||||||
return InvalidFile;
|
return InvalidFile;
|
||||||
|
|
@ -213,7 +213,7 @@ namespace vcg
|
||||||
}
|
}
|
||||||
|
|
||||||
sa = line.split(' ');
|
sa = line.split(' ');
|
||||||
if (!sa.size()>=2)
|
if (!(sa.size()>=2))
|
||||||
{
|
{
|
||||||
std::cerr << "Error parsing edge " << line.toLocal8Bit().data() << "\n";
|
std::cerr << "Error parsing edge " << line.toLocal8Bit().data() << "\n";
|
||||||
return InvalidFile;
|
return InvalidFile;
|
||||||
|
|
@ -238,7 +238,7 @@ namespace vcg
|
||||||
}
|
}
|
||||||
|
|
||||||
sa = line.split(' ');
|
sa = line.split(' ');
|
||||||
if (!sa.size()>=3)
|
if (!(sa.size()>=3))
|
||||||
{
|
{
|
||||||
std::cerr << "Error parsing face " << line.toLocal8Bit().data() << "\n";
|
std::cerr << "Error parsing face " << line.toLocal8Bit().data() << "\n";
|
||||||
return InvalidFile;
|
return InvalidFile;
|
||||||
|
|
|
||||||
|
|
@ -524,7 +524,6 @@ namespace vcg {
|
||||||
locInd[iii]=indexTriangulatedVect[pi+iii];
|
locInd[iii]=indexTriangulatedVect[pi+iii];
|
||||||
ff.v[iii]=indexVVect[ locInd[iii] ];
|
ff.v[iii]=indexVVect[ locInd[iii] ];
|
||||||
ff.n[iii]=indexNVect[ locInd[iii] ];
|
ff.n[iii]=indexNVect[ locInd[iii] ];
|
||||||
// qDebug("ff.n[iii]=indexNVect[ locInd[iii] ]; %i", ff.n[iii]);
|
|
||||||
ff.t[iii]=indexTVect[ locInd[iii] ];
|
ff.t[iii]=indexTVect[ locInd[iii] ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -644,14 +643,11 @@ namespace vcg {
|
||||||
for(int i=0; i<numEdges; ++i)
|
for(int i=0; i<numEdges; ++i)
|
||||||
{
|
{
|
||||||
ObjEdge & e = ev[i];
|
ObjEdge & e = ev[i];
|
||||||
EdgeType & edge = m.edge[i];
|
|
||||||
|
|
||||||
assert(e.v0 >= 0 && size_t(e.v0) < m.vert.size() &&
|
assert(e.v0 >= 0 && size_t(e.v0) < m.vert.size() &&
|
||||||
e.v1 >= 0 && size_t(e.v1) < m.vert.size());
|
e.v1 >= 0 && size_t(e.v1) < m.vert.size());
|
||||||
// TODO add proper handling of bad indices
|
// TODO add proper handling of bad indices
|
||||||
|
m.edge[i].V(0) = &(m.vert[e.v0]);
|
||||||
edge.V(0) = &(m.vert[e.v0]);
|
m.edge[i].V(1) = &(m.vert[e.v1]);
|
||||||
edge.V(1) = &(m.vert[e.v1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
||||||
|
|
@ -665,6 +661,8 @@ namespace vcg {
|
||||||
|
|
||||||
for(unsigned int j=0;j<indexedFaces[i].v.size();++j)
|
for(unsigned int j=0;j<indexedFaces[i].v.size();++j)
|
||||||
{
|
{
|
||||||
|
int vertInd = indexedFaces[i].v[j];
|
||||||
|
assert(vertInd >=0 && vertInd < m.vn);
|
||||||
m.face[i].V(j) = &(m.vert[indexedFaces[i].v[j]]);
|
m.face[i].V(j) = &(m.vert[indexedFaces[i].v[j]]);
|
||||||
|
|
||||||
if (((oi.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) != 0) && (HasPerWedgeTexCoord(m)))
|
if (((oi.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) != 0) && (HasPerWedgeTexCoord(m)))
|
||||||
|
|
@ -687,7 +685,6 @@ namespace vcg {
|
||||||
|
|
||||||
if ( oi.mask & vcg::tri::io::Mask::IOM_VERTNORMAL )
|
if ( oi.mask & vcg::tri::io::Mask::IOM_VERTNORMAL )
|
||||||
{
|
{
|
||||||
// qDebug("XXXXXX %i",indexedFaces[i].n[j]);
|
|
||||||
m.face[i].V(j)->N().Import(normals[indexedFaces[i].n[j]]);
|
m.face[i].V(j)->N().Import(normals[indexedFaces[i].n[j]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -734,8 +731,8 @@ namespace vcg {
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Read the next valid line and parses it into "tokens", allowing
|
* Read the next valid line and parses it into "tokens" (e.g. groups like 234/234/234), allowing
|
||||||
* the tokens to be read one at a time.
|
* the tokens to be read one at a time. It read multiple lines concatenating them if they end with '\'
|
||||||
* \param stream The object providing the input stream
|
* \param stream The object providing the input stream
|
||||||
* \param tokens The "tokens" in the next line
|
* \param tokens The "tokens" in the next line
|
||||||
*/
|
*/
|
||||||
|
|
@ -746,6 +743,16 @@ namespace vcg {
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
std::getline(stream, line);
|
std::getline(stream, line);
|
||||||
|
// We have to manage backspace terminated lines,
|
||||||
|
// joining them together before parsing them
|
||||||
|
if(!line.empty() && line.back()==13) line.pop_back();
|
||||||
|
while(!line.empty() && line.back()=='\\') {
|
||||||
|
std::string tmpLine;
|
||||||
|
std::getline(stream, tmpLine);
|
||||||
|
if(tmpLine.back()==13) line.pop_back();
|
||||||
|
line.pop_back();
|
||||||
|
line.append(tmpLine);
|
||||||
|
}
|
||||||
const size_t len = line.length();
|
const size_t len = line.length();
|
||||||
if((len > 0) && colVec && line[0] == '#')
|
if((len > 0) && colVec && line[0] == '#')
|
||||||
{
|
{
|
||||||
|
|
@ -798,6 +805,12 @@ namespace vcg {
|
||||||
while (from<length);
|
while (from<length);
|
||||||
} // end TokenizeNextLine
|
} // end TokenizeNextLine
|
||||||
|
|
||||||
|
// This function takes a token and, according to the mask, it returns the indexes of the involved vertex, normal and texcoord indexes.
|
||||||
|
// Example. if the obj file has vertex texcoord (e.g. lines 'vt 0.444 0.5555')
|
||||||
|
// when parsing a line like
|
||||||
|
// f 46/303 619/325 624/326 623/327
|
||||||
|
// if in the mask you have specified to read wedge tex coord
|
||||||
|
// for the first token it will return inside vId and tId the corresponding indexes 46 and 303 )
|
||||||
inline static void SplitToken(const std::string & token, int & vId, int & nId, int & tId, int mask)
|
inline static void SplitToken(const std::string & token, int & vId, int & nId, int & tId, int mask)
|
||||||
{
|
{
|
||||||
static const char delimiter = '/';
|
static const char delimiter = '/';
|
||||||
|
|
@ -816,141 +829,8 @@ namespace vcg {
|
||||||
if (hasTexcoord) tId = atoi(token.substr(firstSep + 1, secondSep - firstSep - 1).c_str()) - 1;
|
if (hasTexcoord) tId = atoi(token.substr(firstSep + 1, secondSep - firstSep - 1).c_str()) - 1;
|
||||||
if (hasNormal)
|
if (hasNormal)
|
||||||
nId = atoi(token.substr(secondSep + 1).c_str()) - 1;
|
nId = atoi(token.substr(secondSep + 1).c_str()) - 1;
|
||||||
// qDebug("%s -> %i %i %i",token.c_str(),vId,nId,tId);
|
|
||||||
/*
|
|
||||||
const std::string vStr = (hasPosition) ? (token.substr(0, firstSep)) : ("0");
|
|
||||||
const std::string tStr = (hasTexcoord) ? (token.substr(firstSep + 1, secondSep - firstSep - 1)) : ("0");
|
|
||||||
const std::string nStr = (hasNormal) ? (token.substr(secondSep + 1)) : ("0");
|
|
||||||
|
|
||||||
if (!vStr.empty()) vId = atoi(vStr.c_str()) - 1;
|
|
||||||
if (!tStr.empty()) tId = atoi(tStr.c_str()) - 1;
|
|
||||||
if (!nStr.empty()) nId = atoi(nStr.c_str()) - 1;
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
// This function takes a token and, according to the mask, it returns the indexes of the involved vertex, normal and texcoord indexes.
|
|
||||||
// Example. if the obj file has vertex texcoord (e.g. lines 'vt 0.444 0.5555')
|
|
||||||
// when parsing a line like
|
|
||||||
// f 46/303 619/325 624/326 623/327
|
|
||||||
// if in the mask you have specified to read wedge tex coord
|
|
||||||
// for the first token it will return inside vId and tId the corresponding indexes 46 and 303 )
|
|
||||||
inline static void SplitToken(std::string token, int &vId, int &nId, int &tId, int mask)
|
|
||||||
{
|
|
||||||
std::string vertex;
|
|
||||||
std::string texcoord;
|
|
||||||
std::string normal;
|
|
||||||
|
|
||||||
if( ( mask & Mask::IOM_WEDGTEXCOORD ) && (mask & Mask::IOM_WEDGNORMAL) ) SplitVVTVNToken(token, vertex, texcoord, normal);
|
|
||||||
if(!( mask & Mask::IOM_WEDGTEXCOORD ) && (mask & Mask::IOM_WEDGNORMAL) ) SplitVVNToken(token, vertex, normal);
|
|
||||||
if( ( mask & Mask::IOM_WEDGTEXCOORD ) &&!(mask & Mask::IOM_WEDGNORMAL) ) SplitVVTToken(token, vertex, texcoord);
|
|
||||||
if(!( mask & Mask::IOM_WEDGTEXCOORD ) &&!(mask & Mask::IOM_WEDGNORMAL) ) SplitVToken(token, vertex);
|
|
||||||
|
|
||||||
vId = atoi(vertex.c_str()) - 1;
|
|
||||||
if(mask & Mask::IOM_WEDGTEXCOORD) tId = atoi(texcoord.c_str()) - 1;
|
|
||||||
if(mask & Mask::IOM_WEDGNORMAL) nId = atoi(normal.c_str()) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static void SplitVToken(std::string token, std::string &vertex)
|
|
||||||
{
|
|
||||||
vertex = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static void SplitVVTToken(std::string token, std::string &vertex, std::string &texcoord)
|
|
||||||
{
|
|
||||||
vertex.clear();
|
|
||||||
texcoord.clear();
|
|
||||||
|
|
||||||
size_t from = 0;
|
|
||||||
size_t to = 0;
|
|
||||||
size_t length = token.size();
|
|
||||||
|
|
||||||
if(from!=length)
|
|
||||||
{
|
|
||||||
char c = token[from];
|
|
||||||
vertex.push_back(c);
|
|
||||||
|
|
||||||
to = from+1;
|
|
||||||
while (to<length && ((c = token[to]) !='/'))
|
|
||||||
{
|
|
||||||
vertex.push_back(c);
|
|
||||||
++to;
|
|
||||||
}
|
|
||||||
++to;
|
|
||||||
while (to<length && ((c = token[to]) !=' '))
|
|
||||||
{
|
|
||||||
texcoord.push_back(c);
|
|
||||||
++to;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // end of SplitVVTToken
|
|
||||||
|
|
||||||
inline static void SplitVVNToken(std::string token, std::string &vertex, std::string &normal)
|
|
||||||
{
|
|
||||||
vertex.clear();
|
|
||||||
normal.clear();
|
|
||||||
|
|
||||||
size_t from = 0;
|
|
||||||
size_t to = 0;
|
|
||||||
size_t length = token.size();
|
|
||||||
|
|
||||||
if(from!=length)
|
|
||||||
{
|
|
||||||
char c = token[from];
|
|
||||||
vertex.push_back(c);
|
|
||||||
|
|
||||||
to = from+1;
|
|
||||||
while (to!=length && ((c = token[to]) !='/'))
|
|
||||||
{
|
|
||||||
vertex.push_back(c);
|
|
||||||
++to;
|
|
||||||
}
|
|
||||||
++to;
|
|
||||||
++to; // should be the second '/'
|
|
||||||
while (to!=length && ((c = token[to]) !=' '))
|
|
||||||
{
|
|
||||||
normal.push_back(c);
|
|
||||||
++to;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // end of SplitVVNToken
|
|
||||||
|
|
||||||
inline static void SplitVVTVNToken(std::string token, std::string &vertex, std::string &texcoord, std::string &normal)
|
|
||||||
{
|
|
||||||
vertex.clear();
|
|
||||||
texcoord.clear();
|
|
||||||
normal.clear();
|
|
||||||
|
|
||||||
size_t from = 0;
|
|
||||||
size_t to = 0;
|
|
||||||
size_t length = token.size();
|
|
||||||
|
|
||||||
if(from!=length)
|
|
||||||
{
|
|
||||||
char c = token[from];
|
|
||||||
vertex.push_back(c);
|
|
||||||
|
|
||||||
to = from+1;
|
|
||||||
while (to!=length && ((c = token[to]) !='/'))
|
|
||||||
{
|
|
||||||
vertex.push_back(c);
|
|
||||||
++to;
|
|
||||||
}
|
|
||||||
++to;
|
|
||||||
while (to!=length && ((c = token[to]) !='/'))
|
|
||||||
{
|
|
||||||
texcoord.push_back(c);
|
|
||||||
++to;
|
|
||||||
}
|
|
||||||
++to;
|
|
||||||
while (to!=length && ((c = token[to]) !=' '))
|
|
||||||
{
|
|
||||||
normal.push_back(c);
|
|
||||||
++to;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // end of SplitVVTVNToken
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Retrieves infos about kind of data stored into the file and fills a mask appropriately
|
* Retrieves infos about kind of data stored into the file and fills a mask appropriately
|
||||||
|
|
|
||||||
|
|
@ -29,19 +29,19 @@
|
||||||
#include <wrap/io_trimesh/io_fan_tessellator.h>
|
#include <wrap/io_trimesh/io_fan_tessellator.h>
|
||||||
|
|
||||||
namespace vcg {
|
namespace vcg {
|
||||||
namespace tri {
|
namespace tri {
|
||||||
namespace io {
|
namespace io {
|
||||||
|
|
||||||
// /** \addtogroup */
|
// /** \addtogroup */
|
||||||
// /* @{ */
|
// /* @{ */
|
||||||
/**
|
/**
|
||||||
This class encapsulate a filter for importing OFF meshes.
|
This class encapsulate a filter for importing OFF meshes.
|
||||||
A basic description of the OFF file format can be found at http://www.geomview.org/docs/html/geomview_41.html
|
A basic description of the OFF file format can be found at http://www.geomview.org/docs/html/geomview_41.html
|
||||||
*/
|
*/
|
||||||
template<class MESH_TYPE>
|
template<class MESH_TYPE>
|
||||||
class ImporterOFF
|
class ImporterOFF
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef typename MESH_TYPE::VertexType VertexType;
|
typedef typename MESH_TYPE::VertexType VertexType;
|
||||||
typedef typename MESH_TYPE::VertexIterator VertexIterator;
|
typedef typename MESH_TYPE::VertexIterator VertexIterator;
|
||||||
|
|
@ -53,9 +53,11 @@ public:
|
||||||
typedef typename MESH_TYPE::ScalarType ScalarType;
|
typedef typename MESH_TYPE::ScalarType ScalarType;
|
||||||
|
|
||||||
// OFF codes
|
// OFF codes
|
||||||
enum OFFCodes {NoError=0, CantOpen, InvalidFile,
|
enum OFFCodes {
|
||||||
|
NoError = 0, CantOpen, InvalidFile,
|
||||||
InvalidFile_MissingOFF,
|
InvalidFile_MissingOFF,
|
||||||
UnsupportedFormat, ErrorNotTriangularFace,ErrorHighDimension,ErrorDegenerateFace};
|
UnsupportedFormat, ErrorNotTriangularFace, ErrorHighDimension, ErrorDegenerateFace
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Standard call for knowing the meaning of an error code
|
* Standard call for knowing the meaning of an error code
|
||||||
|
|
@ -70,7 +72,7 @@ public:
|
||||||
"Invalid file: OFF file should have in the first line the OFF keyword as a first token",
|
"Invalid file: OFF file should have in the first line the OFF keyword as a first token",
|
||||||
"Unsupported format", "Face with more than 3 vertices","File with high dimensional vertexes are not supported", "Error Degenerate Face with less than 3 vertices" };
|
"Unsupported format", "Face with more than 3 vertices","File with high dimensional vertexes are not supported", "Error Degenerate Face with less than 3 vertices" };
|
||||||
|
|
||||||
if(message_code>6 || message_code<0)
|
if (message_code > 6 || message_code < 0)
|
||||||
return "Unknown error";
|
return "Unknown error";
|
||||||
else
|
else
|
||||||
return error_msg[message_code];
|
return error_msg[message_code];
|
||||||
|
|
@ -87,24 +89,24 @@ public:
|
||||||
{
|
{
|
||||||
// To obtain the loading mask all the file must be parsed
|
// To obtain the loading mask all the file must be parsed
|
||||||
// to distinguish between per-vertex and per-face color attribute.
|
// to distinguish between per-vertex and per-face color attribute.
|
||||||
loadmask=0;
|
loadmask = 0;
|
||||||
MESH_TYPE dummyMesh;
|
MESH_TYPE dummyMesh;
|
||||||
return (Open(dummyMesh, filename, loadmask)==NoError);
|
return (Open(dummyMesh, filename, loadmask) == NoError);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Open(MESH_TYPE &mesh, const char *filename,CallBackPos *cb=0)
|
static int Open(MESH_TYPE &mesh, const char *filename, CallBackPos *cb = 0)
|
||||||
{
|
{
|
||||||
int loadmask;
|
int loadmask;
|
||||||
return Open(mesh,filename,loadmask,cb);
|
return Open(mesh, filename, loadmask, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int OpenMem(MESH_TYPE &mesh, const char *mem, size_t sz, int &loadmask,
|
static int OpenMem(MESH_TYPE &mesh, const char *mem, size_t sz, int &loadmask,
|
||||||
CallBackPos *cb=0)
|
CallBackPos *cb = 0)
|
||||||
{
|
{
|
||||||
std::string str;
|
std::string str;
|
||||||
str.append(mem,sz);
|
str.append(mem, sz);
|
||||||
std::istringstream strm(str);
|
std::istringstream strm(str);
|
||||||
return OpenStream(mesh,strm,loadmask,cb);
|
return OpenStream(mesh, strm, loadmask, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -115,20 +117,20 @@ public:
|
||||||
* \return the operation result
|
* \return the operation result
|
||||||
*/
|
*/
|
||||||
static int Open(MESH_TYPE &mesh, const char *filename, int &loadmask,
|
static int Open(MESH_TYPE &mesh, const char *filename, int &loadmask,
|
||||||
CallBackPos *cb=0)
|
CallBackPos *cb = 0)
|
||||||
{
|
{
|
||||||
std::ifstream stream(filename);
|
std::ifstream stream(filename);
|
||||||
if (stream.fail())
|
if (stream.fail())
|
||||||
return CantOpen;
|
return CantOpen;
|
||||||
return OpenStream(mesh,stream,loadmask,cb);
|
return OpenStream(mesh, stream, loadmask, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int OpenStream(MESH_TYPE &mesh, std::istream &stream, int &loadmask,
|
static int OpenStream(MESH_TYPE &mesh, std::istream &stream, int &loadmask,
|
||||||
CallBackPos *cb=0)
|
CallBackPos *cb = 0)
|
||||||
{
|
{
|
||||||
std::vector< std::string > tokens;
|
std::vector< std::string > tokens;
|
||||||
TokenizeNextLine(stream, tokens);
|
TokenizeNextLine(stream, tokens);
|
||||||
if(tokens.empty()) return InvalidFile_MissingOFF;
|
if (tokens.empty()) return InvalidFile_MissingOFF;
|
||||||
|
|
||||||
bool isNormalDefined = false;
|
bool isNormalDefined = false;
|
||||||
bool isColorDefined = false;
|
bool isColorDefined = false;
|
||||||
|
|
@ -164,21 +166,26 @@ public:
|
||||||
std::string header = tokens[0];
|
std::string header = tokens[0];
|
||||||
if (header.rfind("OFF") != std::basic_string<char>::npos)
|
if (header.rfind("OFF") != std::basic_string<char>::npos)
|
||||||
{ // the OFF string is in the header go on parsing it.
|
{ // the OFF string is in the header go on parsing it.
|
||||||
for (int u = static_cast<int>(header.rfind("OFF")-1); u>=0; u--)
|
for (int u = static_cast<int>(header.rfind("OFF") - 1); u >= 0; u--)
|
||||||
{
|
{
|
||||||
if (header[u] == 'C') isColorDefined = true;
|
if (header[u] == 'C')
|
||||||
else if (header[u] == 'N') isNormalDefined = true;
|
isColorDefined = true;
|
||||||
else if (u>0 && header[u-1] == 'S' && header[u] == 'T') isTexCoordDefined = true;
|
else if (header[u] == 'N')
|
||||||
else if (header[u] == '4') homogeneousComponents = true;
|
isNormalDefined = true;
|
||||||
else if (header[u] == 'n') return ErrorHighDimension;
|
else if (u > 0 && header[u - 1] == 'S' && header[u] == 'T')
|
||||||
|
isTexCoordDefined = true;
|
||||||
|
else if (header[u] == '4')
|
||||||
|
homogeneousComponents = true;
|
||||||
|
else if (header[u] == 'n')
|
||||||
|
return ErrorHighDimension;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else return InvalidFile_MissingOFF;
|
else return InvalidFile_MissingOFF;
|
||||||
|
|
||||||
// If the file is slightly malformed and it has nvert and nface AFTER the OFF string instead of in the next line
|
// If the file is slightly malformed and it has nvert and nface AFTER the OFF string instead of in the next line
|
||||||
// we manage it here...
|
// we manage it here...
|
||||||
if(tokens.size()==1) TokenizeNextLine(stream, tokens);
|
if (tokens.size() == 1) TokenizeNextLine(stream, tokens);
|
||||||
else tokens.erase(tokens.begin(),tokens.begin()+1);
|
else tokens.erase(tokens.begin(), tokens.begin() + 1);
|
||||||
|
|
||||||
// Update loading mask
|
// Update loading mask
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
|
|
@ -187,7 +194,7 @@ public:
|
||||||
|
|
||||||
if (isNormalDefined) loadmask |= Mask::IOM_VERTNORMAL;
|
if (isNormalDefined) loadmask |= Mask::IOM_VERTNORMAL;
|
||||||
if (isTexCoordDefined) loadmask |= Mask::IOM_VERTTEXCOORD;
|
if (isTexCoordDefined) loadmask |= Mask::IOM_VERTTEXCOORD;
|
||||||
if (isColorDefined) { loadmask |= Mask::IOM_VERTCOLOR;loadmask |= Mask::IOM_FACECOLOR;}
|
//if (isColorDefined) { loadmask |= Mask::IOM_VERTCOLOR;loadmask |= Mask::IOM_FACECOLOR;}
|
||||||
|
|
||||||
|
|
||||||
//if(onlyMaskFlag) return NoError;
|
//if(onlyMaskFlag) return NoError;
|
||||||
|
|
@ -196,7 +203,7 @@ public:
|
||||||
mesh.Clear();
|
mesh.Clear();
|
||||||
|
|
||||||
// check on next 2 lines to detect corrupted files
|
// check on next 2 lines to detect corrupted files
|
||||||
if(tokens.size() < 3)
|
if (tokens.size() < 3)
|
||||||
return InvalidFile;
|
return InvalidFile;
|
||||||
|
|
||||||
unsigned int nVertices, nFaces, nEdges;
|
unsigned int nVertices, nFaces, nEdges;
|
||||||
|
|
@ -218,13 +225,13 @@ public:
|
||||||
TokenizeNextLine(stream, tokens);
|
TokenizeNextLine(stream, tokens);
|
||||||
size_t k = 0; // next token to read
|
size_t k = 0; // next token to read
|
||||||
|
|
||||||
for (unsigned int i=0; i<nVertices; i++, v_iter++)
|
for (unsigned int i = 0; i < nVertices; i++, v_iter++)
|
||||||
{
|
{
|
||||||
if (cb && (i%1000)==0)
|
if (cb && (i % 1000) == 0)
|
||||||
cb(i*50/nVertices, "Vertex Loading");
|
cb(i * 50 / nVertices, "Vertex Loading");
|
||||||
|
|
||||||
// Read 3 vertex coordinates
|
// Read 3 vertex coordinates
|
||||||
for (unsigned int j=0; j<3; j++)
|
for (unsigned int j = 0; j < 3; j++)
|
||||||
{
|
{
|
||||||
// Go to next line when needed
|
// Go to next line when needed
|
||||||
if (k == tokens.size()) // if EOL
|
if (k == tokens.size()) // if EOL
|
||||||
|
|
@ -236,14 +243,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read vertex coordinate
|
// Read vertex coordinate
|
||||||
(*v_iter).P()[j] = (ScalarType) atof(tokens[k].c_str());
|
(*v_iter).P()[j] = (ScalarType)atof(tokens[k].c_str());
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNormalDefined)
|
if (isNormalDefined)
|
||||||
{
|
{
|
||||||
// Read 3 normal coordinates
|
// Read 3 normal coordinates
|
||||||
for (unsigned int j=0; j<3; j++)
|
for (unsigned int j = 0; j < 3; j++)
|
||||||
{
|
{
|
||||||
// Go to next line when needed
|
// Go to next line when needed
|
||||||
if (k == tokens.size()) // if EOL
|
if (k == tokens.size()) // if EOL
|
||||||
|
|
@ -255,7 +262,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read normal coordinate
|
// Read normal coordinate
|
||||||
(*v_iter).N()[j] = (ScalarType) atof(tokens[k].c_str());
|
(*v_iter).N()[j] = (ScalarType)atof(tokens[k].c_str());
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -297,9 +304,9 @@ public:
|
||||||
unsigned char r =
|
unsigned char r =
|
||||||
static_cast<unsigned char>(atoi(tokens[k].c_str()));
|
static_cast<unsigned char>(atoi(tokens[k].c_str()));
|
||||||
unsigned char g =
|
unsigned char g =
|
||||||
static_cast<unsigned char>(atoi(tokens[k+1].c_str()));
|
static_cast<unsigned char>(atoi(tokens[k + 1].c_str()));
|
||||||
unsigned char b =
|
unsigned char b =
|
||||||
static_cast<unsigned char>(atoi(tokens[k+2].c_str()));
|
static_cast<unsigned char>(atoi(tokens[k + 2].c_str()));
|
||||||
|
|
||||||
vcg::Color4b color(r, g, b, 255);
|
vcg::Color4b color(r, g, b, 255);
|
||||||
(*v_iter).C().Import(color);
|
(*v_iter).C().Import(color);
|
||||||
|
|
@ -308,8 +315,8 @@ public:
|
||||||
{
|
{
|
||||||
// floats
|
// floats
|
||||||
float r = static_cast<float>(atof(tokens[k].c_str()));
|
float r = static_cast<float>(atof(tokens[k].c_str()));
|
||||||
float g = static_cast<float>(atof(tokens[k+1].c_str()));
|
float g = static_cast<float>(atof(tokens[k + 1].c_str()));
|
||||||
float b = static_cast<float>(atof(tokens[k+2].c_str()));
|
float b = static_cast<float>(atof(tokens[k + 2].c_str()));
|
||||||
|
|
||||||
vcg::Color4f color(r, g, b, 1.0);
|
vcg::Color4f color(r, g, b, 1.0);
|
||||||
(*v_iter).C().Import(color);
|
(*v_iter).C().Import(color);
|
||||||
|
|
@ -324,11 +331,11 @@ public:
|
||||||
unsigned char r =
|
unsigned char r =
|
||||||
static_cast<unsigned char>(atoi(tokens[k].c_str()));
|
static_cast<unsigned char>(atoi(tokens[k].c_str()));
|
||||||
unsigned char g =
|
unsigned char g =
|
||||||
static_cast<unsigned char>(atoi(tokens[k+1].c_str()));
|
static_cast<unsigned char>(atoi(tokens[k + 1].c_str()));
|
||||||
unsigned char b =
|
unsigned char b =
|
||||||
static_cast<unsigned char>(atoi(tokens[k+2].c_str()));
|
static_cast<unsigned char>(atoi(tokens[k + 2].c_str()));
|
||||||
unsigned char a =
|
unsigned char a =
|
||||||
static_cast<unsigned char>(atoi(tokens[k+3].c_str()));
|
static_cast<unsigned char>(atoi(tokens[k + 3].c_str()));
|
||||||
|
|
||||||
Color4b color(r, g, b, a);
|
Color4b color(r, g, b, a);
|
||||||
(*v_iter).C().Import(color);
|
(*v_iter).C().Import(color);
|
||||||
|
|
@ -337,9 +344,9 @@ public:
|
||||||
{
|
{
|
||||||
// floats
|
// floats
|
||||||
float r = static_cast<float>(atof(tokens[k].c_str()));
|
float r = static_cast<float>(atof(tokens[k].c_str()));
|
||||||
float g = static_cast<float>(atof(tokens[k+1].c_str()));
|
float g = static_cast<float>(atof(tokens[k + 1].c_str()));
|
||||||
float b = static_cast<float>(atof(tokens[k+2].c_str()));
|
float b = static_cast<float>(atof(tokens[k + 2].c_str()));
|
||||||
float a = static_cast<float>(atof(tokens[k+3].c_str()));
|
float a = static_cast<float>(atof(tokens[k + 3].c_str()));
|
||||||
|
|
||||||
vcg::Color4f color(r, g, b, a);
|
vcg::Color4f color(r, g, b, a);
|
||||||
(*v_iter).C().Import(color);
|
(*v_iter).C().Import(color);
|
||||||
|
|
@ -352,7 +359,7 @@ public:
|
||||||
|
|
||||||
if (isTexCoordDefined)
|
if (isTexCoordDefined)
|
||||||
{
|
{
|
||||||
for (unsigned int j=0; j<2; j++)
|
for (unsigned int j = 0; j < 2; j++)
|
||||||
{
|
{
|
||||||
// Go to next line when needed
|
// Go to next line when needed
|
||||||
if (k == tokens.size()) // if EOL
|
if (k == tokens.size()) // if EOL
|
||||||
|
|
@ -377,16 +384,16 @@ public:
|
||||||
|
|
||||||
// READ FACES
|
// READ FACES
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
if(FaceType::HasPolyInfo())
|
if (FaceType::HasPolyInfo())
|
||||||
{
|
{
|
||||||
for (unsigned int f=0; f < nFaces; f++)
|
for (unsigned int f = 0; f < nFaces; f++)
|
||||||
{
|
{
|
||||||
if(cb && (f%1000)==0) cb(50+f*50/nFaces,"Face Loading");
|
if (cb && (f % 1000) == 0) cb(50 + f * 50 / nFaces, "Face Loading");
|
||||||
TokenizeNextLine(stream, tokens);
|
TokenizeNextLine(stream, tokens);
|
||||||
int vert_per_face = atoi(tokens[0].c_str());
|
int vert_per_face = atoi(tokens[0].c_str());
|
||||||
std::vector<int> vInd(vert_per_face);
|
std::vector<int> vInd(vert_per_face);
|
||||||
k = 1;
|
k = 1;
|
||||||
for (int j=0; j < vert_per_face; j++)
|
for (int j = 0; j < vert_per_face; j++)
|
||||||
{
|
{
|
||||||
if (k == tokens.size()) // if EOL // Go to next line when needed
|
if (k == tokens.size()) // if EOL // Go to next line when needed
|
||||||
{
|
{
|
||||||
|
|
@ -397,36 +404,36 @@ public:
|
||||||
vInd[j] = atoi(tokens[k].c_str());
|
vInd[j] = atoi(tokens[k].c_str());
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
if(vert_per_face==3)
|
if (vert_per_face == 3)
|
||||||
Allocator<MESH_TYPE>::AddFace(mesh, &mesh.vert[ vInd[0] ], &mesh.vert[ vInd[1] ], &mesh.vert[ vInd[2] ]);
|
Allocator<MESH_TYPE>::AddFace(mesh, &mesh.vert[vInd[0]], &mesh.vert[vInd[1]], &mesh.vert[vInd[2]]);
|
||||||
|
|
||||||
if(vert_per_face==4)
|
if (vert_per_face == 4)
|
||||||
Allocator<MESH_TYPE>::AddQuadFace(mesh, &mesh.vert[ vInd[0] ], &mesh.vert[ vInd[1] ], &mesh.vert[ vInd[2] ],&mesh.vert[ vInd[3] ]);
|
Allocator<MESH_TYPE>::AddQuadFace(mesh, &mesh.vert[vInd[0]], &mesh.vert[vInd[1]], &mesh.vert[vInd[2]], &mesh.vert[vInd[3]]);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // Standard Triangular Mesh Loading
|
else // Standard Triangular Mesh Loading
|
||||||
{
|
{
|
||||||
Allocator<MESH_TYPE>::AddFaces(mesh, nFaces);
|
Allocator<MESH_TYPE>::AddFaces(mesh, nFaces);
|
||||||
unsigned int f0=0;
|
unsigned int f0 = 0;
|
||||||
|
|
||||||
|
|
||||||
// Initial call to the QuadTriangulate with an empty vector to just reset the static set of existing diagonals
|
// Initial call to the QuadTriangulate with an empty vector to just reset the static set of existing diagonals
|
||||||
std::vector<VertexPointer> qtmp;
|
std::vector<VertexPointer> qtmp;
|
||||||
BitQuad<MESH_TYPE>::QuadTriangulate(qtmp);
|
BitQuad<MESH_TYPE>::QuadTriangulate(qtmp);
|
||||||
|
|
||||||
for (unsigned int f=0; f < nFaces; f++)
|
for (unsigned int f = 0; f < nFaces; f++)
|
||||||
{
|
{
|
||||||
f0 = f;
|
f0 = f;
|
||||||
if (stream.fail())
|
if (stream.fail())
|
||||||
return InvalidFile;
|
return InvalidFile;
|
||||||
|
|
||||||
if(cb && (f%1000)==0)
|
if (cb && (f % 1000) == 0)
|
||||||
cb(50+f*50/nFaces,"Face Loading");
|
cb(50 + f * 50 / nFaces, "Face Loading");
|
||||||
|
|
||||||
TokenizeNextLine(stream, tokens);
|
TokenizeNextLine(stream, tokens);
|
||||||
int vert_per_face = atoi(tokens[0].c_str());
|
int vert_per_face = atoi(tokens[0].c_str());
|
||||||
if(vert_per_face < 3)
|
if (vert_per_face < 3)
|
||||||
return ErrorDegenerateFace;
|
return ErrorDegenerateFace;
|
||||||
k = 1;
|
k = 1;
|
||||||
if (vert_per_face == 3)
|
if (vert_per_face == 3)
|
||||||
|
|
@ -440,19 +447,19 @@ public:
|
||||||
k = 0;
|
k = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh.face[f].V(j) = &(mesh.vert[ atoi(tokens[k].c_str()) ]);
|
mesh.face[f].V(j) = &(mesh.vert[atoi(tokens[k].c_str())]);
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The face must be triangulated
|
// The face must be triangulated
|
||||||
unsigned int trigs = vert_per_face-3; // number of extra faces to add
|
unsigned int trigs = vert_per_face - 3; // number of extra faces to add
|
||||||
nFaces += trigs;
|
nFaces += trigs;
|
||||||
Allocator<MESH_TYPE>::AddFaces(mesh, trigs);
|
Allocator<MESH_TYPE>::AddFaces(mesh, trigs);
|
||||||
std::vector<int> vertIndices(vert_per_face);
|
std::vector<int> vertIndices(vert_per_face);
|
||||||
std::vector<vcg::Point3f > polygonVect(vert_per_face); // vec of polygon loops used for the triangulation of polygonal face
|
std::vector<vcg::Point3f > polygonVect(vert_per_face); // vec of polygon loops used for the triangulation of polygonal face
|
||||||
for (int j=0; j < vert_per_face; j++)
|
for (int j = 0; j < vert_per_face; j++)
|
||||||
{
|
{
|
||||||
if (k == tokens.size()) // if EOL // Go to next line when needed
|
if (k == tokens.size()) // if EOL // Go to next line when needed
|
||||||
{
|
{
|
||||||
|
|
@ -461,27 +468,27 @@ public:
|
||||||
k = 0;
|
k = 0;
|
||||||
}
|
}
|
||||||
vertIndices[j] = atoi(tokens[k].c_str());
|
vertIndices[j] = atoi(tokens[k].c_str());
|
||||||
polygonVect[j].Import<ScalarType> (mesh.vert[ vertIndices[j] ].P());
|
polygonVect[j].Import<ScalarType>(mesh.vert[vertIndices[j]].P());
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
if(vert_per_face==4)
|
if (vert_per_face == 4)
|
||||||
{ // To well triangulate use the bitquad support function that reorders vertex for a simple fan
|
{ // To well triangulate use the bitquad support function that reorders vertex for a simple fan
|
||||||
std::vector<VertexPointer> q(4);
|
std::vector<VertexPointer> q(4);
|
||||||
for(int qqi=0;qqi<4;++qqi)
|
for (int qqi = 0; qqi < 4; ++qqi)
|
||||||
q[qqi]=& mesh.vert[vertIndices[qqi]];
|
q[qqi] = &mesh.vert[vertIndices[qqi]];
|
||||||
BitQuad<MESH_TYPE>::QuadTriangulate(q);
|
BitQuad<MESH_TYPE>::QuadTriangulate(q);
|
||||||
for(int qqi=0;qqi<4;++qqi)
|
for (int qqi = 0; qqi < 4; ++qqi)
|
||||||
vertIndices[qqi] = q[qqi]- & mesh.vert[0];
|
vertIndices[qqi] = q[qqi] - &mesh.vert[0];
|
||||||
// build a two face fan
|
// build a two face fan
|
||||||
for (int j=0; j<2; j++)
|
for (int j = 0; j < 2; j++)
|
||||||
{
|
{
|
||||||
mesh.face[f+j].V(0) = &(mesh.vert[ vertIndices[0 ] ]);
|
mesh.face[f + j].V(0) = &(mesh.vert[vertIndices[0]]);
|
||||||
mesh.face[f+j].V(1) = &(mesh.vert[ vertIndices[1+j] ]);
|
mesh.face[f + j].V(1) = &(mesh.vert[vertIndices[1 + j]]);
|
||||||
mesh.face[f+j].V(2) = &(mesh.vert[ vertIndices[2+j] ]);
|
mesh.face[f + j].V(2) = &(mesh.vert[vertIndices[2 + j]]);
|
||||||
if (tri::HasPerFaceFlags(mesh)) {
|
if (tri::HasPerFaceFlags(mesh)) {
|
||||||
// tag internal polygonal edges as "faux"
|
// tag internal polygonal edges as "faux"
|
||||||
if (j>0) mesh.face[f+j].SetF(0);
|
if (j > 0) mesh.face[f + j].SetF(0);
|
||||||
if (j<vert_per_face-3) mesh.face[f+j].SetF(2);
|
if (j < vert_per_face - 3) mesh.face[f + j].SetF(2);
|
||||||
loadmask |= Mask::IOM_BITPOLYGONAL;
|
loadmask |= Mask::IOM_BITPOLYGONAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -499,100 +506,99 @@ public:
|
||||||
//qDebug("Warning: using fan tessellation for a polygon of %i vertices",vertexesPerFace);
|
//qDebug("Warning: using fan tessellation for a polygon of %i vertices",vertexesPerFace);
|
||||||
tri::io::FanTessellator(loopVect, indexTriangulatedVect);
|
tri::io::FanTessellator(loopVect, indexTriangulatedVect);
|
||||||
#endif
|
#endif
|
||||||
for (size_t j=0; j<indexTriangulatedVect.size(); j+=3)
|
for (size_t j = 0; j < indexTriangulatedVect.size(); j += 3)
|
||||||
{
|
{
|
||||||
mesh.face[f+j/3].V(0) = &(mesh.vert[ vertIndices[ indexTriangulatedVect[j+0] ] ]);
|
mesh.face[f + j / 3].V(0) = &(mesh.vert[vertIndices[indexTriangulatedVect[j + 0]]]);
|
||||||
mesh.face[f+j/3].V(1) = &(mesh.vert[ vertIndices[ indexTriangulatedVect[j+1] ] ]);
|
mesh.face[f + j / 3].V(1) = &(mesh.vert[vertIndices[indexTriangulatedVect[j + 1]]]);
|
||||||
mesh.face[f+j/3].V(2) = &(mesh.vert[ vertIndices[ indexTriangulatedVect[j+2] ] ]);
|
mesh.face[f + j / 3].V(2) = &(mesh.vert[vertIndices[indexTriangulatedVect[j + 2]]]);
|
||||||
// To correctly set Faux edges we have to clear the faux bit for all the edges that do not correspond to consecutive vertices
|
// To correctly set Faux edges we have to clear the faux bit for all the edges that do not correspond to consecutive vertices
|
||||||
// Consecutivity is in the space of the index of the polygon.
|
// Consecutivity is in the space of the index of the polygon.
|
||||||
for(int qq=0;qq<3;++qq)
|
for (int qq = 0; qq < 3; ++qq)
|
||||||
{
|
{
|
||||||
if( (indexTriangulatedVect[j+qq]+1)%vert_per_face == indexTriangulatedVect[j+(qq+1)%3])
|
if ((indexTriangulatedVect[j + qq] + 1) % vert_per_face == indexTriangulatedVect[j + (qq + 1) % 3])
|
||||||
mesh.face[f+j/3].ClearF(qq);
|
mesh.face[f + j / 3].ClearF(qq);
|
||||||
else mesh.face[f+j/3].SetF(qq);
|
else mesh.face[f + j / 3].SetF(qq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f+=trigs;
|
f += trigs;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: It is assumed that colored face takes exactly one text line
|
// NOTE: It is assumed that colored face takes exactly one text line
|
||||||
// (otherwise it is impossible to parse color information since
|
// (otherwise it is impossible to parse color information since
|
||||||
// color components can vary)
|
// color components can vary)
|
||||||
size_t color_elements = tokens.size() - vert_per_face-1;
|
size_t color_elements = tokens.size() - vert_per_face - 1;
|
||||||
isColorDefined |= (color_elements>0);
|
//isColorDefined |= (color_elements>0);
|
||||||
if(isColorDefined) loadmask |= Mask::IOM_FACECOLOR;
|
//if(isColorDefined) loadmask |= Mask::IOM_FACECOLOR;
|
||||||
|
|
||||||
if( (color_elements>0) && tri::HasPerFaceColor(mesh) )
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
// set per-face color attribute
|
|
||||||
if (color_elements > 0)
|
if (color_elements > 0)
|
||||||
|
{
|
||||||
loadmask |= Mask::IOM_FACECOLOR;
|
loadmask |= Mask::IOM_FACECOLOR;
|
||||||
|
|
||||||
|
if (tri::HasPerFaceColor(mesh))
|
||||||
|
{
|
||||||
switch (color_elements)
|
switch (color_elements)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
for ( ; f0<=f; f0++)
|
for (; f0 <= f; f0++)
|
||||||
mesh.face[f0].C().Import(vcg::Color4f(.666f, .666f, .666f, .666f));
|
mesh.face[f0].C().Import(vcg::Color4f(.666f, .666f, .666f, .666f));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
for ( ; f0<=f; f0++)
|
for (; f0 <= f; f0++)
|
||||||
mesh.face[f0].C().Import( ColorMap( atoi(tokens[vert_per_face+1].c_str()) ) );
|
mesh.face[f0].C().Import(ColorMap(atoi(tokens[vert_per_face + 1].c_str())));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 3:
|
case 3:
|
||||||
{
|
{
|
||||||
if (tokens[vert_per_face+1].find('.')==std::string::npos) // if there is a float there is a dot
|
if (tokens[vert_per_face + 1].find('.') == std::string::npos) // if there is a float there is a dot
|
||||||
{
|
{
|
||||||
Color4b cc(Color4b::White);
|
Color4b cc(Color4b::White);
|
||||||
cc[0] = (unsigned char)atoi( tokens[vert_per_face+1].c_str() );
|
cc[0] = (unsigned char)atoi(tokens[vert_per_face + 1].c_str());
|
||||||
cc[1] = (unsigned char)atoi( tokens[vert_per_face+2].c_str() );
|
cc[1] = (unsigned char)atoi(tokens[vert_per_face + 2].c_str());
|
||||||
cc[2] = (unsigned char)atoi( tokens[vert_per_face+3].c_str() );
|
cc[2] = (unsigned char)atoi(tokens[vert_per_face + 3].c_str());
|
||||||
for ( ; f0<=f; f0++)
|
for (; f0 <= f; f0++)
|
||||||
mesh.face[f0].C()=cc;
|
mesh.face[f0].C() = cc;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float color[3];
|
float color[3];
|
||||||
color[0] = (float) atof( tokens[vert_per_face+1].c_str() );
|
color[0] = (float)atof(tokens[vert_per_face + 1].c_str());
|
||||||
color[1] = (float) atof( tokens[vert_per_face+2].c_str() );
|
color[1] = (float)atof(tokens[vert_per_face + 2].c_str());
|
||||||
color[2] = (float) atof( tokens[vert_per_face+3].c_str() );
|
color[2] = (float)atof(tokens[vert_per_face + 3].c_str());
|
||||||
for ( ; f0<=f; f0++)
|
for (; f0 <= f; f0++)
|
||||||
mesh.face[f0].C().Import(vcg::Color4f(color[0], color[1], color[2], 1.0f));
|
mesh.face[f0].C().Import(vcg::Color4f(color[0], color[1], color[2], 1.0f));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 4:
|
case 4:
|
||||||
{
|
{
|
||||||
if (tokens[vert_per_face+1].find('.')==std::string::npos) // if it is a float there is a dot
|
if (tokens[vert_per_face + 1].find('.') == std::string::npos) // if it is a float there is a dot
|
||||||
{
|
{
|
||||||
Color4b cc;
|
Color4b cc;
|
||||||
cc[0] = (unsigned char) atoi(tokens[vert_per_face+1].c_str());
|
cc[0] = (unsigned char)atoi(tokens[vert_per_face + 1].c_str());
|
||||||
cc[1] = (unsigned char) atoi(tokens[vert_per_face+2].c_str());
|
cc[1] = (unsigned char)atoi(tokens[vert_per_face + 2].c_str());
|
||||||
cc[2] = (unsigned char) atoi(tokens[vert_per_face+3].c_str());
|
cc[2] = (unsigned char)atoi(tokens[vert_per_face + 3].c_str());
|
||||||
cc[3] = (unsigned char) atoi(tokens[vert_per_face+4].c_str());
|
cc[3] = (unsigned char)atoi(tokens[vert_per_face + 4].c_str());
|
||||||
for ( ; f0<=f; f0++)
|
for (; f0 <= f; f0++)
|
||||||
mesh.face[f0].C()=cc;
|
mesh.face[f0].C() = cc;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float color[4];
|
float color[4];
|
||||||
color[0] = float( atof(tokens[vert_per_face+1].c_str()) );
|
color[0] = float(atof(tokens[vert_per_face + 1].c_str()));
|
||||||
color[1] = float( atof(tokens[vert_per_face+2].c_str()) );
|
color[1] = float(atof(tokens[vert_per_face + 2].c_str()));
|
||||||
color[2] = float( atof(tokens[vert_per_face+3].c_str()) );
|
color[2] = float(atof(tokens[vert_per_face + 3].c_str()));
|
||||||
color[3] = float( atof(tokens[vert_per_face+4].c_str()) );
|
color[3] = float(atof(tokens[vert_per_face + 4].c_str()));
|
||||||
for ( ; f0<=f; f0++)
|
for (; f0 <= f; f0++)
|
||||||
mesh.face[f0].C().Import(vcg::Color4f(color[0], color[1], color[2], color[3]));
|
mesh.face[f0].C().Import(vcg::Color4f(color[0], color[1], color[2], color[3]));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} //end switch
|
} //end switch
|
||||||
|
}
|
||||||
} // end if (isColorDefined)
|
} // end if (isColorDefined)
|
||||||
} // end of for f=...
|
} // end of for f=...
|
||||||
}
|
}
|
||||||
|
|
@ -600,7 +606,7 @@ public:
|
||||||
|
|
||||||
} // end Open
|
} // end Open
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Read the next valid line and parses it into "tokens", allowing the tokens to be read one at a time.
|
* Read the next valid line and parses it into "tokens", allowing the tokens to be read one at a time.
|
||||||
|
|
@ -612,7 +618,7 @@ protected:
|
||||||
std::string line;
|
std::string line;
|
||||||
do
|
do
|
||||||
std::getline(stream, line, '\n');
|
std::getline(stream, line, '\n');
|
||||||
while ((line[0] == '#' || line.length()==0 || line[0]=='\r' ) && (!stream.eof()));
|
while ((line[0] == '#' || line.length() == 0 || line[0] == '\r') && (!stream.eof()));
|
||||||
|
|
||||||
size_t from = 0;
|
size_t from = 0;
|
||||||
size_t to = 0;
|
size_t to = 0;
|
||||||
|
|
@ -620,18 +626,17 @@ protected:
|
||||||
tokens.clear();
|
tokens.clear();
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
while (from!=length && (line[from]==' ' || line[from] == '\t' || line[from] == '\r'))
|
while (from != length && (line[from] == ' ' || line[from] == '\t' || line[from] == '\r'))
|
||||||
from++;
|
from++;
|
||||||
if(from!=length)
|
if (from != length)
|
||||||
{
|
{
|
||||||
to = from+1;
|
to = from + 1;
|
||||||
while ( to!=length && (((line[to]!=' ') && (line[to] != '\t')) || (line[to] == '\r')))
|
while (to != length && (((line[to] != ' ') && (line[to] != '\t')) || (line[to] == '\r')))
|
||||||
to++;
|
to++;
|
||||||
tokens.push_back(line.substr(from, to-from).c_str());
|
tokens.push_back(line.substr(from, to - from).c_str());
|
||||||
from = to;
|
from = to;
|
||||||
}
|
}
|
||||||
}
|
} while (from < length);
|
||||||
while (from<length);
|
|
||||||
} // end Tokenize
|
} // end Tokenize
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -794,10 +799,10 @@ protected:
|
||||||
};
|
};
|
||||||
return Color4f(colorMap[i][0], colorMap[i][1], colorMap[i][2], colorMap[i][3]);
|
return Color4f(colorMap[i][0], colorMap[i][1], colorMap[i][2], colorMap[i][3]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// /*! @} */
|
// /*! @} */
|
||||||
} //namespace io
|
} //namespace io
|
||||||
}//namespace tri
|
}//namespace tri
|
||||||
} // namespace vcg
|
} // namespace vcg
|
||||||
|
|
||||||
#endif //__VCGLIB_IMPORT_OFF
|
#endif //__VCGLIB_IMPORT_OFF
|
||||||
|
|
|
||||||
|
|
@ -469,12 +469,14 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi )
|
||||||
{
|
{
|
||||||
pf.AddToRead(VertDesc(6));
|
pf.AddToRead(VertDesc(6));
|
||||||
pf.AddToRead(VertDesc(7));
|
pf.AddToRead(VertDesc(7));
|
||||||
|
pf.AddToRead(VertDesc(8));
|
||||||
pi.mask |= Mask::IOM_VERTCOLOR;
|
pi.mask |= Mask::IOM_VERTCOLOR;
|
||||||
}
|
}
|
||||||
if( pf.AddToRead(VertDesc(9))!=-1 )
|
if( pf.AddToRead(VertDesc(9))!=-1 )
|
||||||
{
|
{
|
||||||
pf.AddToRead(VertDesc(10));
|
pf.AddToRead(VertDesc(10));
|
||||||
pf.AddToRead(VertDesc(11));
|
pf.AddToRead(VertDesc(11));
|
||||||
|
pf.AddToRead(VertDesc(12));
|
||||||
pi.mask |= Mask::IOM_VERTCOLOR;
|
pi.mask |= Mask::IOM_VERTCOLOR;
|
||||||
}
|
}
|
||||||
if( pf.AddToRead(VertDesc(21))!=-1 )
|
if( pf.AddToRead(VertDesc(21))!=-1 )
|
||||||
|
|
@ -518,6 +520,7 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi )
|
||||||
{
|
{
|
||||||
pf.AddToRead(FaceDesc(7));
|
pf.AddToRead(FaceDesc(7));
|
||||||
pf.AddToRead(FaceDesc(8));
|
pf.AddToRead(FaceDesc(8));
|
||||||
|
pf.AddToRead(FaceDesc(9));
|
||||||
pi.mask |= Mask::IOM_FACECOLOR;
|
pi.mask |= Mask::IOM_FACECOLOR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -646,6 +649,7 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi )
|
||||||
for(j=0;j<n;++j)
|
for(j=0;j<n;++j)
|
||||||
{
|
{
|
||||||
if(pi.cb && (j%1000)==0) pi.cb(j*50/n,"Vertex Loading");
|
if(pi.cb && (j%1000)==0) pi.cb(j*50/n,"Vertex Loading");
|
||||||
|
va.a = 255;
|
||||||
if( pf.Read( (void *)&(va) )==-1 )
|
if( pf.Read( (void *)&(va) )==-1 )
|
||||||
{
|
{
|
||||||
pi.status = PlyInfo::E_SHORTFILE;
|
pi.status = PlyInfo::E_SHORTFILE;
|
||||||
|
|
@ -737,6 +741,7 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi )
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
if(pi.cb && (j%1000)==0) pi.cb(50+j*50/n,"Face Loading");
|
if(pi.cb && (j%1000)==0) pi.cb(50+j*50/n,"Face Loading");
|
||||||
|
fa.a = 255;
|
||||||
if( pf.Read(&fa)==-1 )
|
if( pf.Read(&fa)==-1 )
|
||||||
{
|
{
|
||||||
pi.status = PlyInfo::E_SHORTFILE;
|
pi.status = PlyInfo::E_SHORTFILE;
|
||||||
|
|
@ -768,7 +773,7 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi )
|
||||||
(*fi).C()[0] = fa.r;
|
(*fi).C()[0] = fa.r;
|
||||||
(*fi).C()[1] = fa.g;
|
(*fi).C()[1] = fa.g;
|
||||||
(*fi).C()[2] = fa.b;
|
(*fi).C()[2] = fa.b;
|
||||||
(*fi).C()[3] = 255;
|
(*fi).C()[3] = fa.a;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pi.mask & Mask::IOM_WEDGTEXCOORD )
|
if( pi.mask & Mask::IOM_WEDGTEXCOORD )
|
||||||
|
|
@ -944,7 +949,7 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//qDebug("Completed the reading of %i indexes",RangeGridAuxVec.size());
|
//qDebug("Completed the reading of %i indexes",RangeGridAuxVec.size());
|
||||||
tri::FaceGrid(m, RangeGridAuxVec, RangeGridCols,RangeGridRows);
|
tri::SparseFaceGrid(m, RangeGridAuxVec, RangeGridCols,RangeGridRows);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -496,7 +496,7 @@ namespace nanoply
|
||||||
for (int i = 0; i < faceDescr.dataDescriptor.size(); i++)
|
for (int i = 0; i < faceDescr.dataDescriptor.size(); i++)
|
||||||
if (faceDescr.dataDescriptor[i]->elem != NNP_UNKNOWN_ENTITY)
|
if (faceDescr.dataDescriptor[i]->elem != NNP_UNKNOWN_ENTITY)
|
||||||
delete faceDescr.dataDescriptor[i];
|
delete faceDescr.dataDescriptor[i];
|
||||||
|
mesh.textures = info.textureFile;
|
||||||
return info.errInfo;
|
return info.errInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -687,6 +687,7 @@ namespace nanoply
|
||||||
infoSave.AddPlyElement(vertexElem);
|
infoSave.AddPlyElement(vertexElem);
|
||||||
infoSave.AddPlyElement(edgeElem);
|
infoSave.AddPlyElement(edgeElem);
|
||||||
infoSave.AddPlyElement(faceElem);
|
infoSave.AddPlyElement(faceElem);
|
||||||
|
infoSave.textureFile = mesh.textures;
|
||||||
std::vector<ElementDescriptor*> meshDescr;
|
std::vector<ElementDescriptor*> meshDescr;
|
||||||
meshDescr.push_back(&cameraDescr);
|
meshDescr.push_back(&cameraDescr);
|
||||||
meshDescr.push_back(&vertexDescr);
|
meshDescr.push_back(&vertexDescr);
|
||||||
|
|
|
||||||
|
|
@ -71,8 +71,8 @@ public:
|
||||||
faceBarycenter[i] = vcg::Barycenter(face[i]);
|
faceBarycenter[i] = vcg::Barycenter(face[i]);
|
||||||
|
|
||||||
material().resize(2);
|
material().resize(2);
|
||||||
material()[0] = { vcg::Point3f(0.1, 0.2, 0.3), vcg::Point3f(0.3, 0.3, 0.3), 5.0 };
|
material()[0] = { vcg::Point3f(0.1f, 0.2f, 0.3f), vcg::Point3f(0.3f, 0.3f, 0.3f), 5.0f };
|
||||||
material()[1] = { vcg::Point3f(0.1, 0.1, 0.1), vcg::Point3f(0.5, 0.3, 0.4), 50.0 };
|
material()[1] = { vcg::Point3f(0.1f, 0.1f, 0.1f), vcg::Point3f(0.5f, 0.3f, 0.4f), 50.0f };
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -87,9 +87,12 @@ bool Load(const char* filename, MyMesh& mesh)
|
||||||
mesh.material().resize(count);
|
mesh.material().resize(count);
|
||||||
customAttrib.AddVertexAttribDescriptor<int, int, 1>(std::string("materialId"), nanoply::NNP_INT32, NULL);
|
customAttrib.AddVertexAttribDescriptor<int, int, 1>(std::string("materialId"), nanoply::NNP_INT32, NULL);
|
||||||
customAttrib.AddFaceAttribDescriptor<vcg::Point3f, float, 3>(std::string("barycenter"), nanoply::NNP_LIST_UINT8_FLOAT32, NULL);
|
customAttrib.AddFaceAttribDescriptor<vcg::Point3f, float, 3>(std::string("barycenter"), nanoply::NNP_LIST_UINT8_FLOAT32, NULL);
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
customAttrib.AddMeshAttribDescriptor<Material, float, 3>(std::string("material"), std::string("kd"), nanoply::NNP_FLOAT32, mesh.material()[0].kd.V());
|
customAttrib.AddMeshAttribDescriptor<Material, float, 3>(std::string("material"), std::string("kd"), nanoply::NNP_FLOAT32, mesh.material()[0].kd.V());
|
||||||
customAttrib.AddMeshAttribDescriptor<Material, float, 3>(std::string("material"), std::string("ks"), nanoply::NNP_FLOAT32, mesh.material()[0].ks.V());
|
customAttrib.AddMeshAttribDescriptor<Material, float, 3>(std::string("material"), std::string("ks"), nanoply::NNP_FLOAT32, mesh.material()[0].ks.V());
|
||||||
customAttrib.AddMeshAttribDescriptor<Material, float, 1>(std::string("material"), std::string("rho"), nanoply::NNP_FLOAT32, &mesh.material()[0].rho);
|
customAttrib.AddMeshAttribDescriptor<Material, float, 1>(std::string("material"), std::string("rho"), nanoply::NNP_FLOAT32, &mesh.material()[0].rho);
|
||||||
|
}
|
||||||
|
|
||||||
//Load the ply file
|
//Load the ply file
|
||||||
unsigned int mask = 0;
|
unsigned int mask = 0;
|
||||||
|
|
@ -113,10 +116,13 @@ bool Save(const char* filename, MyMesh& mesh, bool binary)
|
||||||
nanoply::NanoPlyWrapper<MyMesh>::CustomAttributeDescriptor customAttrib;
|
nanoply::NanoPlyWrapper<MyMesh>::CustomAttributeDescriptor customAttrib;
|
||||||
customAttrib.AddVertexAttribDescriptor<int, int, 1>(std::string("materialId"), nanoply::NNP_INT32, &mesh.vertexMaterial[0]);
|
customAttrib.AddVertexAttribDescriptor<int, int, 1>(std::string("materialId"), nanoply::NNP_INT32, &mesh.vertexMaterial[0]);
|
||||||
customAttrib.AddFaceAttribDescriptor<vcg::Point3f, float, 3>(std::string("barycenter"), nanoply::NNP_LIST_UINT8_FLOAT32, mesh.faceBarycenter[0].V());
|
customAttrib.AddFaceAttribDescriptor<vcg::Point3f, float, 3>(std::string("barycenter"), nanoply::NNP_LIST_UINT8_FLOAT32, mesh.faceBarycenter[0].V());
|
||||||
customAttrib.AddMeshAttrib(std::string("material"), 2);
|
if (mesh.material().size() > 0)
|
||||||
|
{
|
||||||
|
customAttrib.AddMeshAttrib(std::string("material"), mesh.material().size());
|
||||||
customAttrib.AddMeshAttribDescriptor<Material, float, 3>(std::string("material"), std::string("kd"), nanoply::NNP_LIST_UINT8_FLOAT32, mesh.material()[0].kd.V());
|
customAttrib.AddMeshAttribDescriptor<Material, float, 3>(std::string("material"), std::string("kd"), nanoply::NNP_LIST_UINT8_FLOAT32, mesh.material()[0].kd.V());
|
||||||
customAttrib.AddMeshAttribDescriptor<Material, float, 3>(std::string("material"), std::string("ks"), nanoply::NNP_LIST_UINT8_FLOAT32, mesh.material()[0].ks.V());
|
customAttrib.AddMeshAttribDescriptor<Material, float, 3>(std::string("material"), std::string("ks"), nanoply::NNP_LIST_UINT8_FLOAT32, mesh.material()[0].ks.V());
|
||||||
customAttrib.AddMeshAttribDescriptor<Material, float, 1>(std::string("material"), std::string("rho"), nanoply::NNP_FLOAT32, &mesh.material()[0].rho);
|
customAttrib.AddMeshAttribDescriptor<Material, float, 1>(std::string("material"), std::string("rho"), nanoply::NNP_FLOAT32, &mesh.material()[0].rho);
|
||||||
|
}
|
||||||
|
|
||||||
//Save the ply file
|
//Save the ply file
|
||||||
unsigned int mask = 0;
|
unsigned int mask = 0;
|
||||||
|
|
|
||||||
|
|
@ -56,12 +56,14 @@ Cleaning of the automatic bbox caching support for ply files. First working vers
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include <vcg/space/box3.h>
|
#include <vcg/space/box3.h>
|
||||||
#include <wrap/ply/plylib.h>
|
#include <wrap/ply/plylib.h>
|
||||||
using namespace vcg;
|
using namespace vcg;
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ namespace vcg
|
||||||
void meshAttributesUpdated(bool hasmeshconnectivitychanged,const GLMeshAttributesInfo::RendAtts& changedrendatts)
|
void meshAttributesUpdated(bool hasmeshconnectivitychanged,const GLMeshAttributesInfo::RendAtts& changedrendatts)
|
||||||
{
|
{
|
||||||
QWriteLocker locker(&_lock);
|
QWriteLocker locker(&_lock);
|
||||||
vcg::NotThreadSafeGLMeshAttributesMultiViewerBOManager<MESH_TYPE,UNIQUE_VIEW_ID_TYPE,GL_OPTIONS_DERIVED_TYPE>::meshAttributesUpdated(hasmeshconnectivitychanged,changedrendatts);
|
vcg::NotThreadSafeGLMeshAttributesMultiViewerBOManager<MESH_TYPE,UNIQUE_VIEW_ID_TYPE,GL_OPTIONS_DERIVED_TYPE>::meshAttributesUpdated(hasmeshconnectivitychanged, changedrendatts);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getPerViewInfo(UNIQUE_VIEW_ID_TYPE viewid,PerViewData<GL_OPTIONS_DERIVED_TYPE>& dt) const
|
bool getPerViewInfo(UNIQUE_VIEW_ID_TYPE viewid,PerViewData<GL_OPTIONS_DERIVED_TYPE>& dt) const
|
||||||
|
|
@ -62,6 +62,12 @@ namespace vcg
|
||||||
vcg::NotThreadSafeGLMeshAttributesMultiViewerBOManager<MESH_TYPE,UNIQUE_VIEW_ID_TYPE,GL_OPTIONS_DERIVED_TYPE>::setPerViewInfo(viewid,dt);
|
vcg::NotThreadSafeGLMeshAttributesMultiViewerBOManager<MESH_TYPE,UNIQUE_VIEW_ID_TYPE,GL_OPTIONS_DERIVED_TYPE>::setPerViewInfo(viewid,dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setPerAllViewsInfo(const PerViewData<GL_OPTIONS_DERIVED_TYPE>& dt)
|
||||||
|
{
|
||||||
|
QWriteLocker locker(&_lock);
|
||||||
|
vcg::NotThreadSafeGLMeshAttributesMultiViewerBOManager<MESH_TYPE, UNIQUE_VIEW_ID_TYPE, GL_OPTIONS_DERIVED_TYPE>::setPerAllViewsInfo(dt);
|
||||||
|
}
|
||||||
|
|
||||||
void removeView(UNIQUE_VIEW_ID_TYPE viewid)
|
void removeView(UNIQUE_VIEW_ID_TYPE viewid)
|
||||||
{
|
{
|
||||||
QWriteLocker locker(&_lock);
|
QWriteLocker locker(&_lock);
|
||||||
|
|
@ -74,6 +80,13 @@ namespace vcg
|
||||||
vcg::NotThreadSafeGLMeshAttributesMultiViewerBOManager<MESH_TYPE,UNIQUE_VIEW_ID_TYPE,GL_OPTIONS_DERIVED_TYPE>::draw(viewid,_textids.textId());
|
vcg::NotThreadSafeGLMeshAttributesMultiViewerBOManager<MESH_TYPE,UNIQUE_VIEW_ID_TYPE,GL_OPTIONS_DERIVED_TYPE>::draw(viewid,_textids.textId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void drawAllocatedAttributesSubset(UNIQUE_VIEW_ID_TYPE viewid,const PerViewData<GL_OPTIONS_DERIVED_TYPE>& dt) const
|
||||||
|
{
|
||||||
|
QReadLocker locker(&_lock);
|
||||||
|
vcg::NotThreadSafeGLMeshAttributesMultiViewerBOManager<MESH_TYPE,UNIQUE_VIEW_ID_TYPE,GL_OPTIONS_DERIVED_TYPE>::drawAllocatedAttributesSubset(viewid,dt,_textids.textId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool isBORenderingAvailable() const
|
bool isBORenderingAvailable() const
|
||||||
{
|
{
|
||||||
QReadLocker locker(&_lock);
|
QReadLocker locker(&_lock);
|
||||||
|
|
@ -113,7 +126,7 @@ namespace vcg
|
||||||
vcg::NotThreadSafeGLMeshAttributesMultiViewerBOManager<MESH_TYPE,UNIQUE_VIEW_ID_TYPE,GL_OPTIONS_DERIVED_TYPE>::setDebugMode(activatedebugmodality);
|
vcg::NotThreadSafeGLMeshAttributesMultiViewerBOManager<MESH_TYPE,UNIQUE_VIEW_ID_TYPE,GL_OPTIONS_DERIVED_TYPE>::setDebugMode(activatedebugmodality);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getLog(vcg::GLMeshAttributesInfo::DebugInfo& info)
|
void getLog(GLMeshAttributesInfo::DebugInfo& info)
|
||||||
{
|
{
|
||||||
QWriteLocker locker(&_lock);
|
QWriteLocker locker(&_lock);
|
||||||
vcg::NotThreadSafeGLMeshAttributesMultiViewerBOManager<MESH_TYPE,UNIQUE_VIEW_ID_TYPE,GL_OPTIONS_DERIVED_TYPE>::getLog(info);
|
vcg::NotThreadSafeGLMeshAttributesMultiViewerBOManager<MESH_TYPE,UNIQUE_VIEW_ID_TYPE,GL_OPTIONS_DERIVED_TYPE>::getLog(info);
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ template <class ShotType>
|
||||||
shot.Extrinsics.SetRot(rot);
|
shot.Extrinsics.SetRot(rot);
|
||||||
|
|
||||||
vcg::Camera<ScalarType> &cam = shot.Intrinsics;
|
vcg::Camera<ScalarType> &cam = shot.Intrinsics;
|
||||||
|
if(attr.contains("CameraType")) cam.cameraType = attr.namedItem("CameraType").nodeValue().toInt();
|
||||||
cam.FocalMm = attr.namedItem("FocalMm").nodeValue().toDouble();
|
cam.FocalMm = attr.namedItem("FocalMm").nodeValue().toDouble();
|
||||||
cam.ViewportPx.X() = attr.namedItem("ViewportPx").nodeValue().section(' ',0,0).toInt();
|
cam.ViewportPx.X() = attr.namedItem("ViewportPx").nodeValue().section(' ',0,0).toInt();
|
||||||
cam.ViewportPx.Y() = attr.namedItem("ViewportPx").nodeValue().section(' ',1,1).toInt();
|
cam.ViewportPx.Y() = attr.namedItem("ViewportPx").nodeValue().section(' ',1,1).toInt();
|
||||||
|
|
@ -118,6 +119,8 @@ template <class ShotType>
|
||||||
|
|
||||||
const vcg::Camera<ScalarType> &cam = shot.Intrinsics;
|
const vcg::Camera<ScalarType> &cam = shot.Intrinsics;
|
||||||
|
|
||||||
|
shotElem.setAttribute("CameraType", cam.cameraType);
|
||||||
|
|
||||||
shotElem.setAttribute( "FocalMm", cam.FocalMm);
|
shotElem.setAttribute( "FocalMm", cam.FocalMm);
|
||||||
|
|
||||||
str = QString("%1 %2").arg(cam.k[0]).arg(cam.k[1]);
|
str = QString("%1 %2").arg(cam.k[0]).arg(cam.k[1]);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue