paella/Code/include/Meshing/Skeleton3D.hpp

258 lines
13 KiB
C++

////////////////////////////////////////////////////////////////////////////////
//
// Paella
// Copyright (C) 2015 - Thomas FORGIONE, Emilie JALRAS, Marion LENFANT, Thierry MALON, Amandine PAILLOUX
// Authors :
// Thomas FORGIONE
// Emilie JALRAS
// Marion LENFANT
// Thierry MALON
// Amandine PAILLOUX
//
// This file is part of the project Paella
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
////////////////////////////////////////////////////////////////////////////////
#ifndef SKELETON3D_HPP
#define SKELETON3D_HPP
#include <vector>
#include <list>
#include <Geometry/Mesh.hpp>
#include <Geometry/Spline.hpp>
#include <Geometry/Point.hpp>
namespace pae
{
/////////////////////////////////////////////////////////
// Junction : a junction in the skeleton defined by a vector of pairs containing:
// - spline's index
// - t parameter where the junction
// is located on the spline
//
// Example : <<ind1,t1>, <ind2,t2>, <ind3,t3>>
//This junction is between 3 splines designated by their indexes.
////////////////////////////////////////////////////////
using Junction = std::vector<std::pair<unsigned int,float>>;
namespace detail
{
/////////////////////////////////////////////////////////////
/// \ingroup meshing
/// \relates pae::Skeleton3D
/// \brief compute on which side of the plane is the point (depending on the orientation of the plane
///
/// \param plane the caracteristic elements of the plane a, b, c, d in the plane equation : ax + by + cz + d = 0.
/// \param point the point that need to be evaluated
///
/// \return a boolean which is true when : a*point.x() + b*point.y() + c*point.z() < -d.
/////////////////////////////////////////////////////////////
template<typename T>
bool whichSide(geo::Vector<T,4> const& plane, geo::Vector3<T> const& point);
//////////////////////////////////////////////////////////
/// \ingroup meshing
/// \relates pae::Skeleton3D
/// \brief compute the equation of the optimal plane for a given set of points. For 3 points it only computes the equation of a plane, beyond 3 points with ACP decomposition it returns the mean plane.
///
/// \param points the given set of points to estimate the equation of the plane
///
/// \return the caracteristic elements of the plane a, b, c, d in the plane equation : ax + by + cz + d = 0.)
/////////////////////////////////////////////////////////
template<typename T>
geo::Vector<float,4> closestPlane(std::vector<geo::Vector3<T>> const& points);
//////////////////////////////////////////////////////////
/// \ingroup meshing
/// \relates pae::Skeleton3D
/// \brief sort all the points of all the circles of the junction according to the side of the plane where they are. For one side of one circle the points are sorted in the order on the circle. See the example
///
/// \param plane the caracteristic elements of the plane a, b, c, d in the plane equation : ax + by + cz + d = 0.
/// \param junction_circles circles (given by the points on it) to be sorted
///
/// \return pair containing
/// - a vector of lists of up points for all the circles
/// - a vector of lists of down points for all the circles
/// the n th list of the up points vector correspond to the same circle than the n th list of the down points.
/////////////////////////////////////////////////////////
template<typename T>
std::pair<std::vector<std::list<geo::Point<T>>>, std::vector<std::list<geo::Point<T>>>> sortedPoints(geo::Vector<T,4> const& plane, std::vector<geo::Circle<T>> const& junction_circles);
/////////////////////////////////////////////////////////
/// \ingroup meshing
/// \relates pae::Skeleton3D
/// \brief push the face to the mesh with the correct orientation
/// \param mesh mesh to add the face
/// \param face face to be added
/// \param sphere_center center of the sphere
///
/// Compute the vector between the center of the sphere and the points of the faces
/// and add the face so that the normal is pointing outside the sphere.
//////////////////////////////////////////////////////////
template<typename T>
void pushFaceOriented(geo::Mesh& mesh, geo::Vector3<unsigned int> const& face, geo::Vector3<T> const& sphere_center);
}
/////////////////////////////////////////////////////////////////
/// \ingroup meshing
/// \relates pae::Skeleton3D
/// \brief mesh one junction given the circles associated, the center of the junction and its radius.
//
/// \param mesh the existing mesh to complete.
/// \param junction_point the 3D point where the junction is done
/// \param junction_radius the radius of the n splines of the junction at the junction
/// \param junction_circles last circles on the spline that we want to join
///
/// \return the plane that cut the circles in two (helpful to test).
////////////////////////////////////////////////////////////////
template<typename T>
geo::Vector<T,4> meshJunction(geo::Mesh& mesh, geo::Vector3<T> const& junction_point, float junction_radius, std::vector<geo::Circle<T>> const& junction_circles);
/////////////////////////////////////////////////////////////////
/// \ingroup meshing
/// \brief Template class for 3D Skeleton
///
/// This class allows to load a 3D skeleton from a file. Then, you can generate
/// a mesh from the skeleton, including junctions and extremities
///
////////////////////////////////////////////////////////////////
template<typename... Types>
class Skeleton3D
{
public:
/////////////////////////////////////////////////////////////
/// \brief Default constructor
///
/// Creates an empty skeleton, with no splines
/////////////////////////////////////////////////////////////
Skeleton3D();
/////////////////////////////////////////////////////////////
/// \brief Load a skeleton from file
/// \param path path to the file to load
/// \return true if the skeleton was load correctly
/// Loads a skeleton, its splines, its junction points from a file
/////////////////////////////////////////////////////////////
bool loadFromFile(std::string const& path);
/////////////////////////////////////////////////////////////
/// \brief Mesh all the junctions of a given Skeleton 3D and complete the mesh already computed.
///
/// \param mesh the existing mesh to complete.
/// \param splines_circles all the circles of each spline of the Skeleton.
///
/////////////////////////////////////////////////////////////
void meshJunctions(geo::Mesh& mesh, std::vector<std::vector<geo::Circle<float>>> const& splines_circles) const;
/////////////////////////////////////////////////////////////
/// \brief get the extremities of the skeleton
///
/// \return a vector of pair which contain the index of the spline
/// and the t where is the extremity
/////////////////////////////////////////////////////////////
std::vector<std::pair<unsigned int, float>> findExtremities() const;
////////////////////////////////////////////////////////////
/// \brief compute the extremities as a mesh
///
/// \param mesh the mesh
/// \param splines_circles the circles associated to the splines
/// \param profondeur the depth of the subdivision
////////////////////////////////////////////////////////////
void meshExtremities(geo::Mesh& mesh, std::vector<std::vector<geo::Circle<float>>> const& splines_circles, unsigned int profondeur) const;
////////////////////////////////////////////////////////////
/// \brief compute one extremity
///
/// \param mesh the mesh
/// \param splines_circles the circles associated to the splines
/// \param profondeur the depth of the subdivision
/// \param extremity the extremity concerned
////////////////////////////////////////////////////////////
void meshExtremity(geo::Mesh& mesh, std::vector<std::vector<geo::Circle<float>>> const& splines_circles, unsigned int profondeur, std::pair<unsigned int,float> extremity) const;
///////////////////////////////////////////////////////////
/// \brief subdivise all the segment along the extremity
/// \param mesh the mesh
/// \param profondeur the depth of the subdivision
/// \param extremCircle the circle associated to the extremity
/// \param intersectionIndex the index of the intersection point
/// \param intersection the intersection point
/// \param center the center of the sphere
/// \param radius the radius of the sphere
/// \param t the time where is the extremity on the spline
//////////////////////////////////////////////////////////
void subdivision(geo::Mesh& mesh, unsigned int profondeur, geo::Circle<float> extremCircle, unsigned int intersectionIndex, geo::Vector3<float> intersection, geo::Vector3<float> center, float radius, float t) const;
/////////////////////////////////////////////////////////
/// \brief the subdivision on one segment
///
/// \param pt1 the first point on the segment
/// \param pt2 the second point on the segment
/// \param profondeur the depth of the subdivision
/// \param arc the segment [pt1 pt2] with the points inside
/// \param center the center of the sphere
/// \param radius the radius of the sphere
////////////////////////////////////////////////////////
void arcSubdivise(geo::Vector3<float> pt1, geo::Vector3<float> pt2, unsigned int profondeur, std::vector<geo::Vector3<float>>& arc, geo::Vector3<float> center, float radius) const;
////////////////////////////////////////////////////////
/// \brief sort the indexes
/// \param a first index of the vector
/// \param b second index of the vector
/// \param c third index of the vector
/// \param t instant of the spline
/// \pre t must be 0 or 1
/// \return (a,b,c) if t == 0, (a,c,b) if t == 1
////////////////////////////////////////////////////////
geo::Vector3<unsigned int> sortedIndexes(unsigned int a, unsigned int b, unsigned int c, float t) const;
////////////////////////////////////////////////////////
/// \brief Compute a mesh around the skeleton
///
/// \param pointsProportion multiplicative factor of the number of circles by spline
/// \param nbPointsPerCircle nunmber of points on each circle of the splines
/// \param depth number of subdivision of extremities
/// \param withExtremities if true, the extremities will be computed
/// \param withJunctions if true, the junctions will be computed
/// \return a mesh of the skeleton
////////////////////////////////////////////////////////
geo::Mesh computeMesh(float pointsProportion = 10, unsigned int nbPointsPerCircle = 18u, unsigned int depth = 1, bool withExtremities=true, bool withJunctions=true) const;
////////////////////////////////////////////////////////
/// \brief Overload of the operator<<
/// \param out stream to print the skeleton
/// \param s skeleton to print on the stream
/// \return a reference to out
///
/// Prints the splines and the junctions points on the stream
////////////////////////////////////////////////////////
template<typename... T>
friend std::ostream& operator<<(std::ostream& out, Skeleton3D<T...> const& s);
// private:
std::vector<geo::Spline<Types...>> splines; ///< all the splines that the skeleton contains
std::vector<Junction> junctions; ///< all the junction points of the skeleton
};
} // namespace pae
#include "Skeleton3D.inl"
#endif // SKELETON3D_HPP