Commit 99a37a51 authored by Kenneth Vanhoey's avatar Kenneth Vanhoey

new naming convention for frames : XYZ instead of TBN

parent 5587bbe0
/*******************************************************************************
* 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 Geom {
/**
* 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 cartesian coordinates.
* The spherical coordinates are in radius-longitude-latitude
* @param sph the spherical coordinates
* @return the cartesian coordinates
*/
template<typename REAL>
Geom::Vector<3,REAL> sphericalToCart (const Geom::Vector<3,REAL>& sph) ;
/**
* Util for conversion from cartesian to spherical coordinates.
* The spherical coordinates are in radius-longitude-latitude
* @param cart the cartesian coordinates
* @return the spherical coordinates
*/
template<typename REAL>
Geom::Vector<3,REAL> cartToSpherical (const Geom::Vector<3,REAL>& cart) ;
/**
* Class for representing a direct right-handed 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 composed of the Euler angles).
* Usage :
* VEC3 X,Y,Z ; // current set of orthonormal vectors composing the direct frame.
* Frame<PFP> lf(X,Y,Z) ; // Constructor from explicit expression.
* if (lf.isOrthoNormalDirect()) // test if the frame is Orthogonal, Normalized and Direct
* VEC3 compressed = lf.getCompressed() ; // Extract compressed frame
* Frame<PFP> decompressed(compressed) ; // Constructor from implicit (compressed) expression.
*/
template <typename PFP>
class Frame
{
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_X,m_Y,m_Z ;
public: // methods
/**
* Constructor from explicit data
* @param X the tangent vector
* @param Y the bitangent vector
* @param Z the normal vector
*/
Frame(const VEC3& X, const VEC3& Y, const VEC3& Z) ;
/**
* Constructor from implicit (compressed representation)
* @param compressedFrame an implicit (compressed) version of the local frame (can be produced by localFrame.getCompressed())
*/
Frame(const VEC3& eulerAngles) ;
~Frame() {} ;
/**
* 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 Frame<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 Frame<PFP>& lf) const ;
/**
* Inequality of frames
* Identical to calling !equals with default epsilon
* @return false if frames are identical
*/
bool operator!=(const Frame<PFP>& lf) const ;
/**
* Tests if the frame is direct
* @return true if the frame is direct
*/
bool isDirect(REAL epsilon = 1e-7) const ;
/**
* Tests if the frame is orthogonal
* @return true if the frame is orthogonal
*/
bool isOrthogonal(REAL epsilon = 1e-5) const ;
/**
* Tests if the frame is normalized
* @return true if the frame is normalized
*/
bool isNormalized(REAL epsilon = 1e-5) const ;
/**
* Tests if the frame is direct, normalized and orthogonal
* @return true if the frame is direct, normalized and orthogonal
*/
bool isOrthoNormalDirect(REAL epsilon = 1e-5) const ;
/**
* @return current tangent vector
*/
VEC3& getX() { return m_X ; }
const VEC3& getX() const { return m_X ; }
/**
* @return current bitangent vector
*/
VEC3& getY() { return m_Y ; }
const VEC3& getY() const { return m_Y ; }
/**
* @return current normal vector
*/
VEC3& getZ() { return m_Z ; }
const VEC3& getZ() const { return m_Z ; }
friend std::ostream& operator<< (std::ostream &out, const Frame& lf) {
out << "X : " << lf.m_X << std::endl ;
out << "Y : " << lf.m_Y << std::endl ;
out << "Z : " << lf.m_Z ;
return out ;
} ;
private : // private constants
// The reference frame (X,Y,Z) can be any orthonormal
// direct frame. Zeros are not recommended since they
// can easily generate zero vectors after a dot product
// UPDATE : this problem should be handled in compression
// static const REAL Xx = 0.267261 ;
// static const REAL Xy = 0.534522 ;
// static const REAL Xz = 0.801784 ;
// static const REAL Yx = 0.844416 ;
// static const REAL Yy = -0.530776 ;
// static const REAL Yz = 0.0723785 ;
// static const REAL Zx = 0.464255 ;
// static const REAL Zy = 0.657695 ;
// static const REAL Zz = -0.593215 ;
static const REAL Xx = 0.0766965 ;
static const REAL Xy = 0.383483 ;
static const REAL Xz = 0.920358 ;
static const REAL Yx = -0.760734 ;
static const REAL Yy = 0.619202 ;
static const REAL Yz = -0.194606 ;
static const REAL Zx = -0.644516 ;
static const REAL Zy = -0.685222 ;
static const REAL Zz = 0.339219 ;
} ;
} // Geom
} // CGoGN
#include "frame.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 Geom {
template<typename PFP>
Frame<PFP>::Frame(const VEC3& X, const VEC3& Y, const VEC3& Z)
{
m_X = X ;
m_Y = Y ;
m_Z = Z ;
}
template<typename PFP>
Frame<PFP>::Frame(const VEC3& EulerAngles)
{
const VEC3 X(Xx,Xy,Xz) ;
const VEC3 Z(Zx,Zy,Zz) ;
// get known data
const REAL& alpha = EulerAngles[0] ;
const REAL& beta = EulerAngles[1] ;
const REAL& gamma = EulerAngles[2] ;
const VEC3 lineOfNodes = rotate<REAL>(Z,alpha,X) ; // rotation around reference normal of vector T
m_Z = rotate<REAL>(lineOfNodes,gamma,Z) ; // rotation around line of nodes of vector N
m_X = rotate<REAL>(m_Z,beta,lineOfNodes) ; // rotation around new normal of vector represented by line of nodes
m_Y = m_Z ^ m_X ;
}
template<typename PFP>
typename Geom::Vector<3,typename PFP::REAL> Frame<PFP>::getCompressed() const
{
VEC3 EulerAngles ;
const VEC3 X(Xx,Xy,Xz) ;
const VEC3 Y(Yx,Yy,Yz) ;
const VEC3 Z(Zx,Zy,Zz) ;
REAL& alpha = EulerAngles[0] ;
REAL& beta = EulerAngles[1] ;
REAL& gamma = EulerAngles[2] ;
VEC3 lineOfNodes = Z ^ m_Z ;
if (lineOfNodes.norm2() < 1e-5) // if Z ~= m_Z
{
lineOfNodes = X ; // = reference T
alpha = 0 ;
gamma = 0 ;
}
else
{
lineOfNodes.normalize() ;
// angle between reference T and line of nodes
alpha = (Y*lineOfNodes > 0 ? 1 : -1) * std::acos(std::max(std::min(REAL(1.0), X*lineOfNodes ),REAL(-1.0))) ;
// angle between reference normal and normal
gamma = std::acos(std::max(std::min(REAL(1.0), Z*m_Z ),REAL(-1.0))) ; // gamma is always positive because the direction of vector lineOfNodes=(reference normal)^(normal) (around which a rotation of angle beta is done later on) changes depending on the side on which they lay w.r.t eachother.
}
// angle between line of nodes and T
beta = (m_Y*lineOfNodes > 0 ? -1 : 1) * std::acos(std::max(std::min(REAL(1.0), m_X*lineOfNodes ),REAL(-1.0))) ;
return EulerAngles ;
}
template<typename PFP>
bool Frame<PFP>::equals(const Geom::Frame<PFP>& lf, REAL epsilon) const
{
VEC3 dX = m_X - lf.getX() ;
VEC3 dY = m_Y - lf.getY() ;
VEC3 dZ = m_Z - lf.getZ() ;
return dX.norm2() < epsilon && dY.norm2() < epsilon && dZ.norm2() < epsilon ;
}
template<typename PFP>
bool Frame<PFP>::operator==(const Frame<PFP>& lf) const
{
return this->equals(lf) ;
}
template<typename PFP>
bool Frame<PFP>::operator!=(const Frame<PFP>& lf) const
{
return !(this->equals(lf)) ;
}
template<typename PFP>
bool Frame<PFP>::isDirect(REAL epsilon) const
{
VEC3 new_Y = m_Z ^ m_X ; // direct
VEC3 diffs = new_Y - m_Y ; // differences with existing B
REAL diffNorm = diffs.norm2() ; // Norm of this differences vector
return (diffNorm < epsilon) ; // Verify that this difference is very small
}
template<typename PFP>
bool Frame<PFP>::isOrthogonal(REAL epsilon) const
{
return (fabs(m_X * m_Y) < epsilon) && (fabs(m_Z * m_Y) < epsilon) && (fabs(m_X * m_Z) < epsilon) ;
}
template<typename PFP>
bool Frame<PFP>::isNormalized(REAL epsilon) const
{
return (1-epsilon < m_Z.norm2() && m_Z.norm2() < 1+epsilon)
&& (1-epsilon < m_X.norm2() && m_X.norm2() < 1+epsilon)
&& (1-epsilon < m_Y.norm2() && m_Y.norm2() < 1+epsilon) ;
}
template<typename PFP>
bool Frame<PFP>::isOrthoNormalDirect(REAL epsilon) const
{
return isOrthogonal(epsilon) && isNormalized(epsilon) && isDirect(epsilon) ;
}
template<typename REAL>
Geom::Vector<3,REAL> carthToSpherical (const Geom::Vector<3,REAL>& carth)
{
Geom::Vector<3,REAL> res ;
const REAL& x = carth[0] ;
const REAL& y = carth[1] ;
const REAL& z = carth[2] ;
REAL& rho = res[0] ;
REAL& theta = res[1] ;
REAL& phi = res[2] ;
rho = carth.norm() ;
theta = ((y < 0) ? -1 : 1) * std::acos(x / REAL(sqrt(x*x + y*y)) ) ;
if (isnan(theta))
theta = 0.0 ;
phi = std::asin(z) ;
return res ;
}
template<typename REAL>
Geom::Vector<3,REAL> sphericalToCarth (const Geom::Vector<3,REAL>& sph)
{
Geom::Vector<3,REAL> res ;
const REAL& rho = sph[0] ;
const REAL& theta = sph[1] ;
const REAL& phi = sph[2] ;
REAL& x = res[0] ;
REAL& y = res[1] ;
REAL& z = res[2] ;
x = rho*cos(theta)*cos(phi) ;
y = rho*sin(theta)*cos(phi) ;
z = rho*sin(phi) ;
assert(-1.000001 < x && x < 1.000001) ;
assert(-1.000001 < y && y < 1.000001) ;
assert(-1.000001 < z && z < 1.000001) ;
return res ;
}
template <typename REAL>
Geom::Vector<3,REAL> rotate (Geom::Vector<3,REAL> axis, REAL angle, Geom::Vector<3,REAL> vector)
{
axis.normalize() ;
const REAL& u = axis[0] ;
const REAL& v = axis[1] ;
const REAL& w = axis[2] ;
const REAL& x = vector[0] ;
const REAL& y = vector[1] ;
const REAL& z = vector[2] ;
Geom::Vector<3,REAL> res ;
REAL& xp = res[0] ;
REAL& yp = res[1] ;
REAL& zp = res[2] ;
const REAL tmp1 = u*x+v*y+w*z ;
const REAL cos = std::cos(angle) ;
const REAL sin = std::sin(angle) ;
xp = u*tmp1*(1-cos) + x*cos+(v*z-w*y)*sin ;
yp = v*tmp1*(1-cos) + y*cos-(u*z-w*x)*sin ;
zp = w*tmp1*(1-cos) + z*cos+(u*y-v*x)*sin ;
return res ;
}
} // Geom
} // 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