Commit 2bd9824e authored by untereiner's avatar untereiner

Merge cgogn:~cgogn/CGoGN

parents 994aed28 ed815783
......@@ -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
{
......@@ -931,6 +933,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
......
......@@ -425,12 +425,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);
}
......
/*******************************************************************************
* 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_
namespace CGoGN {
namespace Utils {
/**
* 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::VEC3> 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::VEC3> 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 PFP::VEC3 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
*/
LocalFrame(const VEC3& compressedFrame) ;
~LocalFrame() {} ;
/**
* Returns a compressed version of the current local frame
*/
VEC3 getCompressed() ;
/**
* 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-5) 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 ;
/**
* Tests if the frame is direct
* @return true if the frame is direct
*/
bool isDirect() const ;
/**
* Tests if the frame is orthogonal
* @return true if the frame is orthogonal
*/
bool isOrthogonal() const ;
/**
* Tests if the frame is normalized
* @return true if the frame is normalized
*/
bool isNormalized() const ;
/**
* Tests if the frame is direct, normalized and orthogonal
* @return true if the frame is direct, normalized and orthogonal
*/
bool isOrthoNormalDirect() const ;
/**
* @return current tangent vector
*/
VEC3& getT() { return m_T ; }
const VEC3& getT() const { return m_T ; }
/**
* @return current bitangent vector
*/
VEC3& getB() { return m_B ; }
const VEC3& getB() const { return m_B ; }
/**
* @return current normal vector
*/
VEC3& getN() { return m_N ; }
const VEC3& getN() const { return m_N ; }
friend std::ostream& operator<< (std::ostream &out, const LocalFrame& lf) {
out << "T : " << lf.m_T << std::endl ;
out << "B : " << lf.m_B << std::endl ;
out << "N : " << lf.m_N << std::endl ;
return out ;
} ;
private : // methods
VEC2 carthToSpherical(const VEC3& carth) const ;
VEC3 sphericalToCarth(const VEC2& sph) const ;
} ;
} // Utils
} // CGoGN
#include "localFrame.hpp"
#endif /* LOCALFRAME_H_ */
/*******************************************************************************
* 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 *
* *
*******************************************************************************/
namespace CGoGN {
namespace Utils {
template<typename PFP>
LocalFrame<PFP>::LocalFrame(const VEC3& T, const VEC3& B, const VEC3& N)
{
m_T = T ;
m_B = B ;
m_N = N ;
}
template<typename PFP>
LocalFrame<PFP>::LocalFrame(const VEC3& compressedFrame)
{
VEC2 Nspher ;
VEC2 Tspher ;
REAL& thetaN = Nspher[0] ; // known
REAL& phiN = Nspher[1] ; // known
REAL& thetaT = Tspher[0] ; // known
REAL& phiT = Tspher[1] ; // to be decoded
// compute phiT
REAL Den,Nom ;
Den = sin(phiN)*(cos(thetaN)*cos(thetaT) + sin(thetaN)*sin(thetaT)) ; // Based on orthogonality
Nom = cos(phiN) ;
phiT = -atan(Nom/Den) ; // if A==0, atan returns Pi/2
if (phiT < 0.0)
phiT = M_PI + phiT ; // = Pi - |phiT|
// convert to carthesian
m_N = sphericalToCarth(Nspher) ;
m_T = sphericalToCarth(Tspher) ;
// compute B
m_B = m_N ^ m_T ;
}
template<typename PFP>
typename PFP::VEC3 LocalFrame<PFP>::getCompressed()
{
VEC3 res ;
REAL& thetaN = res[0] ;
REAL& phiN = res[1] ;
REAL& thetaT = res[2] ;
// convert to spherical coordinates
VEC2 Nspher = carthToSpherical(m_N) ;
VEC2 Tspher = carthToSpherical(m_T) ;
// extract the three scalars
thetaN = Nspher[0] ;
phiN = Nspher[1] ;
thetaT = Tspher[0] ;
return res ;
}
template<typename PFP>
bool LocalFrame<PFP>::equals(const Utils::LocalFrame<PFP>& lf, REAL epsilon) const
{
VEC3 dT = m_T - lf.getT() ;
VEC3 dB = m_B - lf.getB() ;
VEC3 dN = m_N - lf.getN() ;
return dT.norm2() < epsilon && dB.norm2() < epsilon && dN.norm2() < epsilon ;
}
template<typename PFP>
bool LocalFrame<PFP>::operator==(const LocalFrame<PFP>& lf) const
{
return this->equals(lf) ;
}
template<typename PFP>
bool LocalFrame<PFP>::operator!=(const LocalFrame<PFP>& lf) const
{
return !(this->equals(lf)) ;
}
template<typename PFP>
bool LocalFrame<PFP>::isDirect() const
{
VEC3 new_B = m_N ^ m_T ; // direct
VEC3 diffs = new_B - m_B ; // differences with existing B
REAL diffNorm = diffs.norm2() ; // Norm of this differences vector
return (diffNorm < 1e-10) ; // Verify that this difference is very small
}
template<typename PFP>
bool LocalFrame<PFP>::isOrthogonal() const
{
return (fabs(m_T * m_B) < 1e-5) && (fabs(m_N * m_B) < 1e-5) && (fabs(m_T * m_N) < 1e-5) ;
}
template<typename PFP>
bool LocalFrame<PFP>::isNormalized() const
{
return (1-1e-5 < m_N.norm2() && m_N.norm2() < 1+1e-5)
&& (1-1e-5 < m_T.norm2() && m_T.norm2() < 1+1e-5)
&& (1-1e-5 < m_B.norm2() && m_B.norm2() < 1+1e-5) ;
}
template<typename PFP>
bool LocalFrame<PFP>::isOrthoNormalDirect() const
{
return isOrthogonal() && isNormalized() && isDirect() ;
}
template<typename PFP>
typename Geom::Vector<2,typename PFP::REAL> LocalFrame<PFP>::carthToSpherical (const VEC3& carth) const
{
VEC2 res ;
const REAL& x = carth[0] ;
const REAL& y = carth[1] ;
const REAL& z = carth[2] ;
REAL& theta = res[0] ;
REAL& phi = res[1] ;
phi = acos(z) ;
const REAL sinphi = sin(phi) ;
if (sinphi == 0.0)
theta = 0.0 ;
else
theta = ((y > 0) ? 1 : -1) * acos(std::min(REAL(1.0),std::max(REAL(-1.0),x / sinphi))) ;
assert (-(M_PI+0.000001) <= theta && theta <= M_PI+0.000001) ;
assert (-0.000001 < phi && phi <= M_PI+0.000001) ;
assert (!isnan(theta) || !"carthToSpherical : Theta is NaN !") ;
assert (!isnan(phi) || !"carthToSpherical : Phi is NaN !") ;
return res ;
}
template<typename PFP>
typename PFP::VEC3 LocalFrame<PFP>::sphericalToCarth (const VEC2& sph) const
{
VEC3 res ;
const REAL& theta = sph[0] ;
const REAL& phi = sph[1] ;
REAL& x = res[0] ;
REAL& y = res[1] ;
REAL& z = res[2] ;
x = cos(theta)*sin(phi) ;
y = sin(theta)*sin(phi) ;
z = cos(phi) ;
assert(-1.000001 < x && x < 1.000001) ;
assert(-1.000001 < y && y < 1.000001) ;
assert(-1.000001 < z && z < 1.000001) ;
return res ;
}
} // Utils
} // CGoGN
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment