Commit fea93fec authored by Pierre Kraemer's avatar Pierre Kraemer

Merge cgogn:~cgogn/CGoGN

parents b0194eba ae997b3c
......@@ -166,6 +166,8 @@ void Viewer::cb_Open()
{
std::string filters("all (*.*);; trian (*.trian);; ctm (*.ctm);; off (*.off);; ply (*.ply)") ;
std::string filename = selectFile("Open Mesh", "", filters) ;
if (filename.empty())
return ;
importMesh(filename) ;
updateGL() ;
......
......@@ -189,14 +189,6 @@ void StageShader::importMesh(std::string& filename)
else
position = myMap.getAttribute<PFP::VEC3>(VERTEX , attrNames[0]) ;
}
else
{
position = myMap.addAttribute<PFP::VEC3>(VERTEX, "position");
Algo::Modelisation::Primitive3D<PFP> prim(myMap, position);
prim.hexaGrid_topo(10,10,10);
prim.embedHexaGrid(1.0f,1.0f,1.0f);
}
updateVBOprimitives(Algo::Render::GL2::TRIANGLES | Algo::Render::GL2::LINES | Algo::Render::GL2::POINTS) ;
......@@ -316,6 +308,13 @@ int main(int argc, char** argv)
std::string filename(argv[1]) ;
sqt.importMesh(filename) ;
}
else
{
sqt.position = sqt.myMap.addAttribute<PFP::VEC3>(VERTEX, "position");
Algo::Modelisation::Primitive3D<PFP> prim(sqt.myMap, sqt.position);
prim.hexaGrid_topo(10,10,10);
prim.embedHexaGrid(1.0f,1.0f,1.0f);
}
sqt.initGUI() ;
......
Pour utiliser Eclipse (testé avec la version Helios & Galileo)
Pour utiliser Eclipse (testé avec la version Helios, Galileo & Indigo)
Faire un nouveau projet C++
Choisir Makefile project -> Empty Project
Choisir Comme "Location": la racine de NewCGoGN
Choisir Toolchains: Linux GCC
* Configurer un projet dans Eclipse :
- Faire un nouveau projet C++
- Choisir Makefile project -> Empty Project
- Choisir Comme "Location": la racine de CGoGN
- Choisir Toolchains: Linux GCC
* Compilation avec le petit marteau ;) (l'icone)
Dans les propriétés du projet:
-> C/C++ Build:
Dans la configuration Default | Active:
......@@ -12,14 +14,41 @@ Dans les propriétés du projet:
on peut ensuite ajouter des configurations pour compiler ce que l'on veut
en changeant juste le Build directory:
CGoGNRelease: build/Release (compile la lib en release)
CGoGNDebug: build/Debug (compile la lib en debug)
Apps: build/Apps (compile les exemples et les tutos)
CGoGNRelease: build/Release (compile la lib en release)
CGoGNDebug: build/Debug (compile la lib en debug)
Apps: build/Apps (compile les exemples et les tutos)
Tuto: build/Apps/Tuto (compile les tutos)
etc..
On peut alors compiler avec le petit marteau ;) (l'icone) et choisir avec le bouton droit ce que l'on
veut compiler.
Ceci ajoute dans le repertoire de CGoGN un .project et un .cproject.
* Dépendances inter-projets et autocomplétion
Si le projet X dépend d'un autre projet, alors :
Projet X -> Properties -> Project references : cocher le projet dont il dépend.
* Dépendances de Qt :
Afin d'éviter qu'Eclipse ne rejette les syntaxes Qt (les includes de Qt, les Q_OBJECT, les callbacks) :
- Télécharger le plugin Qt "eclipse-integration" http://qt.nokia.com/developer/eclipse-integration/
- Décompresser l'archive et copier son contenu dans le répertoire d'installation d'Eclipse (plugins et features)
- Relancer Eclipse au moins une fois avec l'option --clean (relecture des répertoires locaux)
Normalement, dans Window->Preferences de Eclipse, Qt apparait dans le menu.
- Y ajouter le répertoire de Qt (/usr/bin sur Debian/Ubuntu) et le répertoire d'include (/usr/include/qt4).
Ensuite, pour chaque projet, ajouter les includes suivants dans Properties -> C/C++ general -> Paths and Symbols
parmi les includes de C++ :
- /usr/include/qt4
- /usr/include/qt4/Qt
- /usr/include/qt4/QtCore
- /usr/include/qt4/QtGui
- /usr/include/qt4/QtOpenGL
REMARQUE : en bas de cette fenêtre, le bouton "Export Settings" permet d'exporter en XML la configuration afin
de l'importer dans les autres projets.
- Pour finir, un petit clic-droit sur le projet -> Index -> Freshen all files et le tour est joué.
* Coloration syntaxique des shaders
- Télécharger et décompresser EclipseShaders : http://sourceforge.net/projects/glshaders/
- Copier les répertoires plugins et features dans le répertoire d'installation eclipse
- Relancer Eclipse au moins une fois avec l'option --clean (relecture des répertoires locaux)
Eclipse reconnaîtra désormais les fichiers .frag et .vert.
Pour associer d'autres fichiers au programme GLSLeditor :
- Preferences -> General -> Editors -> File Associations
Dans Preferences -> Shaders Preferences, on peut désormais configurer certaines options liées au shaders.
......@@ -32,7 +32,7 @@ namespace IHM
{
/***************************************************
* ATTRIBUTES MANAGEMENT *
* ATTRIBUTES MANAGEMENT *
***************************************************/
template <typename T>
......@@ -64,7 +64,7 @@ AttributeHandler_IHM<T> ImplicitHierarchicalMap3::getAttribute(unsigned int orbi
}
/***************************************************
* MAP TRAVERSAL *
* MAP TRAVERSAL *
***************************************************/
inline Dart ImplicitHierarchicalMap3::newDart()
......
......@@ -51,7 +51,7 @@ namespace Import
* @return a boolean indicating if import was successfull
*/
template <typename PFP>
bool importMesh(typename PFP::MAP& map, const std::string& filename, std::vector<std::string>& attrNames, ImportSurfacique::ImportType kind = ImportSurfacique::UNKNOWNSURFACE);
bool importMesh(typename PFP::MAP& map, const std::string& filename, std::vector<std::string>& attrNames, ImportSurfacique::ImportType kind = ImportSurfacique::UNKNOWNSURFACE, bool mergeCloseVertices=false);
/**
* import a volumic mesh
......
......@@ -115,6 +115,8 @@ public:
bool importCTM(const std::string& filename, std::vector<std::string>& attrNames);
bool importASSIMP(const std::string& filename, std::vector<std::string>& attrNames);
bool mergeCloseVertices();
/**
* @param container container of vertex orbite
......
......@@ -23,6 +23,8 @@
*******************************************************************************/
#include "Algo/Import/importPlyData.h"
#include "Algo/Geometry/boundingbox.h"
#include "Topology/generic/autoAttributeHandler.h"
#include "openctm.h"
......@@ -433,7 +435,7 @@ bool MeshTablesSurface<PFP>::importObj(const std::string& filename, std::vector<
m_emb.reserve(verticesID.size()*8);
std::vector<int> table;
table.reserve(64); // 64 cotes pour une face devrait suffire
table.reserve(64); // NBV cotes pour une face devrait suffire
m_nbFaces = 0;
do
{
......@@ -672,9 +674,8 @@ bool MeshTablesSurface<PFP>::importPlyPTMgeneric(const std::string& filename, st
* @param attrNames : reference that will be filled with the attribute names ;
* - 1 attrName for geometric position (VEC3)
* - 3 attrNames for local frame (3xVEC3) : Tangent, Bitangent and Normal vector
* - 6 attrNames for the function coefficients (6xVEC3) : 6 RGB coefficients being successively the constants, the linears (v then u) and the quadratics : a0 + a1*v + a2*u + a3*u*v + a4*v^2 + a5*u^2.
* @return bool : success.
* @return bool : success.
* - 6 attrNames for the function coefficients (6xVEC3) : 6 RGB coefficients being successively the quadratic members, the linears and the constants (u then v) : a*u^2 + b*v^2 + c*uv + d*u + e*v +f.
* @return bool : success.
*/
template <typename PFP>
bool MeshTablesSurface<PFP>::importPlyPTM(const std::string& filename, std::vector<std::string>& attrNames)
......@@ -931,6 +932,158 @@ bool MeshTablesSurface<PFP>::importASSIMP(const std::string& filename, std::vect
return true;
}
template<typename PFP>
bool MeshTablesSurface<PFP>::mergeCloseVertices()
{
const unsigned int NBV=64; // seems to be good
const int NEIGH[27]={
-NBV*NBV - NBV - 1, -NBV*NBV - NBV, -NBV*NBV - NBV + 1,
-NBV*NBV - 1, -NBV*NBV, -NBV*NBV + 1,
-NBV*NBV + NBV - 1, -NBV*NBV + NBV, - NBV*NBV + NBV + 1,
-NBV - 1, - NBV, -NBV + 1,
-1, 0, 1,
NBV - 1, NBV, NBV + 1,
NBV*NBV - NBV - 1, NBV*NBV - NBV, NBV*NBV - NBV + 1,
NBV*NBV - 1, NBV*NBV, NBV*NBV + 1,
NBV*NBV + NBV - 1, NBV*NBV + NBV, NBV*NBV + NBV + 1};
std::vector<unsigned int>** grid;
grid = new std::vector<unsigned int>*[NBV*NBV*NBV];
// init grid with null ptrs
for (unsigned int i=0; i<NBV*NBV*NBV; ++i)
grid[i]=NULL;
AttributeHandler<typename PFP::VEC3> positions = m_map.template getAttribute<typename PFP::VEC3>(VERTEX, "position");
// compute BB
Geom::BoundingBox<typename PFP::VEC3> bb(positions[ positions.begin() ]) ;
for (unsigned int i = positions.begin(); i != positions.end(); positions.next(i))
{
bb.addPoint(positions[i]) ;
}
// add one voxel around to avoid testing
typename PFP::VEC3 bbsize = (bb.max() - bb.min());
typename PFP::VEC3 one = bbsize/(NBV-2);
one*= 1.001f;
bb.addPoint( bb.min() - one);
bb.addPoint( bb.max() + one);
bbsize = (bb.max() - bb.min());
AutoAttributeHandler<unsigned int> gridIndex(m_map,VERTEX, "gridIndex");
AutoAttributeHandler<unsigned int> newIndices(m_map,VERTEX, "newIndices");
// Store each vertex in the grid and store voxel index in vertex attribute
for (unsigned int i = positions.begin(); i != positions.end(); positions.next(i))
{
typename PFP::VEC3 P = positions[i];
P -= bb.min();
float pz = floor((P[2]/bbsize[2])*NBV);
float py = floor((P[1]/bbsize[1])*NBV);
float px = floor((P[0]/bbsize[0])*NBV);
unsigned int index = NBV*NBV*pz + NBV*py + px;
if (pz==63)
std::cout << "z 63 bb:"<<bb<<" P="<<positions[i]<< std::endl;
std::vector<unsigned int>* vox = grid[index];
if (vox==NULL)
{
grid[index] = new std::vector<unsigned int>();
grid[index]->reserve(8);
vox = grid[index];
}
vox->push_back(i);
gridIndex[i] = index;
newIndices[i] = 0xffffffff;
}
// compute EPSILON: average length of 50 of 100 first edges of first faces divide by 10000
int nb = 100;
if (m_nbEdges.size()< 100)
nb = m_nbEdges.size();
int k=0;
typename PFP::REAL d=0;
for (int i=0; i< nb; i+=2)
{
typename PFP::VEC3 e1 = positions[m_emb[k+1]] - positions[m_emb[k]];
d += e1.norm();
k += m_nbEdges[i];
}
d /= float(nb/2);
typename PFP::REAL EPSILON = d/10000.0f;
// traverse vertices
for (unsigned int i = positions.begin(); i != positions.end(); positions.next(i))
{
if (newIndices[i] == 0xffffffff)
{
const typename PFP::VEC3& P = positions[i];
for (unsigned int n=0; n<27; ++n)
{
std::vector<unsigned int>* voxel = grid[gridIndex[i]+NEIGH[n]];
if (voxel != NULL)
{
for (std::vector<unsigned int>::iterator v = voxel->begin(); v != voxel->end(); ++v)
{
if ((*v != i) && (*v != 0xffffffff))
{
typename PFP::VEC3 Q = positions[*v];
Q -= P;
typename PFP::REAL d2 = Q*Q;
if (d2 < EPSILON*EPSILON)
{
newIndices[*v] = i;
*v = 0xffffffff;
}
}
}
}
}
}
}
// update faces indices
for (std::vector<unsigned int>::iterator it = m_emb.begin(); it != m_emb.end(); ++it)
{
if (newIndices[*it] != 0xffffffff)
{
*it = newIndices[*it];
}
}
// delete embeddings
AttributeContainer& container = m_map.getAttributeContainer(VERTEX) ;
for (unsigned int i = positions.begin(); i != positions.end(); positions.next(i))
{
if (newIndices[i] != 0xffffffff)
{
container.removeLine(i);
}
}
// release grid memory
for (unsigned int i=0; i<NBV*NBV*NBV; ++i)
if (grid[i]!=NULL)
delete grid[i];
delete[] grid;
return true;
}
} // namespace Import
} // namespace Algo
......
......@@ -114,6 +114,7 @@ bool importMesh(typename PFP::MAP& map, MeshTablesSurface<PFP>& mts)
}
else
{
m.unmark(d);
++nbnm;
}
}
......@@ -425,12 +426,15 @@ bool importMesh(typename PFP::MAP& map, MeshTablesVolume<PFP>& mtv)
}
template <typename PFP>
bool importMesh(typename PFP::MAP& map, const std::string& filename, std::vector<std::string>& attrNames, ImportSurfacique::ImportType kind)
bool importMesh(typename PFP::MAP& map, const std::string& filename, std::vector<std::string>& attrNames, ImportSurfacique::ImportType kind, bool mergeCloseVertices)
{
MeshTablesSurface<PFP> mts(map);
if(!mts.importMesh(filename, attrNames, kind))
return false;
if (mergeCloseVertices)
mts.mergeCloseVertices();
return importMesh<PFP>(map, mts);
}
......
......@@ -87,15 +87,17 @@ public:
};
class SvgPolyline: public SvgObj
class SvgPoints: public SvgObj
{
protected:
public:
void save(std::ofstream& out);
};
class SvgPolyline: public SvgObj
{
public:
void save(std::ofstream& out);
};
......@@ -151,7 +153,11 @@ public:
void renderLinesToSVG(typename PFP::MAP& map, const typename PFP::TVEC3& position, const FunctorSelect& good = SelectorTrue(), unsigned int thread=0);
template <typename PFP>
void renderFacesToSVG(typename PFP::MAP& map, const typename PFP::TVEC3& position, float shrink, const FunctorSelect& good = SelectorTrue(), unsigned int thread=0);
void renderFacesToSVG(typename PFP::MAP& map, const typename PFP::TVEC3& position, float shrink, bool cull = false, const FunctorSelect& good = SelectorTrue(), unsigned int thread=0);
template <typename PFP>
void renderPointsToSVG(typename PFP::MAP& map, const typename PFP::TVEC3& position, const FunctorSelect& good = SelectorTrue(), unsigned int thread=0);
void orderPrimitives(std::list<SvgObj*>& primitives);
};
......
......@@ -38,6 +38,32 @@ namespace Render
namespace SVG
{
template <typename PFP>
void SVGOut::renderPointsToSVG(typename PFP::MAP& map, const typename PFP::TVEC3& position, const FunctorSelect& good, unsigned int thread)
{
glm::i32vec4 viewport;
glGetIntegerv(GL_VIEWPORT, &(viewport[0]));
SvgPoints* points = new SvgPoints();
points->setColor(global_color);
points->setWidth(global_width);
DartMarker m(map, thread);
for(Dart d = map.begin(); d != map.end(); map.next(d))
{
if(!m.isMarked(d) && good(d))
{
const Geom::Vec3f& P = position[d];
glm::vec3 Q = glm::project(glm::vec3(P[0],P[1],P[2]),m_model,m_proj,viewport);
glm::vec3 R = glm::project(glm::vec3(P[0],P[1],P[2]),m_model,glm::mat4(1.0),viewport);
points->addVertex(Geom::Vec3f(Q[0],float(viewport[3])-Q[1],Q[2]));
m.markOrbit(VERTEX, d);
}
}
m_objs.push_back(points);
}
template <typename PFP>
void SVGOut::renderLinesToSVG(typename PFP::MAP& map, const typename PFP::TVEC3& position, const FunctorSelect& good, unsigned int thread)
{
......@@ -75,7 +101,7 @@ void SVGOut::renderLinesToSVG(typename PFP::MAP& map, const typename PFP::TVEC3&
template <typename PFP>
void SVGOut::renderFacesToSVG(typename PFP::MAP& map, const typename PFP::TVEC3& position, float shrink, const FunctorSelect& good, unsigned int thread)
void SVGOut::renderFacesToSVG(typename PFP::MAP& map, const typename PFP::TVEC3& position, float shrink, bool cull, const FunctorSelect& good, unsigned int thread)
{
glm::i32vec4 viewport;
glGetIntegerv(GL_VIEWPORT, &(viewport[0]));
......@@ -85,25 +111,42 @@ void SVGOut::renderFacesToSVG(typename PFP::MAP& map, const typename PFP::TVEC3&
{
if(!m.isMarked(d) && good(d))
{
typename PFP::VEC3 center = Algo::Geometry::faceCentroid<PFP>(map,d,position);
SvgPolygon* pol = new SvgPolygon();
Dart dd = d;
do
bool cullFace=false;
if (cull)
{
Geom::Vec3f P = position[d];
P = P*shrink + center*(1.0f-shrink);
glm::vec3 Q = glm::project(glm::vec3(P[0],P[1],P[2]),m_model,m_proj,viewport);
glm::vec3 R = glm::project(glm::vec3(P[0],P[1],P[2]),m_model,glm::mat4(1.0),viewport);
pol->addVertex(Geom::Vec3f(Q[0],float(viewport[3])-Q[1],Q[2]));
pol->addVertex3D(Geom::Vec3f(R[0],R[1],R[2]));
d = map.phi1(d);
}while (d!=dd);
pol->close();
pol->setColor(global_color);
pol->setWidth(global_width);
m_objs.push_back(pol);
const Geom::Vec3f& P = position[d];
glm::vec3 Q = glm::project(glm::vec3(P[0],P[1],P[2]),m_model,m_proj,viewport);
const Geom::Vec3f& P2 = position[map.phi1(d)];
glm::vec3 R = glm::project(glm::vec3(P2[0],P2[1],P2[2]),m_model,m_proj,viewport);
const Geom::Vec3f& P3 = position[map.phi1(map.phi1(d))];
glm::vec3 S = glm::project(glm::vec3(P3[0],P3[1],P3[2]),m_model,m_proj,viewport);
glm::vec3 N = glm::cross(S-R,Q-R);
if (N[2]<0.0f)
cullFace=true;
}
if (!cullFace)
{
typename PFP::VEC3 center = Algo::Geometry::faceCentroid<PFP>(map,d,position);
SvgPolygon* pol = new SvgPolygon();
Dart dd = d;
do
{
Geom::Vec3f P = position[d];
P = P*shrink + center*(1.0f-shrink);
glm::vec3 Q = glm::project(glm::vec3(P[0],P[1],P[2]),m_model,m_proj,viewport);
glm::vec3 R = glm::project(glm::vec3(P[0],P[1],P[2]),m_model,glm::mat4(1.0),viewport);
pol->addVertex(Geom::Vec3f(Q[0],float(viewport[3])-Q[1],Q[2]));
pol->addVertex3D(Geom::Vec3f(R[0],R[1],R[2]));
d = map.phi1(d);
}while (d!=dd);
pol->close();
pol->setColor(global_color);
pol->setWidth(global_width);
m_objs.push_back(pol);
}
m.markOrbit(FACE, d);
}
}
......
/*******************************************************************************
* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps *
* version 0.1 *
* Copyright (C) 2009-2011, IGG Team, LSIIT, University of Strasbourg *
* *
* This library is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, or (at your *
* option) any later version. *
* *
* This library 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 Lesser General Public License *
* for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this library; if not, write to the Free Software Foundation, *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
* *
* Web site: http://cgogn.u-strasbg.fr/ *
* Contact information: cgogn@unistra.fr *
* *
*******************************************************************************/
#ifndef LOCALFRAME_H_
#define LOCALFRAME_H_
#include <cmath>
namespace CGoGN {
namespace Utils {
/**
* Util for rotation of a 3D point (or vector) around a given line (going through the origin) and of a given angle
* @param axis the rotation axis direction
* @param angle the rotation angle
* @param p the point to rotate
*/
template <typename REAL>
Geom::Vector<3,REAL> rotate (Geom::Vector<3,REAL> axis, REAL angle, Geom::Vector<3,REAL> p) ;
/**
* Util for conversion from spherical to carthesian coordinates.
* The spherical coordinates are in radius-longitude-latitude
* @param sph the spherical coordinates
* @return the carthesian coordinates
*/
template<typename REAL>
Geom::Vector<3,REAL> sphericalToCarth (const Geom::Vector<3,REAL>& sph) ;
/**
* Util for conversion from carthesian to spherical coordinates.
* The spherical coordinates are in radius-longitude-latitude
* @param carth the carthesian coordinates
* @return the spherical coordinates
*/
template<typename REAL>
Geom::Vector<3,REAL> carthToSpherical (const Geom::Vector<3,REAL>& carth) ;
/**
* Class for representing a direct local frame composed of 3 orthonormal vectors T (tangent), B (bitangent) and N (normal).
* This class can compress/decompress a local frame, switching from its explicit representation (3 vectors) to its compressed representation (1 vector).
* Usage :
* VEC3 T,B,N ; // current set of orthonormal vectors composing the direct frame.
* LocalFrame<PFP> lf(T,B,N) ; // Constructor from explicit expression.
* if (lf.isOrthoNormalDirect()) // test if the frame is Orthogonal, Normalized and Direct
* VEC3 compressed = lf.getCompressed() ; // Extract compressed frame
* LocalFrame<PFP> decompressed(compressed) ; // Constructor from implicit (compressed) expression.
*
* All formulae were provided by "Représentation compacte d'un repère local", june 14th, 2011 by K. Vanhoey
*/
template <typename PFP>
class LocalFrame
{
typedef typename PFP::REAL REAL ;
typedef typename Geom::Vector<2,REAL> VEC2 ;
typedef typename Geom::Vector<3,REAL> VEC3 ;
private: // fields
/**
* The three explicit vectors
*/
VEC3 m_T,m_B,m_N ;
public: // methods
/**
* Constructor from explicit data
* @param T the tangent vector
* @param B the bitangent vector
* @param N the normal vector
*/
LocalFrame(const VEC3& T, const VEC3& B, const VEC3& N) ;
/**
* Constructor from implicit (compressed representation)
* @param compressedFrame an implicit (compressed) version of the local frame (can be produced by localFrame.getCompressed())
*/
LocalFrame(const VEC3& compressedFrame) ;
~LocalFrame() {} ;
/**
* Returns a compressed version of the current local frame
* A VEC3 is not sufficient to completely define a local frame (if phiN=0, the decompression is not unique).
*/
VEC3 getCompressed() const ;
/**
* Tests if the frames are identical
* @param lf the frame to compare to the current frame
* @param epsilon the authorized deviation
* @return true if frames are identical (or deviate less than epsilon)
*/
bool equals(const LocalFrame<PFP>& lf, REAL epsilon = 1e-6) const ;
/**
* Equality of frames
* Identical to calling equals with default epsilon
* @return true if frames are identical
*/
bool operator==(const LocalFrame<PFP>& lf) const ;
/**
* Inequality of frames
* Identical to calling !equals with default epsilon
* @return false if frames are identical
*/
bool operator!=(const LocalFrame<PFP>& lf) const ;